#!/usr/local/bin/php \n"); die; } $CONDUIT_TOKEN_FILE = $argv[1]; $OUTPUT_DIR = $argv[2]; ///////////////////////////////////////////////////////////////////////////////// // Global configuration. $HOST = 'phabricator.local'; ///////////////////////////////////////////////////////////////////////////////// // Utilities. // Create an instance of the AphrontApplicationConfiguration configured with all // invariant settings (settings which do not change between handlers of different // revisions). function CreateApplicationConfiguration() { global $HOST; $application_configuration = new AphrontApplicationConfiguration(); $application_configuration->setHost($HOST); return $application_configuration; } ///////////////////////////////////////////////////////////////////////////////// // Global state. $site = id(new PhabricatorPlatformSite()); $viewer = PhabricatorUser::getOmnipotentUser(); $application_configuration = CreateApplicationConfiguration(); $differential_application = id(new PhabricatorDifferentialApplication()); $revision_controller = id(new DifferentialRevisionViewController()) ->setCurrentApplication($differential_application); $maniphest_application = id(new PhabricatorManiphestApplication()); $maniphest_controller = id(new ManiphestTaskDetailController()) ->setCurrentApplication($maniphest_application); $differential_routing_map = id(new AphrontRoutingMap()) ->setSite($site) ->setApplication($differential_application) ->setRoutes($differential_application->getRoutes()); $maniphest_routing_map = id(new AphrontRoutingMap()) ->setSite($site) ->setApplication($maniphest_application) ->setRoutes($maniphest_application->getRoutes()); $conduit = id(new ConduitClient('https://developer.blender.org/api/')) ->setConduitToken(trim(file_get_contents($CONDUIT_TOKEN_FILE))); ///////////////////////////////////////////////////////////////////////////////// // Baking utilities. function EnsureDirectoryOrDie($dir) { if (!is_dir($dir)) { if (!mkdir($dir, 0777, true)) { print("Error creating output durectory $dir\n"); die; } } } function RenderElement($element) { if (is_array($element)) { $html = ''; foreach ($element as $child) { $html .= RenderElement($child); } return $html; } return $element->render(); } function RenderResponseToHTML($response) { $html = ''; $crumbs = $response->getCrumbs(); if ($crumbs) { $html .= $crumbs->render(); } foreach ($response->renderChildren() as $child) { $html .= RenderElement($child); } return $html; } ///////////////////////////////////////////////////////////////////////////////// // Revision baking. class RevisionInfo { public $title = ''; public $page_title = ''; public $last_diff_id = 0; public $hash = ''; public static function ReadFromFile($file_name) { $info = new RevisionInfo(); if (!file_exists($file_name)) { return $info; } $json = json_decode(file_get_contents($file_name)); foreach ($json as $key => $value) { $info->{$key} = $value; } return $info; } public function SaveToFile($file_name) { $json_str = json_encode(get_object_vars($this)); file_put_contents($file_name, $json_str); } }; function GetRevisionOutputDirectory($revision) { global $OUTPUT_DIR; $id = $revision->getID(); return PathJoin(array($OUTPUT_DIR, 'differential', SubpathFromId($id))); } function EnsureRevisionOutputDirectory($revision) { $dir = GetRevisionOutputDirectory($revision); EnsureDirectoryOrDie($dir); EnsureDirectoryOrDie(PathJoin(array($dir, 'raw_diff'))); return $dir; } function GetRevisionInfoFilename($revision) { $revision_dir = GetRevisionOutputDirectory($revision); return PathJoin(array($revision_dir, 'info.json')); } function GetRevisionHTMLFilename($revision, $diff_id) { $revision_id = $revision->getID(); $revision_dir = GetRevisionOutputDirectory($revision); $file_name = "D{$revision_id}.id{$diff_id}.html"; return PathJoin(array($revision_dir, $file_name)); } function GetRevisionRawDiffFilename($revision, $diff_id) { $revision_id = $revision->getID(); $revision_dir = GetRevisionOutputDirectory($revision); $file_name = "D{$revision_id}.id{$diff_id}.diff"; return PathJoin(array($revision_dir, 'raw_diff', $file_name)); } function RenderDifferentialToResponse($revision, $diff_id) { global $application_configuration; global $revision_controller; global $differential_routing_map; global $viewer; $revision_id = $revision->getID(); $path = '/D' . $revision_id; $route_result = $differential_routing_map->routePath($path); $uri_data = $route_result->getURIData(); $application_configuration->setPath($path); $request_data = array( 'id' => $diff_id, ); $request = $application_configuration->buildRequest() ->setUser($viewer) ->setRequestData($request_data) ->setURIMap($uri_data); $response = id($revision_controller) ->setRequest($request) ->handleRequest($request); return $response; } function StoreRawDiff($revision, $diff_id) { global $viewer; global $conduit; $diff = id(new DifferentialDiffQuery()) ->setViewer($viewer) ->withIDs(array($diff_id)) ->needChangesets(true) ->executeOne(); $raw_changes = $diff->buildChangesList(); $changes = array(); foreach ($raw_changes as $changedict) { $changes[] = ArcanistDiffChange::newFromDictionary($changedict); } $bundle = ArcanistBundle::newFromChanges($changes); $bundle->setConduit($conduit); $raw_diff = $bundle->toGitPatch(); $output_file = GetRevisionRawDiffFilename($revision, $diff_id); file_put_contents($output_file, $raw_diff); } function GetRevisionHash($revision) { global $viewer; $xaction = id(new DifferentialTransactionQuery()) ->setViewer($viewer) ->withObjectPHIDs(array($revision->getPHID())) ->setOrder('newest') ->setLimit(1) ->executeOne(); $digest = ''; $digest .= $revision->getDateModified(); if ($xaction) { $digest .= '_' . $xaction->getPHID(); $digest .= '_' . $xaction->getDateModified(); } return $digest; } function NeedBakeRevision($info, $revision, $diff_id) { if (!file_exists(GetRevisionHTMLFilename($revision, $diff_id))) { return true; } if (!file_exists(GetRevisionRawDiffFilename($revision, $diff_id))) { return true; } if ($info->last_diff_id < $diff_id) { return true; } if ($revision->getTitle() != $info->title) { return true; } if (GetRevisionHash($revision) != $info->hash) { return true; } return false; } function BakeRevision($revision, $diff_id) { $revision_id = $revision->getID(); printf('Baking D' . $revision_id . '?id=' . $diff_id . ' ...' . "\n"); $info_file_name = GetRevisionInfoFilename($revision); $info = RevisionInfo::ReadFromFile($info_file_name); if (!NeedBakeRevision($info, $revision, $diff_id)) { print(' ... ignoring: up to date' . "\n"); return; } $response = RenderDifferentialToResponse($revision, $diff_id); $html = RenderResponseToHTML($response); $html_file_name = GetRevisionHTMLFIlename($revision, $diff_id); file_put_contents($html_file_name, $html); StoreRawDiff($revision, $diff_id); $info->title = $revision->getTitle(); $info->page_title = $response->getTitle(); $info->hash = GetRevisionHash($revision); $info->last_diff_id = max($info->last_diff_id, $diff_id); $info->SaveToFile($info_file_name); } ///////////////////////////////////////////////////////////////////////////////// // Task baking. class TaskInfo { public $title = ''; public $page_title = ''; public $hash = ''; public static function ReadFromFile($file_name) { $info = new TaskInfo(); if (!file_exists($file_name)) { return $info; } $json = json_decode(file_get_contents($file_name)); foreach ($json as $key => $value) { $info->{$key} = $value; } return $info; } public function SaveToFile($file_name) { $json_str = json_encode(get_object_vars($this)); file_put_contents($file_name, $json_str); } }; function GetTaskOutputDirectory($task) { global $OUTPUT_DIR; $id = $task->getID(); return PathJoin(array($OUTPUT_DIR, 'maniphest', SubpathFromId($id))); } function EnsureTaskOutputDirectory($task) { $dir = GetTaskOutputDirectory($task); EnsureDirectoryOrDie($dir); return $dir; } function GetTaskInfoFilename($task) { $task_dir = GetTaskOutputDirectory($task); return PathJoin(array($task_dir, 'info.json')); } function GetTaskHTMLFilename($task) { $task_id = $task->getID(); $task_dir = GetTaskOutputDirectory($task); $file_name = "index.html"; return PathJoin(array($task_dir, $file_name)); } function RenderTaskToResponse($task) { global $application_configuration; global $maniphest_routing_map; global $viewer; global $maniphest_controller; $task_id = $task->getID(); $path = '/T' . $task_id; $route_result = $maniphest_routing_map->routePath($path); $uri_data = $route_result->getURIData(); $application_configuration->setPath($path); $request_data = array( ); $request = $application_configuration->buildRequest() ->setUser($viewer) ->setRequestData($request_data) ->setURIMap($uri_data); $response = id($maniphest_controller) ->setRequest($request) ->handleRequest($request); return $response; } function GetTaskHash($task) { global $viewer; $xaction = id(new DifferentialTransactionQuery()) ->setViewer($viewer) ->withObjectPHIDs(array($task->getPHID())) ->setOrder('newest') ->setLimit(1) ->executeOne(); $digest = ''; $digest .= $task->getDateModified(); if ($xaction) { $digest .= '_' . $xaction->getPHID(); $digest .= '_' . $xaction->getDateModified(); } return $digest; } function NeedBakeTask($info, $task) { if (!file_exists(GetTaskHTMLFilename($task))) { return true; } if ($task->getTitle() != $info->title) { return true; } if (GetTaskHash($task) != $info->hash) { return true; } return false; } function BakeTask($task) { $task_id = $task->getID(); printf('Baking T' . $task_id . ' ...' . "\n"); $info_file_name = GetTaskInfoFilename($task); $info = TaskInfo::ReadFromFile($info_file_name); if (!NeedBakeTask($info, $task)) { print(' ... ignoring: up to date' . "\n"); return; } $response = RenderTaskToResponse($task); $html = RenderResponseToHTML($response); $html_file_name = GetTaskHTMLFIlename($task); file_put_contents($html_file_name, $html); $info->title = $task->getTitle(); $info->page_title = $response->getTitle(); $info->hash = GetTaskHash($task); $info->SaveToFile($info_file_name); } ///////////////////////////////////////////////////////////////////////////////// // Baking main loop. print('Querying differential revisions from the database ... ' . "\n"); $revisions = id(new DifferentialRevisionQuery()) ->setViewer($viewer) ->needDiffIDs(true) ->setOrder('oldest') ->execute(); foreach ($revisions as $revision_id => $revision) { EnsureRevisionOutputDirectory($revision); foreach ($revision->getDiffIDs() as $diff_id) { BakeRevision($revision, $diff_id); } } print("\n"); print('Querying maniphest tasks from the database ... ' . "\n"); $tasks = id(new ManiphestTaskQuery()) ->setViewer($viewer) ->setOrder('oldest') ->execute(); foreach ($tasks as $task_id => $task) { EnsureTaskOutputDirectory($task); BakeTask($task); } ?>