diff --git a/externals/xhprof/LICENSE b/externals/xhprof/LICENSE new file mode 100644 index 0000000000..f433b1a53f --- /dev/null +++ b/externals/xhprof/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/externals/xhprof/xhprof_lib.php b/externals/xhprof/xhprof_lib.php new file mode 100644 index 0000000000..fed9487039 --- /dev/null +++ b/externals/xhprof/xhprof_lib.php @@ -0,0 +1,866 @@ + array("Wall", "microsecs", "walltime" ), + "ut" => array("User", "microsecs", "user cpu time" ), + "st" => array("Sys", "microsecs", "system cpu time"), + "cpu" => array("Cpu", "microsecs", "cpu time"), + "mu" => array("MUse", "bytes", "memory usage"), + "pmu" => array("PMUse", "bytes", "peak memory usage"), + "samples" => array("Samples", "samples", "cpu time")); + return $possible_metrics; +} + +/* + * Get the list of metrics present in $xhprof_data as an array. + * + * @author Kannan + */ +function xhprof_get_metrics($xhprof_data) { + + // get list of valid metrics + $possible_metrics = xhprof_get_possible_metrics(); + + // return those that are present in the raw data. + // We'll just look at the root of the subtree for this. + $metrics = array(); + foreach ($possible_metrics as $metric => $desc) { + if (isset($xhprof_data["main()"][$metric])) { + $metrics[] = $metric; + } + } + + return $metrics; +} + +/** + * Takes a parent/child function name encoded as + * "a==>b" and returns array("a", "b"). + * + * @author Kannan + */ +function xhprof_parse_parent_child($parent_child) { + $ret = explode("==>", $parent_child); + + // Return if both parent and child are set + if (isset($ret[1])) { + return $ret; + } + + return array(null, $ret[0]); +} + +/** + * Given parent & child function name, composes the key + * in the format present in the raw data. + * + * @author Kannan + */ +function xhprof_build_parent_child_key($parent, $child) { + if ($parent) { + return $parent . "==>" . $child; + } else { + return $child; + } +} + + +/** + * Checks if XHProf raw data appears to be valid and not corrupted. + * + * @param int $run_id Run id of run to be pruned. + * [Used only for reporting errors.] + * @param array $raw_data XHProf raw data to be pruned + * & validated. + * + * @return bool true on success, false on failure + * + * @author Kannan + */ +function xhprof_valid_run($run_id, $raw_data) { + + $main_info = $raw_data["main()"]; + if (empty($main_info)) { + xhprof_error("XHProf: main() missing in raw data for Run ID: $run_id"); + return false; + } + + // raw data should contain either wall time or samples information... + if (isset($main_info["wt"])) { + $metric = "wt"; + } else if (isset($main_info["samples"])) { + $metric = "samples"; + } else { + xhprof_error("XHProf: Wall Time information missing from Run ID: $run_id"); + return false; + } + + foreach ($raw_data as $info) { + $val = $info[$metric]; + + // basic sanity checks... + if ($val < 0) { + xhprof_error("XHProf: $metric should not be negative: Run ID $run_id" + . serialize($info)); + return false; + } + if ($val > (86400000000)) { + xhprof_error("XHProf: $metric > 1 day found in Run ID: $run_id " + . serialize($info)); + return false; + } + } + return true; +} + + +/** + * Return a trimmed version of the XHProf raw data. Note that the raw + * data contains one entry for each unique parent/child function + * combination.The trimmed version of raw data will only contain + * entries where either the parent or child function is in the list + * of $functions_to_keep. + * + * Note: Function main() is also always kept so that overall totals + * can still be obtained from the trimmed version. + * + * @param array XHProf raw data + * @param array array of function names + * + * @return array Trimmed XHProf Report + * + * @author Kannan + */ +function xhprof_trim_run($raw_data, $functions_to_keep) { + + // convert list of functions to a hash with function as the key + $function_map = array_fill_keys($functions_to_keep, 1); + + // always keep main() as well so that overall totals can still + // be computed if need be. + $function_map['main()'] = 1; + + $new_raw_data = array(); + foreach ($raw_data as $parent_child => $info) { + list($parent, $child) = xhprof_parse_parent_child($parent_child); + + if (isset($function_map[$parent]) || isset($function_map[$child])) { + $new_raw_data[$parent_child] = $info; + } + } + + return $new_raw_data; +} + +/** + * Takes raw XHProf data that was aggregated over "$num_runs" number + * of runs averages/nomalizes the data. Essentially the various metrics + * collected are divided by $num_runs. + * + * @author Kannan + */ +function xhprof_normalize_metrics($raw_data, $num_runs) { + + if (empty($raw_data) || ($num_runs == 0)) { + return $raw_data; + } + + $raw_data_total = array(); + + if (isset($raw_data["==>main()"]) && isset($raw_data["main()"])) { + xhprof_error("XHProf Error: both ==>main() and main() set in raw data..."); + } + + foreach ($raw_data as $parent_child => $info) { + foreach ($info as $metric => $value) { + $raw_data_total[$parent_child][$metric] = ($value / $num_runs); + } + } + + return $raw_data_total; +} + + +/** + * Get raw data corresponding to specified array of runs + * aggregated by certain weightage. + * + * Suppose you have run:5 corresponding to page1.php, + * run:6 corresponding to page2.php, + * and run:7 corresponding to page3.php + * + * and you want to accumulate these runs in a 2:4:1 ratio. You + * can do so by calling: + * + * xhprof_aggregate_runs(array(5, 6, 7), array(2, 4, 1)); + * + * The above will return raw data for the runs aggregated + * in 2:4:1 ratio. + * + * @param object $xhprof_runs_impl An object that implements + * the iXHProfRuns interface + * @param array $runs run ids of the XHProf runs.. + * @param array $wts integral (ideally) weights for $runs + * @param string $source source to fetch raw data for run from + * @param bool $use_script_name If true, a fake edge from main() to + * to __script:: is introduced + * in the raw data so that after aggregations + * the script name is still preserved. + * + * @return array Return aggregated raw data + * + * @author Kannan + */ +function xhprof_aggregate_runs($xhprof_runs_impl, $runs, + $wts, $source="phprof", + $use_script_name=false) { + + $raw_data_total = null; + $raw_data = null; + $metrics = array(); + + $run_count = count($runs); + $wts_count = count($wts); + + if (($run_count == 0) || + (($wts_count > 0) && ($run_count != $wts_count))) { + return array('description' => 'Invalid input..', + 'raw' => null); + } + + $bad_runs = array(); + foreach($runs as $idx => $run_id) { + + $raw_data = $xhprof_runs_impl->get_run($run_id, $source, $description); + + // use the first run to derive what metrics to aggregate on. + if ($idx == 0) { + foreach ($raw_data["main()"] as $metric => $val) { + if ($metric != "pmu") { + // for now, just to keep data size small, skip "peak" memory usage + // data while aggregating. + // The "regular" memory usage data will still be tracked. + if (isset($val)) { + $metrics[] = $metric; + } + } + } + } + + if (!xhprof_valid_run($run_id, $raw_data)) { + $bad_runs[] = $run_id; + continue; + } + + if ($use_script_name) { + $page = $description; + + // create a fake function '__script::$page', and have and edge from + // main() to '__script::$page'. We will also need edges to transfer + // all edges originating from main() to now originate from + // '__script::$page' to all function called from main(). + // + // We also weight main() ever so slightly higher so that + // it shows up above the new entry in reports sorted by + // inclusive metrics or call counts. + if ($page) { + foreach($raw_data["main()"] as $metric => $val) { + $fake_edge[$metric] = $val; + $new_main[$metric] = $val + 0.00001; + } + $raw_data["main()"] = $new_main; + $raw_data[xhprof_build_parent_child_key("main()", + "__script::$page")] + = $fake_edge; + } else { + $use_script_name = false; + } + } + + // if no weights specified, use 1 as the default weightage.. + $wt = ($wts_count == 0) ? 1 : $wts[$idx]; + + // aggregate $raw_data into $raw_data_total with appropriate weight ($wt) + foreach ($raw_data as $parent_child => $info) { + if ($use_script_name) { + // if this is an old edge originating from main(), it now + // needs to be from '__script::$page' + if (substr($parent_child, 0, 9) == "main()==>") { + $child =substr($parent_child, 9); + // ignore the newly added edge from main() + if (substr($child, 0, 10) != "__script::") { + $parent_child = xhprof_build_parent_child_key("__script::$page", + $child); + } + } + } + + if (!isset($raw_data_total[$parent_child])) { + foreach ($metrics as $metric) { + $raw_data_total[$parent_child][$metric] = ($wt * $info[$metric]); + } + } else { + foreach ($metrics as $metric) { + $raw_data_total[$parent_child][$metric] += ($wt * $info[$metric]); + } + } + } + } + + $runs_string = implode(",", $runs); + + if (isset($wts)) { + $wts_string = "in the ratio (" . implode(":", $wts) . ")"; + $normalization_count = array_sum($wts); + } else { + $wts_string = ""; + $normalization_count = $run_count; + } + + $run_count = $run_count - count($bad_runs); + + $data['description'] = "Aggregated Report for $run_count runs: ". + "$runs_string $wts_string\n"; + $data['raw'] = xhprof_normalize_metrics($raw_data_total, + $normalization_count); + $data['bad_runs'] = $bad_runs; + + return $data; +} + + +/** + * Analyze hierarchical raw data, and compute per-function (flat) + * inclusive and exclusive metrics. + * + * Also, store overall totals in the 2nd argument. + * + * @param array $raw_data XHProf format raw profiler data. + * @param array &$overall_totals OUT argument for returning + * overall totals for various + * metrics. + * @return array Returns a map from function name to its + * call count and inclusive & exclusive metrics + * (such as wall time, etc.). + * + * @author Kannan Muthukkaruppan + */ +function xhprof_compute_flat_info($raw_data, &$overall_totals) { + + global $display_calls; + + $metrics = xhprof_get_metrics($raw_data); + + $overall_totals = array( "ct" => 0, + "wt" => 0, + "ut" => 0, + "st" => 0, + "cpu" => 0, + "mu" => 0, + "pmu" => 0, + "samples" => 0 + ); + + // compute inclusive times for each function + $symbol_tab = xhprof_compute_inclusive_times($raw_data); + + /* total metric value is the metric value for "main()" */ + foreach ($metrics as $metric) { + $overall_totals[$metric] = $symbol_tab["main()"][$metric]; + } + + /* + * initialize exclusive (self) metric value to inclusive metric value + * to start with. + * In the same pass, also add up the total number of function calls. + */ + foreach ($symbol_tab as $symbol => $info) { + foreach ($metrics as $metric) { + $symbol_tab[$symbol]["excl_" . $metric] = $symbol_tab[$symbol][$metric]; + } + if ($display_calls) { + /* keep track of total number of calls */ + $overall_totals["ct"] += $info["ct"]; + } + } + + /* adjust exclusive times by deducting inclusive time of children */ + foreach ($raw_data as $parent_child => $info) { + list($parent, $child) = xhprof_parse_parent_child($parent_child); + + if ($parent) { + foreach ($metrics as $metric) { + // make sure the parent exists hasn't been pruned. + if (isset($symbol_tab[$parent])) { + $symbol_tab[$parent]["excl_" . $metric] -= $info[$metric]; + } + } + } + } + + return $symbol_tab; +} + +/** + * Hierarchical diff: + * Compute and return difference of two call graphs: Run2 - Run1. + * + * @author Kannan + */ +function xhprof_compute_diff($xhprof_data1, $xhprof_data2) { + global $display_calls; + + // use the second run to decide what metrics we will do the diff on + $metrics = xhprof_get_metrics($xhprof_data2); + + $xhprof_delta = $xhprof_data2; + + foreach ($xhprof_data1 as $parent_child => $info) { + + if (!isset($xhprof_delta[$parent_child])) { + + // this pc combination was not present in run1; + // initialize all values to zero. + if ($display_calls) { + $xhprof_delta[$parent_child] = array("ct" => 0); + } else { + $xhprof_delta[$parent_child] = array(); + } + foreach ($metrics as $metric) { + $xhprof_delta[$parent_child][$metric] = 0; + } + } + + if ($display_calls) { + $xhprof_delta[$parent_child]["ct"] -= $info["ct"]; + } + + foreach ($metrics as $metric) { + $xhprof_delta[$parent_child][$metric] -= $info[$metric]; + } + } + + return $xhprof_delta; +} + + +/** + * Compute inclusive metrics for function. This code was factored out + * of xhprof_compute_flat_info(). + * + * The raw data contains inclusive metrics of a function for each + * unique parent function it is called from. The total inclusive metrics + * for a function is therefore the sum of inclusive metrics for the + * function across all parents. + * + * @return array Returns a map of function name to total (across all parents) + * inclusive metrics for the function. + * + * @author Kannan + */ +function xhprof_compute_inclusive_times($raw_data) { + global $display_calls; + + $metrics = xhprof_get_metrics($raw_data); + + $symbol_tab = array(); + + /* + * First compute inclusive time for each function and total + * call count for each function across all parents the + * function is called from. + */ + foreach ($raw_data as $parent_child => $info) { + + list($parent, $child) = xhprof_parse_parent_child($parent_child); + + if ($parent == $child) { + /* + * XHProf PHP extension should never trigger this situation any more. + * Recursion is handled in the XHProf PHP extension by giving nested + * calls a unique recursion-depth appended name (for example, foo@1). + */ + xhprof_error("Error in Raw Data: parent & child are both: $parent"); + return; + } + + if (!isset($symbol_tab[$child])) { + + if ($display_calls) { + $symbol_tab[$child] = array("ct" => $info["ct"]); + } else { + $symbol_tab[$child] = array(); + } + foreach ($metrics as $metric) { + $symbol_tab[$child][$metric] = $info[$metric]; + } + } else { + if ($display_calls) { + /* increment call count for this child */ + $symbol_tab[$child]["ct"] += $info["ct"]; + } + + /* update inclusive times/metric for this child */ + foreach ($metrics as $metric) { + $symbol_tab[$child][$metric] += $info[$metric]; + } + } + } + + return $symbol_tab; +} + + +/* + * Prunes XHProf raw data: + * + * Any node whose inclusive walltime accounts for less than $prune_percent + * of total walltime is pruned. [It is possible that a child function isn't + * pruned, but one or more of its parents get pruned. In such cases, when + * viewing the child function's hierarchical information, the cost due to + * the pruned parent(s) will be attributed to a special function/symbol + * "__pruned__()".] + * + * @param array $raw_data XHProf raw data to be pruned & validated. + * @param double $prune_percent Any edges that account for less than + * $prune_percent of time will be pruned + * from the raw data. + * + * @return array Returns the pruned raw data. + * + * @author Kannan + */ +function xhprof_prune_run($raw_data, $prune_percent) { + + $main_info = $raw_data["main()"]; + if (empty($main_info)) { + xhprof_error("XHProf: main() missing in raw data"); + return false; + } + + // raw data should contain either wall time or samples information... + if (isset($main_info["wt"])) { + $prune_metric = "wt"; + } else if (isset($main_info["samples"])) { + $prune_metric = "samples"; + } else { + xhprof_error("XHProf: for main() we must have either wt " + ."or samples attribute set"); + return false; + } + + // determine the metrics present in the raw data.. + $metrics = array(); + foreach ($main_info as $metric => $val) { + if (isset($val)) { + $metrics[] = $metric; + } + } + + $prune_threshold = (($main_info[$prune_metric] * $prune_percent) / 100.0); + + init_metrics($raw_data, null, null, false); + $flat_info = xhprof_compute_inclusive_times($raw_data); + + foreach ($raw_data as $parent_child => $info) { + + list($parent, $child) = xhprof_parse_parent_child($parent_child); + + // is this child's overall total from all parents less than threshold? + if ($flat_info[$child][$prune_metric] < $prune_threshold) { + unset($raw_data[$parent_child]); // prune the edge + } else if ($parent && + ($parent != "__pruned__()") && + ($flat_info[$parent][$prune_metric] < $prune_threshold)) { + + // Parent's overall inclusive metric is less than a threshold. + // All edges to the parent node will get nuked, and this child will + // be a dangling child. + // So instead change its parent to be a special function __pruned__(). + $pruned_edge = xhprof_build_parent_child_key("__pruned__()", $child); + + if (isset($raw_data[$pruned_edge])) { + foreach ($metrics as $metric) { + $raw_data[$pruned_edge][$metric]+=$raw_data[$parent_child][$metric]; + } + } else { + $raw_data[$pruned_edge] = $raw_data[$parent_child]; + } + + unset($raw_data[$parent_child]); // prune the edge + } + } + + return $raw_data; +} + + +/** + * Set one key in an array and return the array + * + * @author Kannan + */ +function xhprof_array_set($arr, $k, $v) { + $arr[$k] = $v; + return $arr; +} + +/** + * Removes/unsets one key in an array and return the array + * + * @author Kannan + */ +function xhprof_array_unset($arr, $k) { + unset($arr[$k]); + return $arr; +} + +/** + * Type definitions for URL params + */ +define('XHPROF_STRING_PARAM', 1); +define('XHPROF_UINT_PARAM', 2); +define('XHPROF_FLOAT_PARAM', 3); +define('XHPROF_BOOL_PARAM', 4); + + +/** + * Internal helper function used by various + * xhprof_get_param* flavors for various + * types of parameters. + * + * @param string name of the URL query string param + * + * @author Kannan + */ +function xhprof_get_param_helper($param) { + $val = null; + if (isset($_GET[$param])) + $val = $_GET[$param]; + else if (isset($_POST[$param])) { + $val = $_POST[$param]; + } + return $val; +} + +/** + * Extracts value for string param $param from query + * string. If param is not specified, return the + * $default value. + * + * @author Kannan + */ +function xhprof_get_string_param($param, $default = '') { + $val = xhprof_get_param_helper($param); + + if ($val === null) + return $default; + + return $val; +} + +/** + * Extracts value for unsigned integer param $param from + * query string. If param is not specified, return the + * $default value. + * + * If value is not a valid unsigned integer, logs error + * and returns null. + * + * @author Kannan + */ +function xhprof_get_uint_param($param, $default = 0) { + $val = xhprof_get_param_helper($param); + + if ($val === null) + $val = $default; + + // trim leading/trailing whitespace + $val = trim($val); + + // if it only contains digits, then ok.. + if (ctype_digit($val)) { + return $val; + } + + xhprof_error("$param is $val. It must be an unsigned integer."); + return null; +} + + +/** + * Extracts value for a float param $param from + * query string. If param is not specified, return + * the $default value. + * + * If value is not a valid unsigned integer, logs error + * and returns null. + * + * @author Kannan + */ +function xhprof_get_float_param($param, $default = 0) { + $val = xhprof_get_param_helper($param); + + if ($val === null) + $val = $default; + + // trim leading/trailing whitespace + $val = trim($val); + + // TBD: confirm the value is indeed a float. + if (true) // for now.. + return (float)$val; + + xhprof_error("$param is $val. It must be a float."); + return null; +} + +/** + * Extracts value for a boolean param $param from + * query string. If param is not specified, return + * the $default value. + * + * If value is not a valid unsigned integer, logs error + * and returns null. + * + * @author Kannan + */ +function xhprof_get_bool_param($param, $default = false) { + $val = xhprof_get_param_helper($param); + + if ($val === null) + $val = $default; + + // trim leading/trailing whitespace + $val = trim($val); + + switch (strtolower($val)) { + case '0': + case '1': + $val = (bool)$val; + break; + case 'true': + case 'on': + case 'yes': + $val = true; + break; + case 'false': + case 'off': + case 'no': + $val = false; + break; + default: + xhprof_error("$param is $val. It must be a valid boolean string."); + return null; + } + + return $val; + +} + +/** + * Initialize params from URL query string. The function + * creates globals variables for each of the params + * and if the URL query string doesn't specify a particular + * param initializes them with the corresponding default + * value specified in the input. + * + * @params array $params An array whose keys are the names + * of URL params who value needs to + * be retrieved from the URL query + * string. PHP globals are created + * with these names. The value is + * itself an array with 2-elems (the + * param type, and its default value). + * If a param is not specified in the + * query string the default value is + * used. + * @author Kannan + */ +function xhprof_param_init($params) { + /* Create variables specified in $params keys, init defaults */ + foreach ($params as $k => $v) { + switch ($v[0]) { + case XHPROF_STRING_PARAM: + $p = xhprof_get_string_param($k, $v[1]); + break; + case XHPROF_UINT_PARAM: + $p = xhprof_get_uint_param($k, $v[1]); + break; + case XHPROF_FLOAT_PARAM: + $p = xhprof_get_float_param($k, $v[1]); + break; + case XHPROF_BOOL_PARAM: + $p = xhprof_get_bool_param($k, $v[1]); + break; + default: + xhprof_error("Invalid param type passed to xhprof_param_init: " + . $v[0]); + exit(); + } + + // create a global variable using the parameter name. + $GLOBALS[$k] = $p; + } +} + + +/** + * Given a partial query string $q return matching function names in + * specified XHProf run. This is used for the type ahead function + * selector. + * + * @author Kannan + */ +function xhprof_get_matching_functions($q, $xhprof_data) { + + $matches = array(); + + foreach ($xhprof_data as $parent_child => $info) { + list($parent, $child) = xhprof_parse_parent_child($parent_child); + if (stripos($parent, $q) !== false) { + $matches[$parent] = 1; + } + if (stripos($child, $q) !== false) { + $matches[$child] = 1; + } + } + + $res = array_keys($matches); + + // sort it so the answers are in some reliable order... + asort($res); + + return ($res); +} + diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 927ceb8589..30e05c36b6 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1,397 +1,415 @@ + array( + 'uri' => '/res/ac3fc983/rsrc/css/aphront/dark-console.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/aphront/dark-console.css', + ), 'aphront-dialog-view-css' => array( 'uri' => '/res/a05107ae/rsrc/css/aphront/dialog-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/dialog-view.css', ), 'aphront-form-view-css' => array( 'uri' => '/res/785ac1c6/rsrc/css/aphront/form-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/form-view.css', ), 'aphront-panel-view-css' => array( 'uri' => '/res/63672373/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/panel-view.css', ), 'aphront-request-failure-view-css' => array( 'uri' => '/res/97b8337a/rsrc/css/aphront/request-failure-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/request-failure-view.css', ), 'aphront-side-nav-view-css' => array( 'uri' => '/res/0fc0545c/rsrc/css/aphront/side-nav-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/side-nav-view.css', ), 'aphront-table-view-css' => array( - 'uri' => '/res/52b0191f/rsrc/css/aphront/table-view.css', + 'uri' => '/res/de3a1e4c/rsrc/css/aphront/table-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/table-view.css', ), 'aphront-tokenizer-control-css' => array( 'uri' => '/res/a3d23074/rsrc/css/aphront/tokenizer.css', 'type' => 'css', 'requires' => array( 0 => 'aphront-typeahead-control-css', ), 'disk' => '/rsrc/css/aphront/tokenizer.css', ), 'aphront-typeahead-control-css' => array( 'uri' => '/res/928df9f0/rsrc/css/aphront/typeahead.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/aphront/typeahead.css', ), 'phabricator-standard-page-view' => array( 'uri' => '/res/fb02fb0e/rsrc/css/application/base/standard-page-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/base/standard-page-view.css', ), 'differential-revision-add-comment-css' => array( 'uri' => '/res/623fef21/rsrc/css/application/differential/add-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/add-comment.css', ), 'differential-changeset-view-css' => array( 'uri' => '/res/11e7232a/rsrc/css/application/differential/changeset-view.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/changeset-view.css', ), 'differential-core-view-css' => array( 'uri' => '/res/525d1a12/rsrc/css/application/differential/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/core.css', ), 'differential-revision-comment-list-css' => array( 'uri' => '/res/a1c117db/rsrc/css/application/differential/revision-comment-list.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment-list.css', ), 'differential-revision-comment-css' => array( 'uri' => '/res/bf6369c6/rsrc/css/application/differential/revision-comment.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-comment.css', ), 'differential-revision-detail-css' => array( 'uri' => '/res/230a67c6/rsrc/css/application/differential/revision-detail.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-detail.css', ), 'differential-revision-history-css' => array( 'uri' => '/res/755f3da3/rsrc/css/application/differential/revision-history.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/revision-history.css', ), 'differential-table-of-contents-css' => array( 'uri' => '/res/a4a7b2b5/rsrc/css/application/differential/table-of-contents.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/differential/table-of-contents.css', ), 'phabricator-directory-css' => array( 'uri' => '/res/6a000601/rsrc/css/application/directory/phabricator-directory.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/application/directory/phabricator-directory.css', ), 'phabricator-core-buttons-css' => array( 'uri' => '/res/6e348ba4/rsrc/css/core/buttons.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/buttons.css', ), 'phabricator-core-css' => array( 'uri' => '/res/39ce37c2/rsrc/css/core/core.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/core.css', ), 'phabricator-core-dialog-css' => array( 'uri' => '/res/f66cec41/rsrc/css/core/dialog.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/dialog.css', ), 'phabricator-remarkup-css' => array( 'uri' => '/res/786989c3/rsrc/css/core/remarkup.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/remarkup.css', ), 'syntax-highlighting-css' => array( 'uri' => '/res/fb673ece/rsrc/css/core/syntax.css', 'type' => 'css', 'requires' => array( ), 'disk' => '/rsrc/css/core/syntax.css', ), + 'javelin-behavior-dark-console' => + array( + 'uri' => '/res/453503f4/rsrc/js/application/core/behavior-dark-console.js', + 'type' => 'js', + 'requires' => + array( + ), + 'disk' => '/rsrc/js/application/core/behavior-dark-console.js', + ), 'javelin-behavior-aphront-basic-tokenizer' => array( 'uri' => '/res/8317d761/rsrc/js/application/core/behavior-tokenizer.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), 'javelin-behavior-differential-feedback-preview' => array( 'uri' => '/res/34fbb670/rsrc/js/application/differential/behavior-comment-preview.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js', ), 'javelin-behavior-differential-edit-inline-comments' => array( - 'uri' => '/res/be5ed33e/rsrc/js/application/differential/behavior-edit-inline-comments.js', + 'uri' => '/res/f5b54891/rsrc/js/application/differential/behavior-edit-inline-comments.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-edit-inline-comments.js', ), 'javelin-behavior-differential-populate' => array( 'uri' => '/res/f7efbf62/rsrc/js/application/differential/behavior-populate.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-populate.js', ), 'javelin-behavior-differential-show-more' => array( 'uri' => '/res/d26ebcae/rsrc/js/application/differential/behavior-show-more.js', 'type' => 'js', 'requires' => array( 0 => 'javelin-lib-dev', ), 'disk' => '/rsrc/js/application/differential/behavior-show-more.js', ), 'javelin-magical-init' => array( 'uri' => '/res/76614f84/rsrc/js/javelin/init.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/init.dev.js', ), 'javelin-init-prod' => array( 'uri' => '/res/1267c868/rsrc/js/javelin/init.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/init.min.js', ), 'javelin-lib-dev' => array( 'uri' => '/res/53784c9a/rsrc/js/javelin/javelin.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/javelin.dev.js', ), 'javelin-lib-prod' => array( 'uri' => '/res/2f2b3b2e/rsrc/js/javelin/javelin.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/javelin.min.js', ), 'javelin-typeahead-dev' => array( 'uri' => '/res/6de6ae59/rsrc/js/javelin/typeahead.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/typeahead.dev.js', ), 'javelin-typeahead-prod' => array( 'uri' => '/res/69d5fad1/rsrc/js/javelin/typeahead.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/typeahead.min.js', ), 'javelin-workflow-dev' => array( 'uri' => '/res/7e690e16/rsrc/js/javelin/workflow.dev.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/workflow.dev.js', ), 'javelin-workflow-prod' => array( 'uri' => '/res/b758e0a0/rsrc/js/javelin/workflow.min.js', 'type' => 'js', 'requires' => array( ), 'disk' => '/rsrc/js/javelin/workflow.min.js', ), ), array ( 'packages' => array ( - '4bb7e37f' => + 'c5efa388' => array ( 'name' => 'core.pkg.css', 'symbols' => array ( 0 => 'phabricator-core-css', 1 => 'phabricator-core-buttons-css', 2 => 'phabricator-standard-page-view', 3 => 'aphront-dialog-view-css', 4 => 'aphront-form-view-css', 5 => 'aphront-panel-view-css', 6 => 'aphront-side-nav-view-css', 7 => 'aphront-table-view-css', 8 => 'aphront-tokenizer-control-css', 9 => 'aphront-typeahead-control-css', 10 => 'phabricator-directory-css', ), - 'uri' => '/res/pkg/4bb7e37f/core.pkg.css', + 'uri' => '/res/pkg/c5efa388/core.pkg.css', 'type' => 'css', ), 'f399aad7' => array ( 'name' => 'differential.pkg.css', 'symbols' => array ( 0 => 'differential-core-view-css', 1 => 'differential-changeset-view-css', 2 => 'differential-revision-detail-css', 3 => 'differential-revision-history-css', 4 => 'differential-table-of-contents-css', ), 'uri' => '/res/pkg/f399aad7/differential.pkg.css', 'type' => 'css', ), ), 'reverse' => array ( - 'phabricator-core-css' => '4bb7e37f', - 'phabricator-core-buttons-css' => '4bb7e37f', - 'phabricator-standard-page-view' => '4bb7e37f', - 'aphront-dialog-view-css' => '4bb7e37f', - 'aphront-form-view-css' => '4bb7e37f', - 'aphront-panel-view-css' => '4bb7e37f', - 'aphront-side-nav-view-css' => '4bb7e37f', - 'aphront-table-view-css' => '4bb7e37f', - 'aphront-tokenizer-control-css' => '4bb7e37f', - 'aphront-typeahead-control-css' => '4bb7e37f', - 'phabricator-directory-css' => '4bb7e37f', + 'phabricator-core-css' => 'c5efa388', + 'phabricator-core-buttons-css' => 'c5efa388', + 'phabricator-standard-page-view' => 'c5efa388', + 'aphront-dialog-view-css' => 'c5efa388', + 'aphront-form-view-css' => 'c5efa388', + 'aphront-panel-view-css' => 'c5efa388', + 'aphront-side-nav-view-css' => 'c5efa388', + 'aphront-table-view-css' => 'c5efa388', + 'aphront-tokenizer-control-css' => 'c5efa388', + 'aphront-typeahead-control-css' => 'c5efa388', + 'phabricator-directory-css' => 'c5efa388', 'differential-core-view-css' => 'f399aad7', 'differential-changeset-view-css' => 'f399aad7', 'differential-revision-detail-css' => 'f399aad7', 'differential-revision-history-css' => 'f399aad7', 'differential-table-of-contents-css' => 'f399aad7', ), )); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ed66f1dc3e..3ef9c0e99b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,350 +1,372 @@ array( 'Aphront400Response' => 'aphront/response/400', 'Aphront404Response' => 'aphront/response/404', 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontController' => 'aphront/controller', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', 'AphrontDialogResponse' => 'aphront/response/dialog', 'AphrontDialogView' => 'view/dialog', 'AphrontErrorView' => 'view/form/error', 'AphrontException' => 'aphront/exception/base', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormCheckboxControl' => 'view/form/control/checkbox', 'AphrontFormControl' => 'view/form/control/base', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormMarkupControl' => 'view/form/control/markup', 'AphrontFormPasswordControl' => 'view/form/control/password', 'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha', 'AphrontFormSelectControl' => 'view/form/control/select', 'AphrontFormStaticControl' => 'view/form/control/static', 'AphrontFormSubmitControl' => 'view/form/control/submit', 'AphrontFormTextAreaControl' => 'view/form/control/textarea', 'AphrontFormTextControl' => 'view/form/control/text', 'AphrontFormTokenizerControl' => 'view/form/control/tokenizer', 'AphrontFormView' => 'view/form/base', 'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql', 'AphrontNullView' => 'view/null', 'AphrontPageView' => 'view/page/base', 'AphrontPanelView' => 'view/layout/panel', 'AphrontQueryConnectionException' => 'storage/exception/connection', 'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost', 'AphrontQueryCountException' => 'storage/exception/count', 'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectException' => 'aphront/exception/redirect', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontRequest' => 'aphront/request', 'AphrontRequestFailureView' => 'view/page/failure', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infrastructure/celerity/api', 'CelerityResourceController' => 'infrastructure/celerity/controller', 'CelerityResourceMap' => 'infrastructure/celerity/map', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/response', 'ConduitAPIMethod' => 'applications/conduit/method/base', 'ConduitAPIRequest' => 'applications/conduit/protocol/request', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', 'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find', 'ConduitException' => 'applications/conduit/protocol/exception', + 'DarkConsole' => 'aphront/console/api', + 'DarkConsoleController' => 'aphront/console/controller', + 'DarkConsoleCore' => 'aphront/console/core', + 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog', + 'DarkConsolePlugin' => 'aphront/console/plugin/base', + 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request', + 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services', + 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof', + 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', 'DifferentialChangeType' => 'applications/differential/constants/changetype', 'DifferentialChangeset' => 'applications/differential/storage/changeset', 'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview', 'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview', 'DifferentialChangesetParser' => 'applications/differential/parser/changeset', 'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview', 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', 'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit', 'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', 'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist', 'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail', 'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit', 'DifferentialRevisionEditor' => 'applications/differential/editor/revision', 'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist', 'DifferentialRevisionListData' => 'applications/differential/data/revisionlist', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory', 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'Phabricator404Controller' => 'applications/base/controller/404', 'PhabricatorAuthController' => 'applications/auth/controller/base', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console', 'PhabricatorConduitController' => 'applications/conduit/controller/base', 'PhabricatorConduitDAO' => 'applications/conduit/storage/base', 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorEmailLoginController' => 'applications/auth/controller/email', 'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken', 'PhabricatorEnv' => 'infrastructure/env', 'PhabricatorFacebookAuthController' => 'applications/auth/controller/facebookauth', 'PhabricatorFacebookAuthDiagnosticsController' => 'applications/auth/controller/facebookauth/diagnostics', 'PhabricatorFile' => 'applications/files/storage/file', 'PhabricatorFileController' => 'applications/files/controller/base', 'PhabricatorFileDAO' => 'applications/files/storage/base', 'PhabricatorFileListController' => 'applications/files/controller/list', 'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob', 'PhabricatorFileURI' => 'applications/files/uri', 'PhabricatorFileUploadController' => 'applications/files/controller/upload', 'PhabricatorFileViewController' => 'applications/files/controller/view', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', 'PhabricatorLoginController' => 'applications/auth/controller/login', 'PhabricatorLogoutController' => 'applications/auth/controller/logout', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail', 'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist', 'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit', 'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view', 'PhabricatorObjectHandle' => 'applications/phid/handle', 'PhabricatorObjectHandleData' => 'applications/phid/handle/data', 'PhabricatorPHID' => 'applications/phid/storage/phid', 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', 'PhabricatorPHIDController' => 'applications/phid/controller/base', 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', 'PhabricatorPHIDType' => 'applications/phid/storage/type', 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit', 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', 'PhabricatorPeopleProfileController' => 'applications/people/controller/profile', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', + 'PhabricatorXHProfController' => 'applications/xhprof/controller/base', + 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile', + 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol', + 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api', 'celerity_register_resource_map' => 'infrastructure/celerity/map', 'javelin_render_tag' => 'infrastructure/javelin/markup', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_timestamp' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infrastructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'vqueryfx_all' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryDuplicateKeyException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontSideNavView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontWebpageResponse' => 'AphrontResponse', 'CelerityResourceController' => 'AphrontController', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_find_Method' => 'ConduitAPIMethod', + 'DarkConsoleController' => 'AliteController', + 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', + 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', + 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', + 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialInlineComment' => 'DifferentialDAO', 'DifferentialInlineCommentEditController' => 'DifferentialController', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialRevision' => 'DifferentialDAO', 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorController' => 'AphrontController', 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 'PhabricatorFacebookAuthController' => 'PhabricatorAuthController', 'PhabricatorFacebookAuthDiagnosticsController' => 'PhabricatorAuthController', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLoginController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', + 'PhabricatorXHProfController' => 'PhabricatorController', + 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', + 'PhabricatorXHProfProfileSymbolView' => 'AphrontView', + 'PhabricatorXHProfProfileTopLevelView' => 'AphrontView', ), 'requires_interface' => array( ), )); diff --git a/src/aphront/applicationconfiguration/AphrontApplicationConfiguration.php b/src/aphront/applicationconfiguration/AphrontApplicationConfiguration.php index cba9578bb4..36d0e9408d 100644 --- a/src/aphront/applicationconfiguration/AphrontApplicationConfiguration.php +++ b/src/aphront/applicationconfiguration/AphrontApplicationConfiguration.php @@ -1,77 +1,86 @@ request = $request; return $this; } final public function getRequest() { return $this->request; } + final public function getConsole() { + return $this->console; + } + final public function buildController() { $map = $this->getURIMap(); $mapper = new AphrontURIMapper($map); $request = $this->getRequest(); $path = $request->getPath(); list($controller_class, $uri_data) = $mapper->mapPath($path); if (!$controller_class) { return $this->build404Controller(); } PhutilSymbolLoader::loadClass($controller_class); $controller = newv($controller_class, array($request)); return array($controller, $uri_data); } final public function setHost($host) { $this->host = $host; return $this; } final public function getHost() { return $this->host; } final public function setPath($path) { $this->path = $path; return $this; } final public function getPath() { return $this->path; } + final public function willBuildRequest() { + $this->console = new DarkConsoleCore(); + } + } diff --git a/src/aphront/applicationconfiguration/__init__.php b/src/aphront/applicationconfiguration/__init__.php index fa09ec8107..ccf7d6e897 100644 --- a/src/aphront/applicationconfiguration/__init__.php +++ b/src/aphront/applicationconfiguration/__init__.php @@ -1,15 +1,16 @@ true, + 'toggle' => true, + 'visible' => true, + 'plugin' => true, + + 'etc' => true, + )); + + foreach (array_keys($ops) as $op) { + if (isset($params[$op])) { + $this->op = $op; + break; + } + } + $this->data = $params; + } + + public function getShortControllerName() { + return 'DarkConsole'; + } + + public function shouldPreflush() { + return false; + } + + public function process() { + $request = $this->getRequest(); + + if (!$this->op) { + $this->op = 'toggle'; + } + + $coredata = $request->getCoreData(); + $console = $coredata->getConsole(); + + if ($request->isAsync()) { + $return = null; + } else { + $return = '/'; + } + + + switch ($this->op) { + case 'toggle': + $enabled = $coredata->didToggleDarkConsole(); + if ($enabled) { + if (!$console) { + $console = new DarkConsoleCore($coredata); + } + $console->setConsoleSetting( + DarkConsoleCore::SETTING_VISIBLE, + true); + } + break; + case 'tab': + $console->setConsoleSetting( + DarkConsoleCore::SETTING_TAB, + $request->getStr('tab')); + break; + case 'visible': + $console->setConsoleSetting( + DarkConsoleCore::SETTING_VISIBLE, + !$console->getConsoleSetting(DarkConsoleCore::SETTING_VISIBLE)); + break; + } +// return ; + } + +} diff --git a/src/aphront/console/controller/__init__.php b/src/aphront/console/controller/__init__.php new file mode 100644 index 0000000000..bc1a89277c --- /dev/null +++ b/src/aphront/console/controller/__init__.php @@ -0,0 +1,12 @@ +getCoreData()->getViewerContext()->getUserID(), + self::APPLICATION_ID, + $key, + $value); + $guard->release(); + if (!$okay) { + throw new Exception('Failed to set preference setting.'); + } +*/ + } + + public function getConsoleSetting($key) { +// $viewer_id = $this->getCoreData()->getViewerContext()->getUserID(); +// return idx(idx($this->settings[$viewer_id], $key), 'value'); + return true; + } + + public function getPlugin($plugin_name) { + return idx($this->plugins, $plugin_name); + } + + public function __construct() { + +/* + $this->settings = users_multiget_prefs_info( + array($coredata->getViewerContext()->getUserID()), + self::APPLICATION_ID); + + $disabled = $this->getConsoleSetting(self::SETTING_PLUGINS); + $disabled = array_flip(explode(',', $disabled)); +*/ + foreach (self::getPlugins() as $plugin_name) { + $plugin = self::newPlugin($plugin_name); + if ($plugin->isPermanent() || !isset($disabled[$plugin_name])) { + if ($plugin->shouldStartup()) { + $plugin->didStartup(); + $plugin->setConsoleCore($this); + $this->plugins[$plugin_name] = $plugin; + } + } + } + } + + public static function newPlugin($plugin) { + $class = 'DarkConsole'.$plugin.'Plugin'; + PhutilSymbolLoader::loadClass($class); + return newv($class, array()); + } + + public function getEnabledPlugins() { + return $this->plugins; + } + + public function render(AphrontRequest $request) { + + $plugins = $this->getEnabledPlugins(); + + foreach ($plugins as $plugin) { + $plugin->setRequest($request); + $plugin->willShutdown(); + } + + foreach ($plugins as $plugin) { + $plugin->didShutdown(); + } + + foreach ($plugins as $plugin) { + $plugin->setData($plugin->generateData()); + } + + $selected = 'XHProf';//true;//$this->getConsoleSetting(DarkConsoleCore::SETTING_TAB); + $visible = true;//$this->getConsoleSetting(DarkConsoleCore::SETTING_VISIBLE); + + if (!isset($plugins[$selected])) { + $selected = key($plugins); + } + + $tabs = array(); + foreach ($plugins as $key => $plugin) { + $tabs[$key] = array( + 'name' => $plugin->getName(), + 'panel' => $plugin->render(), + ); + } + + $tabs_markup = array(); + $panel_markup = array(); + foreach ($tabs as $key => $data) { + $is_selected = ($key == $selected); + if ($is_selected) { + $style = null; + $tabclass = 'dark-console-tab-selected'; + } else { + $style = 'display: none;'; + $tabclass = null; + } + + $tabs_markup[] = javelin_render_tag( + 'a', + array( + 'class' => "dark-console-tab {$tabclass}", + 'sigil' => 'dark-console-tab', + 'meta' => array( + 'key' => $key, + ), + ), + (string)$data['name']); + + $panel_markup[] = javelin_render_tag( + 'div', + array( + 'class' => 'dark-console-panel', + 'style' => $style, + 'sigil' => 'dark-console-panel', + 'meta' => array( + 'key' => $key, + ), + ), + (string)$data['panel']); + } + + $console = javelin_render_tag( + 'table', + array( + 'class' => 'dark-console', + 'sigil' => 'dark-console', + 'meta' => array( + 'visible' => true, + ), + 'style' => '', + ), + ''. + ''. + implode("\n", $tabs_markup). + ''. + ''.implode("\n", $panel_markup).''. + ''); + + Javelin::initBehavior('dark-console'); + + return "\n\n\n\n".$console."\n\n\n\n"; + } +} + diff --git a/src/aphront/applicationconfiguration/__init__.php b/src/aphront/console/core/__init__.php similarity index 51% copy from src/aphront/applicationconfiguration/__init__.php copy to src/aphront/console/core/__init__.php index fa09ec8107..ccdf4c2167 100644 --- a/src/aphront/applicationconfiguration/__init__.php +++ b/src/aphront/console/core/__init__.php @@ -1,15 +1,16 @@ core = $core; + return $this; + } + + public function getConsoleCore() { + return $this->core; + } + + public function generateData() { + return null; + } + + public function setData($data) { + $this->data = $data; + return $this; + } + + public function getData() { + return $this->data; + } + + public function setRequest($request) { + $this->request = $request; + return $this; + } + + public function getRequest() { + return $this->request; + } + + public function isPermanent() { + return false; + } + + public function shouldStartup() { + return true; + } + + public function didStartup() { + return null; + } + + public function willShutdown() { + return null; + } + + public function didShutdown() { + return null; + } + + public function processRequest() { + return null; + } + +} diff --git a/src/aphront/console/plugin/base/__init__.php b/src/aphront/console/plugin/base/__init__.php new file mode 100644 index 0000000000..1132baa025 --- /dev/null +++ b/src/aphront/console/plugin/base/__init__.php @@ -0,0 +1,10 @@ +getData()); + +/* + if ($count) { + return + + Error Log ({$count}) + ; + } + +*/ + return 'Error Log'; + } + + + public function getDescription() { + return 'Shows errors and warnings.'; + } + + + public function generateData() { +/* + $stub = tabconsole(); + if (!$stub) { + return array(); + } + + $errors = $stub->getErrors(); + + $data = array(); + foreach ($errors as $error) { + if (is_array($error)) { + list($err, $trace) = $error; + $trace = implode("\n", $trace); + } else { + $err = $error->getMessage(); + $trace = $error->getTraceAsString(); + } + $data[] = array( + 'error' => $err, + 'trace' => $trace, + ); + } + return $data; +*/ + } + + + public function render() { + + return '!!'; +/* + $data = $this->getData(); + if (!$data) { + return + +
No errors.
+
; + } + + $markup = ; + $alt = false; + foreach ($data as $error) { + $row = ; + + $text = $error['error']; + $text = preg_replace('/\(in .* on line \d+\)$/', '', trim($text)); + + $trace = $error['trace']; + $trace = explode("\n", $trace); + if (!$trace) { + $trace = array('unknown@0@unknown'); + } + + foreach ($trace as $idx => $traceline) { + list($file, $line, $where) = array_merge( + explode('@', $traceline), + array('?', '?', '?')); + if ($where == 'DarkConsole->addError' || + $where == 'debug_rlog') { + unset($trace[$idx]); + } + } + + $row->appendChild(); + + foreach ($trace as $traceline) { + list($file, $line, $where) = array_merge( + explode('@', $traceline), + array('?', '?', '?')); + $row->appendChild(); + $row->appendChild(); + $markup->appendChild($row); + $row = ; + } + + $alt = !$alt; + } + + return + +

Errors

+
{$markup}
+
; +*/ + } + +} diff --git a/src/aphront/console/plugin/errorlog/__init__.php b/src/aphront/console/plugin/errorlog/__init__.php new file mode 100644 index 0000000000..0137999ed9 --- /dev/null +++ b/src/aphront/console/plugin/errorlog/__init__.php @@ -0,0 +1,12 @@ + $_REQUEST, + 'Server' => $_SERVER, + ); + } + + public function render() { + + $data = $this->getData(); + + $sections = array( + 'Basics' => array( + 'Host' => $data['Server']['SERVER_ADDR'], + 'Hostname' => gethostbyaddr($data['Server']['SERVER_ADDR']), + ), + ); + + $sections = array_merge($sections, $data); + +/* + $out = ; + foreach ($sections as $header => $map) { + $list =
{$text}{$file}:{$line}{$where}()
; + foreach ($map as $key => $value) { + if (!is_scalar($value)) { + $value = fb_json_encode($value); + } + $value = {$value}; + $list->appendChild( + ); + } + $out->appendChild( + +

{$header}

+ {$list} +
); + } + + return $out; +*/ + return "REQUEST"; + } +} diff --git a/src/aphront/console/plugin/request/__init__.php b/src/aphront/console/plugin/request/__init__.php new file mode 100644 index 0000000000..191e9cd6e0 --- /dev/null +++ b/src/aphront/console/plugin/request/__init__.php @@ -0,0 +1,12 @@ +observations = cacheobserver(); + } + + public function render() { + return '!'; + } +} + diff --git a/src/aphront/console/plugin/services/__init__.php b/src/aphront/console/plugin/services/__init__.php new file mode 100644 index 0000000000..aeab5c172b --- /dev/null +++ b/src/aphront/console/plugin/services/__init__.php @@ -0,0 +1,12 @@ +getData(); + + if ($run) { + return ' XHProf'; + } + + return 'XHProf'; + } + + public function getDescription() { + return 'Provides detailed PHP profiling information through XHProf.'; + } + + public function generateData() { + return $this->xhprofID; + } + + public function getXHProfRunID() { + return $this->xhprofID; + } + + public function render() { + if (!DarkConsoleXHProfPluginAPI::isProfilerAvailable()) { + return + '

The "xhprof" PHP extension is not available. Install xhprof '. + 'to enable the XHProf plugin.'; + } + + return '...'; + } + +} +/* + + public function render() { + $run = $this->getData(); + + if ($run) { + $uri = 'http://www.intern.facebook.com/intern/phprof/?run='.$run; + return + +

XHProf Results

+
+ Permalink +
{$key}{$value}