Page MenuHomePhabricator

D21793.diff
No OneTemporary

D21793.diff

diff --git a/externals/diff_match_patch/diff_match_patch.php b/externals/diff_match_patch/diff_match_patch.php
deleted file mode 100644
--- a/externals/diff_match_patch/diff_match_patch.php
+++ /dev/null
@@ -1,2117 +0,0 @@
-<?php
-/**
- * Diff Match and Patch
- *
- * Copyright 2006 Google Inc.
- * http://code.google.com/p/google-diff-match-patch/
- *
- * php port by Tobias Buschor shwups.ch
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * @fileoverview Computes the difference between two texts to create a patch.
- * Applies the patch onto another text, allowing for errors.
- * @author fraser@google.com (Neil Fraser)
- */
-
-/**
- * Class containing the diff, match and patch methods.
- * @constructor
- */
-class diff_match_patch {
-
- // Defaults.
- // Redefine these in your program to override the defaults.
-
- // Number of seconds to map a diff before giving up (0 for infinity).
- public $Diff_Timeout = 1.0;
- // Cost of an empty edit operation in terms of edit characters.
- public $Diff_EditCost = 4;
- // The size beyond which the double-ended diff activates.
- // Double-ending is twice as fast, but less accurate.
- public $Diff_DualThreshold = 32;
- // At what point is no match declared (0.0 = perfection, 1.0 = very loose).
- public $Match_Threshold = 0.5;
- // How far to search for a match (0 = exact location, 1000+ = broad match).
- // A match this many characters away from the expected location will add
- // 1.0 to the score (0.0 is a perfect match).
- public $Match_Distance = 1000;
- // When deleting a large block of text (over ~64 characters), how close does
- // the contents have to match the expected contents. (0.0 = perfection,
- // 1.0 = very loose). Note that Match_Threshold controls how closely the
- // end points of a delete need to match.
- public $Patch_DeleteThreshold = 0.5;
- // Chunk size for context length.
- public $Patch_Margin = 4;
-
- /**
- * Compute the number of bits in an int.
- * The normal answer for JavaScript is 32.
- * @return {number} Max bits
-
- function getMaxBits() {
- var maxbits = 0;
- var oldi = 1;
- var newi = 2;
- while (oldi != newi) {
- maxbits++;
- oldi = newi;
- newi = newi << 1;
- }
- return maxbits;
- }
- // How many bits in a number?
- this.Match_MaxBits = getMaxBits();
- */
- // DIFF FUNCTIONS
-
- /**
- * Find the differences between two texts. Simplifies the problem by stripping
- * any common prefix or suffix off the texts before diffing.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {boolean} opt_checklines Optional speedup flag. If present and false,
- * then don't run a line-level diff first to identify the changed areas.
- * Defaults to true, which does a faster, slightly less optimal diff
- * @return {Array.<Array.<number|string>>} Array of diff tuples.
- */
- function diff_main($text1, $text2, $checklines = true) {
- // Check for equality (speedup)
- if ($text1 === $text2) {
- return array ( array ( DIFF_EQUAL, $text1) );
- }
-
- // Trim off common prefix (speedup)
- $commonlength = $this->diff_commonPrefix($text1, $text2);
- $commonprefix = mb_substr($text1, 0, $commonlength);
- $text1 = mb_substr($text1, $commonlength);
- $text2 = mb_substr($text2, $commonlength);
-
- // Trim off common suffix (speedup)
- $commonlength = $this->diff_commonSuffix($text1, $text2);
- $commonsuffix = mb_substr($text1, mb_strlen($text1) - $commonlength);
- $text1 = mb_substr($text1, 0, mb_strlen($text1) - $commonlength);
- $text2 = mb_substr($text2, 0, mb_strlen($text2) - $commonlength);
-
- // Compute the diff on the middle block
- $diffs = $this->diff_compute($text1, $text2, $checklines);
-
- // Restore the prefix and suffix
- if ($commonprefix !== '') {
- array_unshift($diffs, array ( DIFF_EQUAL, $commonprefix ));
- }
- if ($commonsuffix !== '') {
- array_push($diffs, array ( DIFF_EQUAL, $commonsuffix ));
- }
- $this->diff_cleanupMerge($diffs);
- return $diffs;
- }
-
- /**
- * Find the differences between two texts. Assumes that the texts do not
- * have any common prefix or suffix.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @param {boolean} checklines Speedup flag. If false, then don't run a
- * line-level diff first to identify the changed areas.
- * If true, then run a faster, slightly less optimal diff
- * @return {Array.<Array.<number|string>>} Array of diff tuples.
- * @private
- */
- function diff_compute($text1, $text2, $checklines) {
-
- if ($text1 === '') {
- // Just add some text (speedup)
- return array ( array ( DIFF_INSERT, $text2 ) );
- }
-
- if ($text2 === '') {
- // Just delete some text (speedup)
- return array ( array ( DIFF_DELETE, $text1 ) );
- }
-
- $longtext = mb_strlen($text1) > mb_strlen($text2) ? $text1 : $text2;
- $shorttext = mb_strlen($text1) > mb_strlen($text2) ? $text2 : $text1;
- $i = mb_strpos($longtext, $shorttext);
- if ($i !== false) {
- // Shorter text is inside the longer text (speedup)
- $diffs = array (
- array ( DIFF_INSERT, mb_substr($longtext, 0, $i) ),
- array ( DIFF_EQUAL, $shorttext ),
- array ( DIFF_INSERT, mb_substr($longtext, $i +mb_strlen($shorttext)) )
- );
-
- // Swap insertions for deletions if diff is reversed.
- if (mb_strlen($text1) > mb_strlen($text2)) {
- $diffs[0][0] = $diffs[2][0] = DIFF_DELETE;
- }
- return $diffs;
- }
- $longtext = $shorttext = null; // Garbage collect
-
- // Check to see if the problem can be split in two.
- $hm = $this->diff_halfMatch($text1, $text2);
- if ($hm) {
- // A half-match was found, sort out the return data.
- $text1_a = $hm[0];
- $text1_b = $hm[1];
- $text2_a = $hm[2];
- $text2_b = $hm[3];
- $mid_common = $hm[4];
- // Send both pairs off for separate processing.
- $diffs_a = $this->diff_main($text1_a, $text2_a, $checklines);
- $diffs_b = $this->diff_main($text1_b, $text2_b, $checklines);
- // Merge the results.
- return array_merge($diffs_a, array (
- array (
- DIFF_EQUAL,
- $mid_common
- )
- ), $diffs_b);
- }
-
- // Perform a real diff.
- if ($checklines && (mb_strlen($text1) < 100 || mb_strlen($text2) < 100)) {
- // Too trivial for the overhead.
- $checklines = false;
- }
- $linearray = null;
- if ($checklines) {
- // Scan the text on a line-by-line basis first.
- $a = $this->diff_linesToChars($text1, $text2);
- $text1 = $a[0];
- $text2 = $a[1];
- $linearray = $a[2];
- }
- $diffs = $this->diff_map($text1, $text2);
- if (!$diffs) {
- // No acceptable result.
- $diffs = array (
- array (
- DIFF_DELETE,
- $text1
- ),
- array (
- DIFF_INSERT,
- $text2
- )
- );
- }
- if ($checklines) {
- // Convert the diff back to original text.
- $this->diff_charsToLines($diffs, $linearray);
- // Eliminate freak matches (e.g. blank lines)
- $this->diff_cleanupSemantic($diffs);
-
- // Rediff any replacement blocks, this time character-by-character.
- // Add a dummy entry at the end.
- array_push($diffs, array (
- DIFF_EQUAL,
- ''
- ));
- $pointer = 0;
- $count_delete = 0;
- $count_insert = 0;
- $text_delete = '';
- $text_insert = '';
- while ($pointer < count($diffs)) {
- switch ($diffs[$pointer][0]) {
- case DIFF_INSERT :
- $count_insert++;
- $text_insert .= $diffs[$pointer][1];
- break;
- case DIFF_DELETE :
- $count_delete++;
- $text_delete .= $diffs[$pointer][1];
- break;
- case DIFF_EQUAL :
- // Upon reaching an equality, check for prior redundancies.
- if ($count_delete >= 1 && $count_insert >= 1) {
- // Delete the offending records and add the merged ones.
- $a = $this->diff_main($text_delete, $text_insert, false);
- array_splice($diffs, $pointer - $count_delete - $count_insert, $count_delete + $count_insert);
-
- $pointer = $pointer - $count_delete - $count_insert;
- for ($j = count($a) - 1; $j >= 0; $j--) {
- array_splice($diffs, $pointer, 0, array($a[$j]));
- }
- $pointer = $pointer +count($a);
- }
- $count_insert = 0;
- $count_delete = 0;
- $text_delete = '';
- $text_insert = '';
- break;
- }
- $pointer++;
- }
- array_pop($diffs); // Remove the dummy entry at the end.
- }
- return $diffs;
- }
-
- /**
- * Split two texts into an array of strings. Reduce the texts to a string of
- * hashes where each Unicode character represents one line.
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {Array.<string|Array.<string>>} Three element Array, containing the
- * encoded text1, the encoded text2 and the array of unique strings. The
- * zeroth element of the array of unique strings is intentionally blank.
- * @private
- */
- function diff_linesToChars($text1, $text2) {
- $lineArray = array(); // e.g. lineArray[4] == 'Hello\n'
- $lineHash = array(); // e.g. lineHash['Hello\n'] == 4
-
- // '\x00' is a valid character, but various debuggers don't like it.
- // So we'll insert a junk entry to avoid generating a null character.
- $lineArray[0] = '';
-
- $chars1 = $this->diff_linesToCharsMunge($text1, $lineArray, $lineHash);
- $chars2 = $this->diff_linesToCharsMunge($text2, $lineArray, $lineHash);
- return array (
- $chars1,
- $chars2,
- $lineArray
- );
- }
-
- /**
- * Split a text into an array of strings. Reduce the texts to a string of
- * hashes where each Unicode character represents one line.
- * Modifies linearray and linehash through being a closure.
- * @param {string} text String to encode
- * @return {string} Encoded string
- * @private
- */
- function diff_linesToCharsMunge($text, &$lineArray, &$lineHash) {
- $chars = '';
- // Walk the text, pulling out a mb_substring for each line.
- // text.split('\n') would would temporarily double our memory footprint.
- // Modifying text would create many large strings to garbage collect.
- $lineStart = 0;
- $lineEnd = -1;
- // Keeping our own length variable is faster than looking it up.
- $lineArrayLength = count($lineArray);
- while ($lineEnd < mb_strlen($text) - 1) {
- $lineEnd = mb_strpos($text, "\n", $lineStart);
- if ($lineEnd === false) {
- $lineEnd = mb_strlen($text) - 1;
- }
- $line = mb_substr($text, $lineStart, $lineEnd +1 -$lineStart);
- $lineStart = $lineEnd +1;
-
- if ( isset($lineHash[$line]) ) {
- $chars .= mb_chr($lineHash[$line]);
- } else {
- $chars .= mb_chr($lineArrayLength);
- $lineHash[$line] = $lineArrayLength;
- $lineArray[$lineArrayLength++] = $line;
- }
- }
- return $chars;
- }
- /**
- * Rehydrate the text in a diff from a string of line hashes to real lines of
- * text.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @param {Array.<string>} lineArray Array of unique strings.
- * @private
- */
- function diff_charsToLines(&$diffs, $lineArray) {
- for ($x = 0; $x < count($diffs); $x++) {
- $chars = $diffs[$x][1];
- $text = array ();
- for ($y = 0; $y < mb_strlen($chars); $y++) {
- $text[$y] = $lineArray[charCodeAt($chars, $y)];
- }
- $diffs[$x][1] = implode('',$text);
- }
- }
-
- /**
- * Explore the intersection points between the two texts.
- * @param {string} text1 Old string to be diffed.
- * @param {string} text2 New string to be diffed.
- * @return {Array.<Array.<number|string>>?} Array of diff tuples or null if no
- * diff available.
- * @private
- */
- function diff_map($text1, $text2) {
- // Don't run for too long.
- $ms_end = microtime(true) + $this->Diff_Timeout;
-
- // Cache the text lengths to prevent multiple calls.
- $text1_length = mb_strlen($text1);
- $text2_length = mb_strlen($text2);
- $max_d = $text1_length + $text2_length -1;
- $doubleEnd = $this->Diff_DualThreshold * 2 < $max_d;
- $v_map1 = array();
- $v_map2 = array();
- $v1 = array();
- $v2 = array();
- $v1[1] = 0;
- $v2[1] = 0;
- $x = null;
- $y = null;
- $footstep = null; // Used to track overlapping paths.
- $footsteps = array();
- $done = false;
- // Safari 1.x doesn't have hasOwnProperty
- //? $hasOwnProperty = !!(footsteps.hasOwnProperty);
- // If the total number of characters is odd, then the front path will collide
- // with the reverse path.
- $front = ($text1_length + $text2_length) % 2;
- for ($d = 0; $d < $max_d; $d++) {
- // Bail out if timeout reached.
- if ($this->Diff_Timeout > 0 && microtime(true) > $ms_end) {
- return null; // zzz
- }
-
- // Walk the front path one step.
- $v_map1[$d] = array ();
- for ($k = -$d; $k <= $d; $k += 2) {
- if ($k == -$d || $k != $d && $v1[$k -1] < $v1[$k +1]) {
- $x = $v1[$k +1];
- } else {
- $x = $v1[$k -1] + 1;
- }
- $y = $x - $k;
- if ($doubleEnd) {
- $footstep = $x . ',' . $y;
- if ($front && isset ($footsteps[$footstep])) {
- $done = true;
- }
- if (!$front) {
- $footsteps[$footstep] = $d;
- }
- }
- while (!$done && ($x < $text1_length) && ($y < $text2_length) && (mb_substr($text1, $x, 1) == mb_substr($text2, $y, 1)) ) {
- $x++;
- $y++;
- if ($doubleEnd) {
- $footstep = $x . ',' . $y;
- if ($front && isset ($footsteps[$footstep])) {
- $done = true;
- }
- if (!$front) {
- $footsteps[$footstep] = $d;
- }
- }
- }
- $v1[$k] = $x;
- $v_map1[$d][$x . ',' . $y] = true;
- if ($x == $text1_length && $y == $text2_length) {
- // Reached the end in single-path mode.
- return $this->diff_path1($v_map1, $text1, $text2);
- }
- elseif ($done) {
- // Front path ran over reverse path.
-
- $v_map2 = array_slice($v_map2, 0, $footsteps[$footstep] + 1);
- $a = $this->diff_path1($v_map1, mb_substr($text1, 0, $x), mb_substr($text2, 0, $y));
-
- return array_merge($a, $this->diff_path2($v_map2, mb_substr($text1, $x), mb_substr($text2, $y)));
- }
- }
-
- if ($doubleEnd) {
- // Walk the reverse path one step.
- $v_map2[$d] = array();
- for ($k = -$d; $k <= $d; $k += 2) {
- if ($k == -$d || $k != $d && $v2[$k -1] < $v2[$k +1]) {
- $x = $v2[$k +1];
- } else {
- $x = $v2[$k -1] + 1;
- }
- $y = $x - $k;
- $footstep = ($text1_length - $x) . ',' . ($text2_length - $y);
- if (!$front && isset ($footsteps[$footstep])) {
- $done = true;
- }
- if ($front) {
- $footsteps[$footstep] = $d;
- }
- while (!$done && $x < $text1_length && $y < $text2_length && mb_substr($text1, $text1_length - $x -1, 1) == mb_substr($text2, $text2_length - $y -1, 1) ) {
- $x++;
- $y++;
- $footstep = ($text1_length - $x) . ',' . ($text2_length - $y);
- if (!$front && isset ($footsteps[$footstep])) {
- $done = true;
- }
- if ($front) {
- $footsteps[$footstep] = $d;
- }
- }
- $v2[$k] = $x;
- $v_map2[$d][$x . ',' . $y] = true;
- if ($done) {
- // Reverse path ran over front path.
- $v_map1 = array_slice($v_map1, 0, $footsteps[$footstep] + 1);
- $a = $this->diff_path1($v_map1, mb_substr($text1, 0, $text1_length - $x), mb_substr($text2, 0, $text2_length - $y));
- return array_merge($a, $this->diff_path2($v_map2, mb_substr($text1, $text1_length - $x), mb_substr($text2, $text2_length - $y)));
- }
- }
- }
- }
- // Number of diffs equals number of characters, no commonality at all.
- return null;
- }
-
- /**
- * Work from the middle back to the start to determine the path.
- * @param {Array.<Object>} v_map Array of paths.ers
- * @param {string} text1 Old string fragment to be diffed.
- * @param {string} text2 New string fragment to be diffed.
- * @return {Array.<Array.<number|string>>} Array of diff tuples.
- * @private
- */
- function diff_path1($v_map, $text1, $text2) {
- $path = array ();
- $x = mb_strlen($text1);
- $y = mb_strlen($text2);
- /** @type {number?} */
- $last_op = null;
- for ($d = count($v_map) - 2; $d >= 0; $d--) {
- while (1) {
- if (isset ($v_map[$d][($x -1) . ',' . $y])) {
- $x--;
- if ($last_op === DIFF_DELETE) {
- $path[0][1] = mb_substr($text1, $x, 1) . $path[0][1];
- } else {
- array_unshift($path, array (
- DIFF_DELETE,
- mb_substr($text1, $x, 1)
- ));
- }
- $last_op = DIFF_DELETE;
- break;
- } elseif (isset ($v_map[$d][$x . ',' . ($y -1)])) {
- $y--;
- if ($last_op === DIFF_INSERT) {
- $path[0][1] = mb_substr($text2, $y, 1) . $path[0][1];
- } else {
- array_unshift($path, array (
- DIFF_INSERT,
- mb_substr($text2, $y, 1)
- ));
- }
- $last_op = DIFF_INSERT;
- break;
- } else {
- $x--;
- $y--;
- //if (text1.charAt(x) != text2.charAt(y)) {
- // throw new Error('No diagonal. Can\'t happen. (diff_path1)');
- //}
- if ($last_op === DIFF_EQUAL) {
- $path[0][1] = mb_substr($text1, $x, 1) . $path[0][1];
- } else {
- array_unshift($path, array (
- DIFF_EQUAL,
- mb_substr($text1, $x, 1)
- ));
- }
- $last_op = DIFF_EQUAL;
- }
- }
- }
- return $path;
- }
-
- /**
- * Work from the middle back to the end to determine the path.
- * @param {Array.<Object>} v_map Array of paths.
- * @param {string} text1 Old string fragment to be diffed.
- * @param {string} text2 New string fragment to be diffed.
- * @return {Array.<Array.<number|string>>} Array of diff tuples.
- * @private
- */
- function diff_path2($v_map, $text1, $text2) {
- $path = array ();
- $pathLength = 0;
- $x = mb_strlen($text1);
- $y = mb_strlen($text2);
- /** @type {number?} */
- $last_op = null;
- for ($d = count($v_map) - 2; $d >= 0; $d--) {
- while (1) {
- if (isset ($v_map[$d][($x -1) . ',' . $y])) {
- $x--;
- if ($last_op === DIFF_DELETE) {
- $path[$pathLength -1][1] .= $text1[mb_strlen($text1) - $x -1];
- } else {
- $path[$pathLength++] = array (
- DIFF_DELETE,
- $text1[mb_strlen($text1) - $x -1]
- );
- }
- $last_op = DIFF_DELETE;
- break;
- }
- elseif (isset ($v_map[$d][$x . ',' . ($y -1)])) {
- $y--;
- if ($last_op === DIFF_INSERT) {
- $path[$pathLength -1][1] .= $text2[mb_strlen($text2) - $y -1];
- } else {
- $path[$pathLength++] = array (
- DIFF_INSERT,
- $text2[mb_strlen($text2) - $y -1]
- );
- }
- $last_op = DIFF_INSERT;
- break;
- } else {
- $x--;
- $y--;
- //if (text1.charAt(text1.length - x - 1) !=
- // text2.charAt(text2.length - y - 1)) {
- // throw new Error('No diagonal. Can\'t happen. (diff_path2)');
- //}
- if ($last_op === DIFF_EQUAL) {
- $path[$pathLength -1][1] .= $text1[mb_strlen($text1) - $x -1];
- } else {
- $path[$pathLength++] = array (
- DIFF_EQUAL,
- $text1[mb_strlen($text1) - $x -1]
- );
- }
- $last_op = DIFF_EQUAL;
- }
- }
- }
- return $path;
- }
-
- /**
- * Determine the common prefix of two strings
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {number} The number of characters common to the start of each
- * string.
- */
- function diff_commonPrefix($text1, $text2) {
- for ($i = 0; 1; $i++) {
- $t1 = mb_substr($text1, $i, 1);
- $t2 = mb_substr($text2, $i, 1);
- if($t1==='' || $t2==='' || $t1 !== $t2 ){
- return $i;
- }
- }
- }
-
- /**
- * Determine the common suffix of two strings
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {number} The number of characters common to the end of each string.
- */
- function diff_commonSuffix($text1, $text2) {
- return $this->diff_commonPrefix( strrev($text1), strrev($text2) );
- }
-
- /**
- * Do the two texts share a mb_substring which is at least half the length of the
- * longer text?
- * @param {string} text1 First string.
- * @param {string} text2 Second string.
- * @return {Array.<string>?} Five element Array, containing the prefix of
- * text1, the suffix of text1, the prefix of text2, the suffix of
- * text2 and the common middle. Or null if there was no match.
- */
- function diff_halfMatch($text1, $text2) {
- $longtext = mb_strlen($text1) > mb_strlen($text2) ? $text1 : $text2;
- $shorttext = mb_strlen($text1) > mb_strlen($text2) ? $text2 : $text1;
- if (mb_strlen($longtext) < 10 || mb_strlen($shorttext) < 1) {
- return null; // Pointless.
- }
-
- // First check if the second quarter is the seed for a half-match.
- $hm1 = $this->diff_halfMatchI($longtext, $shorttext, ceil(mb_strlen($longtext) / 4));
- // Check again based on the third quarter.
- $hm2 = $this->diff_halfMatchI($longtext, $shorttext, ceil(mb_strlen($longtext) / 2));
-
- if (!$hm1 && !$hm2) {
- return null;
- } elseif (!$hm2) {
- $hm = $hm1;
- } elseif (!$hm1) {
- $hm = $hm2;
- } else {
- // Both matched. Select the longest.
- $hm = mb_strlen($hm1[4]) > mb_strlen($hm2[4]) ? $hm1 : $hm2;
- }
-
- // A half-match was found, sort out the return data.
- if (mb_strlen($text1) > mb_strlen($text2)) {
- $text1_a = $hm[0];
- $text1_b = $hm[1];
- $text2_a = $hm[2];
- $text2_b = $hm[3];
- } else {
- $text2_a = $hm[0];
- $text2_b = $hm[1];
- $text1_a = $hm[2];
- $text1_b = $hm[3];
- }
- $mid_common = $hm[4];
- return array( $text1_a, $text1_b, $text2_a, $text2_b, $mid_common );
- }
-
- /**
- * Does a mb_substring of shorttext exist within longtext such that the mb_substring
- * is at least half the length of longtext?
- * Closure, but does not reference any external variables.
- * @param {string} longtext Longer string.
- * @param {string} shorttext Shorter string.
- * @param {number} i Start index of quarter length mb_substring within longtext
- * @return {Array.<string>?} Five element Array, containing the prefix of
- * longtext, the suffix of longtext, the prefix of shorttext, the suffix
- * of shorttext and the common middle. Or null if there was no match.
- * @private
- */
- function diff_halfMatchI($longtext, $shorttext, $i) {
- // Start with a 1/4 length mb_substring at position i as a seed.
- $seed = mb_substr($longtext, $i, floor(mb_strlen($longtext) / 4));
-
- $j = -1;
- $best_common = '';
- $best_longtext_a = null;
- $best_longtext_b = null;
- $best_shorttext_a = null;
- $best_shorttext_b = null;
- while ( ($j = mb_strpos($shorttext, $seed, $j + 1)) !== false ) {
- $prefixLength = $this->diff_commonPrefix(mb_substr($longtext, $i), mb_substr($shorttext, $j));
- $suffixLength = $this->diff_commonSuffix(mb_substr($longtext, 0, $i), mb_substr($shorttext, 0, $j));
- if (mb_strlen($best_common) < $suffixLength + $prefixLength) {
- $best_common = mb_substr($shorttext, $j - $suffixLength, $suffixLength) . mb_substr($shorttext, $j, $prefixLength);
- $best_longtext_a = mb_substr($longtext, 0, $i - $suffixLength);
- $best_longtext_b = mb_substr($longtext, $i + $prefixLength);
- $best_shorttext_a = mb_substr($shorttext, 0, $j - $suffixLength);
- $best_shorttext_b = mb_substr($shorttext, $j + $prefixLength);
- }
- }
- if (mb_strlen($best_common) >= mb_strlen($longtext) / 2) {
- return array (
- $best_longtext_a,
- $best_longtext_b,
- $best_shorttext_a,
- $best_shorttext_b,
- $best_common
- );
- } else {
- return null;
- }
- }
-
- /**
- * Reduce the number of edits by eliminating semantically trivial equalities.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- */
- function diff_cleanupSemantic(&$diffs) {
- $changes = false;
- $equalities = array (); // Stack of indices where equalities are found.
- $equalitiesLength = 0; // Keeping our own length var is faster in JS.
- $lastequality = null; // Always equal to equalities[equalitiesLength-1][1]
- $pointer = 0; // Index of current position.
- // Number of characters that changed prior to the equality.
- $length_changes1 = 0;
- // Number of characters that changed after the equality.
- $length_changes2 = 0;
- while ($pointer < count($diffs)) {
- if ($diffs[$pointer][0] == DIFF_EQUAL) { // equality found
- $equalities[$equalitiesLength++] = $pointer;
- $length_changes1 = $length_changes2;
- $length_changes2 = 0;
- $lastequality = $diffs[$pointer][1];
- } else { // an insertion or deletion
- $length_changes2 += mb_strlen($diffs[$pointer][1]);
- if ($lastequality !== null && (mb_strlen($lastequality) <= $length_changes1) && (mb_strlen($lastequality) <= $length_changes2)) {
- // Duplicate record
- $zzz_diffs = array_splice($diffs, $equalities[$equalitiesLength -1], 0, array(array (
- DIFF_DELETE,
- $lastequality
- )));
- // Change second copy to insert.
- $diffs[$equalities[$equalitiesLength -1] + 1][0] = DIFF_INSERT;
- // Throw away the equality we just deleted.
- $equalitiesLength--;
- // Throw away the previous equality (it needs to be reevaluated).
- $equalitiesLength--;
- $pointer = $equalitiesLength > 0 ? $equalities[$equalitiesLength -1] : -1;
- $length_changes1 = 0; // Reset the counters.
- $length_changes2 = 0;
- $lastequality = null;
- $changes = true;
- }
- }
- $pointer++;
- }
- if ($changes) {
- $this->diff_cleanupMerge($diffs);
- }
- $this->diff_cleanupSemanticLossless($diffs);
- }
-
- /**
- * Look for single edits surrounded on both sides by equalities
- * which can be shifted sideways to align the edit to a word boundary.
- * e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- */
- function diff_cleanupSemanticLossless(&$diffs) {
-
- $pointer = 1;
- // Intentionally ignore the first and last element (don't need checking).
- while ($pointer < count($diffs) - 1) {
- if ($diffs[$pointer -1][0] == DIFF_EQUAL && $diffs[$pointer +1][0] == DIFF_EQUAL) {
- // This is a single edit surrounded by equalities.
- $equality1 = $diffs[$pointer -1][1];
- $edit = $diffs[$pointer][1];
- $equality2 = $diffs[$pointer +1][1];
-
- // First, shift the edit as far left as possible.
- $commonOffset = $this->diff_commonSuffix($equality1, $edit);
- if ($commonOffset !== '') {
- $commonString = mb_substr($edit, mb_strlen($edit) - $commonOffset);
- $equality1 = mb_substr($equality1, 0, mb_strlen($equality1) - $commonOffset);
- $edit = $commonString . mb_substr($edit, 0, mb_strlen($edit) - $commonOffset);
- $equality2 = $commonString . $equality2;
- }
-
- // Second, step character by character right, looking for the best fit.
- $bestEquality1 = $equality1;
- $bestEdit = $edit;
- $bestEquality2 = $equality2;
- $bestScore = $this->diff_cleanupSemanticScore($equality1, $edit) + $this->diff_cleanupSemanticScore($edit, $equality2);
- while (isset($equality2[0]) && $edit[0] === $equality2[0]) {
- $equality1 .= $edit[0];
- $edit = mb_substr($edit, 1) . $equality2[0];
- $equality2 = mb_substr($equality2, 1);
- $score = $this->diff_cleanupSemanticScore($equality1, $edit) + $this->diff_cleanupSemanticScore($edit, $equality2);
- // The >= encourages trailing rather than leading whitespace on edits.
- if ($score >= $bestScore) {
- $bestScore = $score;
- $bestEquality1 = $equality1;
- $bestEdit = $edit;
- $bestEquality2 = $equality2;
- }
- }
-
- if ($diffs[$pointer -1][1] != $bestEquality1) {
- // We have an improvement, save it back to the diff.
- if ($bestEquality1) {
- $diffs[$pointer -1][1] = $bestEquality1;
- } else {
- $zzz_diffs = array_splice($diffs, $pointer -1, 1);
- $pointer--;
- }
- $diffs[$pointer][1] = $bestEdit;
- if ($bestEquality2) {
- $diffs[$pointer +1][1] = $bestEquality2;
- } else {
- $zzz_diffs = array_splice($diffs, $pointer +1, 1);
- $pointer--;
- }
- }
- }
- $pointer++;
- }
- }
-
- /**
- * Given two strings, compute a score representing whether the internal
- * boundary falls on logical boundaries.
- * Scores range from 5 (best) to 0 (worst).
- * Closure, makes reference to regex patterns defined above.
- * @param {string} one First string
- * @param {string} two Second string
- * @return {number} The score.
- */
- function diff_cleanupSemanticScore($one, $two) {
- // Define some regex patterns for matching boundaries.
- $punctuation = '/[^a-zA-Z0-9]/';
- $whitespace = '/\s/';
- $linebreak = '/[\r\n]/';
- $blanklineEnd = '/\n\r?\n$/';
- $blanklineStart = '/^\r?\n\r?\n/';
-
- if (!$one || !$two) {
- // Edges are the best.
- return 5;
- }
-
- // Each port of this function behaves slightly differently due to
- // subtle differences in each language's definition of things like
- // 'whitespace'. Since this function's purpose is largely cosmetic,
- // the choice has been made to use each language's native features
- // rather than force total conformity.
- $score = 0;
- // One point for non-alphanumeric.
- if (preg_match($punctuation, $one[mb_strlen($one) - 1]) || preg_match($punctuation, $two[0])) {
- $score++;
- // Two points for whitespace.
- if (preg_match($whitespace, $one[mb_strlen($one) - 1] ) || preg_match($whitespace, $two[0])) {
- $score++;
- // Three points for line breaks.
- if (preg_match($linebreak, $one[mb_strlen($one) - 1]) || preg_match($linebreak, $two[0])) {
- $score++;
- // Four points for blank lines.
- if (preg_match($blanklineEnd, $one) || preg_match($blanklineStart, $two)) {
- $score++;
- }
- }
- }
- }
- return $score;
- }
-
- /**
- * Reduce the number of edits by eliminating operationally trivial equalities.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- */
- function diff_cleanupEfficiency(&$diffs) {
- $changes = false;
- $equalities = array (); // Stack of indices where equalities are found.
- $equalitiesLength = 0; // Keeping our own length var is faster in JS.
- $lastequality = ''; // Always equal to equalities[equalitiesLength-1][1]
- $pointer = 0; // Index of current position.
- // Is there an insertion operation before the last equality.
- $pre_ins = false;
- // Is there a deletion operation before the last equality.
- $pre_del = false;
- // Is there an insertion operation after the last equality.
- $post_ins = false;
- // Is there a deletion operation after the last equality.
- $post_del = false;
- while ($pointer < count($diffs)) {
- if ($diffs[$pointer][0] == DIFF_EQUAL) { // equality found
- if (mb_strlen($diffs[$pointer][1]) < $this->Diff_EditCost && ($post_ins || $post_del)) {
- // Candidate found.
- $equalities[$equalitiesLength++] = $pointer;
- $pre_ins = $post_ins;
- $pre_del = $post_del;
- $lastequality = $diffs[$pointer][1];
- } else {
- // Not a candidate, and can never become one.
- $equalitiesLength = 0;
- $lastequality = '';
- }
- $post_ins = $post_del = false;
- } else { // an insertion or deletion
- if ($diffs[$pointer][0] == DIFF_DELETE) {
- $post_del = true;
- } else {
- $post_ins = true;
- }
- /*
- * Five types to be split:
- * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
- * <ins>A</ins>X<ins>C</ins><del>D</del>
- * <ins>A</ins><del>B</del>X<ins>C</ins>
- * <ins>A</del>X<ins>C</ins><del>D</del>
- * <ins>A</ins><del>B</del>X<del>C</del>
- */
- if ($lastequality && (($pre_ins && $pre_del && $post_ins && $post_del) || ((mb_strlen($lastequality) < $this->Diff_EditCost / 2) && ($pre_ins + $pre_del + $post_ins + $post_del) == 3))) {
- // Duplicate record
- $zzz_diffs = array_splice($diffs, $equalities[$equalitiesLength -1], 0, array(array (
- DIFF_DELETE,
- $lastequality
- )));
- // Change second copy to insert.
- $diffs[$equalities[$equalitiesLength -1] + 1][0] = DIFF_INSERT;
- $equalitiesLength--; // Throw away the equality we just deleted;
- $lastequality = '';
- if ($pre_ins && $pre_del) {
- // No changes made which could affect previous entry, keep going.
- $post_ins = $post_del = true;
- $equalitiesLength = 0;
- } else {
- $equalitiesLength--; // Throw away the previous equality;
- $pointer = $equalitiesLength > 0 ? $equalities[$equalitiesLength -1] : -1;
- $post_ins = $post_del = false;
- }
- $changes = true;
- }
- }
- $pointer++;
- }
-
- if ($changes) {
- $this->diff_cleanupMerge($diffs);
- }
- }
-
- /**
- * Reorder and merge like edit sections. Merge equalities.
- * Any edit section can move as long as it doesn't cross an equality.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- */
- function diff_cleanupMerge(&$diffs) {
- array_push($diffs, array ( DIFF_EQUAL, '' )); // Add a dummy entry at the end.
- $pointer = 0;
- $count_delete = 0;
- $count_insert = 0;
- $text_delete = '';
- $text_insert = '';
- $commonlength = null;
- while ($pointer < count($diffs)) {
- switch ($diffs[$pointer][0]) {
- case DIFF_INSERT :
- $count_insert++;
- $text_insert .= $diffs[$pointer][1];
- $pointer++;
- break;
- case DIFF_DELETE :
- $count_delete++;
- $text_delete .= $diffs[$pointer][1];
- $pointer++;
- break;
- case DIFF_EQUAL :
- // Upon reaching an equality, check for prior redundancies.
- if ($count_delete !== 0 || $count_insert !== 0) {
- if ($count_delete !== 0 && $count_insert !== 0) {
- // Factor out any common prefixies.
- $commonlength = $this->diff_commonPrefix($text_insert, $text_delete);
- if ($commonlength !== 0) {
- if (($pointer - $count_delete - $count_insert) > 0 && $diffs[$pointer - $count_delete - $count_insert -1][0] == DIFF_EQUAL) {
- $diffs[$pointer - $count_delete - $count_insert -1][1] .= mb_substr($text_insert, 0, $commonlength);
- } else {
- array_splice($diffs, 0, 0, array(array (
- DIFF_EQUAL,
- mb_substr($text_insert, 0, $commonlength)
- )));
- $pointer++;
- }
- $text_insert = mb_substr($text_insert, $commonlength);
- $text_delete = mb_substr($text_delete, $commonlength);
- }
- // Factor out any common suffixies.
- $commonlength = $this->diff_commonSuffix($text_insert, $text_delete);
- if ($commonlength !== 0) {
- $diffs[$pointer][1] = mb_substr($text_insert, mb_strlen($text_insert) - $commonlength) . $diffs[$pointer][1];
- $text_insert = mb_substr($text_insert, 0, mb_strlen($text_insert) - $commonlength);
- $text_delete = mb_substr($text_delete, 0, mb_strlen($text_delete) - $commonlength);
- }
- }
- // Delete the offending records and add the merged ones.
- if ($count_delete === 0) {
- array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array(
- DIFF_INSERT,
- $text_insert
- )));
- } elseif ($count_insert === 0) {
- array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array(
- DIFF_DELETE,
- $text_delete
- )));
- } else {
- array_splice($diffs, $pointer-$count_delete-$count_insert, $count_delete+$count_insert, array(array(
- DIFF_DELETE,
- $text_delete
- ), array (
- DIFF_INSERT,
- $text_insert
- )));
- }
- $pointer = $pointer - $count_delete - $count_insert + ($count_delete ? 1 : 0) + ($count_insert ? 1 : 0) + 1;
- } elseif ($pointer !== 0 && $diffs[$pointer -1][0] == DIFF_EQUAL) {
- // Merge this equality with the previous one.
- $diffs[$pointer -1][1] .= $diffs[$pointer][1];
- array_splice($diffs, $pointer, 1);
- } else {
- $pointer++;
- }
- $count_insert = 0;
- $count_delete = 0;
- $text_delete = '';
- $text_insert = '';
- break;
- }
- }
- if ($diffs[count($diffs) - 1][1] === '') {
- array_pop($diffs); // Remove the dummy entry at the end.
- }
-
- // Second pass: look for single edits surrounded on both sides by equalities
- // which can be shifted sideways to eliminate an equality.
- // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
- $changes = false;
- $pointer = 1;
- // Intentionally ignore the first and last element (don't need checking).
- while ($pointer < count($diffs) - 1) {
- if ($diffs[$pointer-1][0] == DIFF_EQUAL && $diffs[$pointer+1][0] == DIFF_EQUAL) {
- // This is a single edit surrounded by equalities.
- if ( mb_substr($diffs[$pointer][1], mb_strlen($diffs[$pointer][1]) - mb_strlen($diffs[$pointer -1][1])) == $diffs[$pointer -1][1]) {
- // Shift the edit over the previous equality.
- $diffs[$pointer][1] = $diffs[$pointer -1][1] . mb_substr($diffs[$pointer][1], 0, mb_strlen($diffs[$pointer][1]) - mb_strlen($diffs[$pointer -1][1]));
- $diffs[$pointer +1][1] = $diffs[$pointer -1][1] . $diffs[$pointer +1][1];
- array_splice($diffs, $pointer -1, 1);
- $changes = true;
- } elseif (mb_substr($diffs[$pointer][1], 0, mb_strlen($diffs[$pointer +1][1])) == $diffs[$pointer +1][1]) {
- // Shift the edit over the next equality.
- $diffs[$pointer -1][1] .= $diffs[$pointer +1][1];
-
- $diffs[$pointer][1] = mb_substr($diffs[$pointer][1], mb_strlen($diffs[$pointer +1][1])) . $diffs[$pointer +1][1];
- array_splice($diffs, $pointer +1, 1);
- $changes = true;
- }
- }
- $pointer++;
- }
- // If shifts were made, the diff needs reordering and another shift sweep.
- if ($changes) {
- $this->diff_cleanupMerge($diffs);
- }
- }
-
- /**
- * loc is a location in text1, compute and return the equivalent location in
- * text2.
- * e.g. 'The cat' vs 'The big cat', 1->1, 5->8
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @param {number} loc Location within text1.
- * @return {number} Location within text2.
- */
- function diff_xIndex($diffs, $loc) {
- $chars1 = 0;
- $chars2 = 0;
- $last_chars1 = 0;
- $last_chars2 = 0;
- for ($x = 0; $x < count($diffs); $x++) {
- if ($diffs[$x][0] !== DIFF_INSERT) { // Equality or deletion.
- $chars1 += mb_strlen($diffs[$x][1]);
- }
- if ($diffs[$x][0] !== DIFF_DELETE) { // Equality or insertion.
- $chars2 += mb_strlen($diffs[$x][1]);
- }
- if ($chars1 > $loc) { // Overshot the location.
- break;
- }
- $last_chars1 = $chars1;
- $last_chars2 = $chars2;
- }
- // Was the location was deleted?
- if (count($diffs) != $x && $diffs[$x][0] === DIFF_DELETE) {
- return $last_chars2;
- }
- // Add the remaining character length.
- return $last_chars2 + ($loc - $last_chars1);
- }
-
- /**
- * Convert a diff array into a pretty HTML report.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @return {string} HTML representation.
- */
- function diff_prettyHtml($diffs) {
- $html = array ();
- $i = 0;
- for ($x = 0; $x < count($diffs); $x++) {
- $op = $diffs[$x][0]; // Operation (insert, delete, equal)
- $data = $diffs[$x][1]; // Text of change.
- $text = preg_replace(array (
- '/&/',
- '/</',
- '/>/',
- "/\n/"
- ), array (
- '&amp;',
- '&lt;',
- '&gt;',
- '&para;<BR>'
- ), $data);
-
- switch ($op) {
- case DIFF_INSERT :
- $html[$x] = '<INS STYLE="background:#E6FFE6;" TITLE="i=' . $i . '">' . $text . '</INS>';
- break;
- case DIFF_DELETE :
- $html[$x] = '<DEL STYLE="background:#FFE6E6;" TITLE="i=' . $i . '">' . $text . '</DEL>';
- break;
- case DIFF_EQUAL :
- $html[$x] = '<SPAN TITLE="i=' . $i . '">' . $text . '</SPAN>';
- break;
- }
- if ($op !== DIFF_DELETE) {
- $i += mb_strlen($data);
- }
- }
- return implode('',$html);
- }
-
- /**
- * Compute and return the source text (all equalities and deletions).
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @return {string} Source text.
- */
- function diff_text1($diffs) {
- $text = array ();
- for ($x = 0; $x < count($diffs); $x++) {
- if ($diffs[$x][0] !== DIFF_INSERT) {
- $text[$x] = $diffs[$x][1];
- }
- }
- return implode('',$text);
- }
-
- /**
- * Compute and return the destination text (all equalities and insertions).
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @return {string} Destination text.
- */
- function diff_text2($diffs) {
- $text = array ();
- for ($x = 0; $x < count($diffs); $x++) {
- if ($diffs[$x][0] !== DIFF_DELETE) {
- $text[$x] = $diffs[$x][1];
- }
- }
- return implode('',$text);
- }
-
- /**
- * Compute the Levenshtein distance; the number of inserted, deleted or
- * substituted characters.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @return {number} Number of changes.
- */
- function diff_levenshtein($diffs) {
- $levenshtein = 0;
- $insertions = 0;
- $deletions = 0;
- for ($x = 0; $x < count($diffs); $x++) {
- $op = $diffs[$x][0];
- $data = $diffs[$x][1];
- switch ($op) {
- case DIFF_INSERT :
- $insertions += mb_strlen($data);
- break;
- case DIFF_DELETE :
- $deletions += mb_strlen($data);
- break;
- case DIFF_EQUAL :
- // A deletion and an insertion is one substitution.
- $levenshtein += max($insertions, $deletions);
- $insertions = 0;
- $deletions = 0;
- break;
- }
- }
- $levenshtein += max($insertions, $deletions);
- return $levenshtein;
- }
-
- /**
- * Crush the diff into an encoded string which describes the operations
- * required to transform text1 into text2.
- * E.g. =3\t-2\t+ing -> Keep 3 chars, delete 2 chars, insert 'ing'.
- * Operations are tab-separated. Inserted text is escaped using %xx notation.
- * @param {Array.<Array.<number|string>>} diffs Array of diff tuples.
- * @return {string} Delta text.
- */
- function diff_toDelta($diffs) {
- $text = array ();
- for ($x = 0; $x < count($diffs); $x++) {
- switch ($diffs[$x][0]) {
- case DIFF_INSERT :
- $text[$x] = '+' .encodeURI($diffs[$x][1]);
- break;
- case DIFF_DELETE :
- $text[$x] = '-' .mb_strlen($diffs[$x][1]);
- break;
- case DIFF_EQUAL :
- $text[$x] = '=' .mb_strlen($diffs[$x][1]);
- break;
- }
- }
- return str_replace('%20', ' ', implode("\t", $text));
- }
-
- /**
- * Given the original text1, and an encoded string which describes the
- * operations required to transform text1 into text2, compute the full diff.
- * @param {string} text1 Source string for the diff.
- * @param {string} delta Delta text.
- * @return {Array.<Array.<number|string>>} Array of diff tuples.
- * @throws {Error} If invalid input.
- */
- function diff_fromDelta($text1, $delta) {
- $diffs = array ();
- $diffsLength = 0; // Keeping our own length var is faster in JS.
- $pointer = 0; // Cursor in text1
- $tokens = preg_split("/\t/", $delta);
-
- for ($x = 0; $x < count($tokens); $x++) {
- // Each token begins with a one character parameter which specifies the
- // operation of this token (delete, insert, equality).
- $param = mb_substr($tokens[$x], 1);
- switch ($tokens[$x][0]) {
- case '+' :
- try {
- $diffs[$diffsLength++] = array (
- DIFF_INSERT,
- decodeURI($param)
- );
- } catch (Exception $ex) {
- echo_Exception('Illegal escape in diff_fromDelta: ' . $param);
- // Malformed URI sequence.
- }
- break;
- case '-' :
- // Fall through.
- case '=' :
- $n = (int) $param;
- if ($n < 0) {
- echo_Exception('Invalid number in diff_fromDelta: ' . $param);
- }
- $text = mb_substr($text1, $pointer, $n);
- $pointer += $n;
- if ($tokens[$x][0] == '=') {
- $diffs[$diffsLength++] = array (
- DIFF_EQUAL,
- $text
- );
- } else {
- $diffs[$diffsLength++] = array (
- DIFF_DELETE,
- $text
- );
- }
- break;
- default :
- // Blank tokens are ok (from a trailing \t).
- // Anything else is an error.
- if ($tokens[$x]) {
- echo_Exception('Invalid diff operation in diff_fromDelta: ' . $tokens[$x]);
- }
- }
- }
- if ($pointer != mb_strlen($text1)) {
-// throw new Exception('Delta length (' . $pointer . ') does not equal source text length (' . mb_strlen($text1) . ').');
- echo_Exception('Delta length (' . $pointer . ') does not equal source text length (' . mb_strlen($text1) . ').');
- }
- return $diffs;
- }
-
- // MATCH FUNCTIONS
-
- /**
- * Locate the best instance of 'pattern' in 'text' near 'loc'.
- * @param {string} text The text to search.
- * @param {string} pattern The pattern to search for.
- * @param {number} loc The location to search around.
- * @return {number} Best match index or -1.
- */
- function match_main($text, $pattern, $loc) {
- $loc = max(0, min($loc, mb_strlen($text)));
- if ($text == $pattern) {
- // Shortcut (potentially not guaranteed by the algorithm)
- return 0;
- }
- elseif (!mb_strlen($text)) {
- // Nothing to match.
- return -1;
- }
- elseif (mb_substr($text, $loc, mb_strlen($pattern)) == $pattern) {
- // Perfect match at the perfect spot! (Includes case of null pattern)
- return $loc;
- } else {
- // Do a fuzzy compare.
- return $this->match_bitap($text, $pattern, $loc);
- }
- }
-
- /**
- * Locate the best instance of 'pattern' in 'text' near 'loc' using the
- * Bitap algorithm.
- * @param {string} text The text to search.
- * @param {string} pattern The pattern to search for.
- * @param {number} loc The location to search around.
- * @return {number} Best match index or -1.
- * @private
- */
- function match_bitap($text, $pattern, $loc) {
- if (mb_strlen($pattern) > Match_MaxBits) {
- echo_Exception('Pattern too long for this browser.');
- }
-
- // Initialise the alphabet.
- $s = $this->match_alphabet($pattern);
-
- // Highest score beyond which we give up.
- $score_threshold = $this->Match_Threshold;
-
- // Is there a nearby exact match? (speedup)
- $best_loc = mb_strpos($text, $pattern, $loc);
- if ($best_loc !== false) {
- $score_threshold = min($this->match_bitapScore(0, $best_loc, $pattern, $loc), $score_threshold);
- }
-
- // What about in the other direction? (speedup)
- $best_loc = mb_strrpos( $text, $pattern, min($loc + mb_strlen($pattern), mb_strlen($text)) );
- if ($best_loc !== false) {
- $score_threshold = min($this->match_bitapScore(0, $best_loc, $pattern, $loc), $score_threshold);
- }
-
- // Initialise the bit arrays.
- $matchmask = 1 << (mb_strlen($pattern) - 1);
- $best_loc = -1;
-
- $bin_min = null;
- $bin_mid = null;
- $bin_max = mb_strlen($pattern) + mb_strlen($text);
- $last_rd = null;
- for ($d = 0; $d < mb_strlen($pattern); $d++) {
- // Scan for the best match; each iteration allows for one more error.
- // Run a binary search to determine how far from 'loc' we can stray at this
- // error level.
- $bin_min = 0;
- $bin_mid = $bin_max;
- while ($bin_min < $bin_mid) {
- if ($this->match_bitapScore($d, $loc + $bin_mid, $pattern, $loc) <= $score_threshold) {
- $bin_min = $bin_mid;
- } else {
- $bin_max = $bin_mid;
- }
- $bin_mid = floor(($bin_max - $bin_min) / 2 + $bin_min);
- }
- // Use the result from this iteration as the maximum for the next.
- $bin_max = $bin_mid;
- $start = max(1, $loc - $bin_mid +1);
- $finish = min($loc + $bin_mid, mb_strlen($text)) + mb_strlen($pattern);
-
- $rd = Array (
- $finish +2
- );
- $rd[$finish +1] = (1 << $d) - 1;
- for ($j = $finish; $j >= $start; $j--) {
- // The alphabet (s) is a sparse hash, so the following line generates
- // warnings.
-@ $charMatch = $s[ $text[$j -1] ];
- if ($d === 0) { // First pass: exact match.
- $rd[$j] = (($rd[$j +1] << 1) | 1) & $charMatch;
- } else { // Subsequent passes: fuzzy match.
- $rd[$j] = (($rd[$j +1] << 1) | 1) & $charMatch | ((($last_rd[$j +1] | $last_rd[$j]) << 1) | 1) | $last_rd[$j +1];
- }
- if ($rd[$j] & $matchmask) {
- $score = $this->match_bitapScore($d, $j -1, $pattern, $loc);
- // This match will almost certainly be better than any existing match.
- // But check anyway.
- if ($score <= $score_threshold) {
- // Told you so.
- $score_threshold = $score;
- $best_loc = $j -1;
- if ($best_loc > $loc) {
- // When passing loc, don't exceed our current distance from loc.
- $start = max(1, 2 * $loc - $best_loc);
- } else {
- // Already passed loc, downhill from here on in.
- break;
- }
- }
- }
- }
- // No hope for a (better) match at greater error levels.
- if ($this->match_bitapScore($d +1, $loc, $pattern, $loc) > $score_threshold) {
- break;
- }
- $last_rd = $rd;
- }
- return (int)$best_loc;
- }
-
- /**
- * Compute and return the score for a match with e errors and x location.
- * Accesses loc and pattern through being a closure.
- * @param {number} e Number of errors in match.
- * @param {number} x Location of match.
- * @return {number} Overall score for match (0.0 = good, 1.0 = bad).
- * @private
- */
- function match_bitapScore($e, $x, $pattern, $loc) {
- $accuracy = $e / mb_strlen($pattern);
- $proximity = abs($loc - $x);
- if (!$this->Match_Distance) {
- // Dodge divide by zero error.
- return $proximity ? 1.0 : $accuracy;
- }
- return $accuracy + ($proximity / $this->Match_Distance);
- }
-
- /**
- * Initialise the alphabet for the Bitap algorithm.
- * @param {string} pattern The text to encode.
- * @return {Object} Hash of character locations.
- * @private
- */
- function match_alphabet($pattern) {
- $s = array ();
- for ($i = 0; $i < mb_strlen($pattern); $i++) {
- $s[ $pattern[$i] ] = 0;
- }
- for ($i = 0; $i < mb_strlen($pattern); $i++) {
- $s[ $pattern[$i] ] |= 1 << (mb_strlen($pattern) - $i - 1);
- }
- return $s;
- }
-
- // PATCH FUNCTIONS
-
- /**
- * Increase the context until it is unique,
- * but don't let the pattern expand beyond Match_MaxBits.
- * @param {patch_obj} patch The patch to grow.
- * @param {string} text Source text.
- * @private
- */
- function patch_addContext($patch, $text) {
- $pattern = mb_substr($text, $patch->start2, $patch->length1 );
- $previousPattern = null;
- $padding = 0;
- $i = 0;
- while (
- ( mb_strlen($pattern) === 0 // Javascript's indexOf/lastIndexOd return 0/strlen respectively if pattern = ''
- || mb_strpos($text, $pattern) !== mb_strrpos($text, $pattern)
- )
- && $pattern !== $previousPattern // avoid infinte loop
- && mb_strlen($pattern) < Match_MaxBits - $this->Patch_Margin - $this->Patch_Margin ) {
- $padding += $this->Patch_Margin;
- $previousPattern = $pattern;
- $pattern = mb_substr($text, max($patch->start2 - $padding,0), ($patch->start2 + $patch->length1 + $padding) - max($patch->start2 - $padding,0) );
- }
- // Add one chunk for good luck.
- $padding += $this->Patch_Margin;
- // Add the prefix.
- $prefix = mb_substr($text, max($patch->start2 - $padding,0), $patch->start2 - max($patch->start2 - $padding,0) );
- if ($prefix!=='') {
- array_unshift($patch->diffs, array (
- DIFF_EQUAL,
- $prefix
- ));
- }
- // Add the suffix.
- $suffix = mb_substr($text, $patch->start2 + $patch->length1, ($patch->start2 + $patch->length1 + $padding) - ($patch->start2 + $patch->length1) );
- if ($suffix!=='') {
- array_push($patch->diffs, array (
- DIFF_EQUAL,
- $suffix
- ));
- }
-
- // Roll back the start points.
- $patch->start1 -= mb_strlen($prefix);
- $patch->start2 -= mb_strlen($prefix);
- // Extend the lengths.
- $patch->length1 += mb_strlen($prefix) + mb_strlen($suffix);
- $patch->length2 += mb_strlen($prefix) + mb_strlen($suffix);
- }
-
- /**
- * Compute a list of patches to turn text1 into text2.
- * Use diffs if provided, otherwise compute it ourselves.
- * There are four ways to call this function, depending on what data is
- * available to the caller:
- * Method 1:
- * a = text1, b = text2
- * Method 2:
- * a = diffs
- * Method 3 (optimal):
- * a = text1, b = diffs
- * Method 4 (deprecated, use method 3):
- * a = text1, b = text2, c = diffs
- *
- * @param {string|Array.<Array.<number|string>>} a text1 (methods 1,3,4) or
- * Array of diff tuples for text1 to text2 (method 2).
- * @param {string|Array.<Array.<number|string>>} opt_b text2 (methods 1,4) or
- * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2).
- * @param {string|Array.<Array.<number|string>>} opt_c Array of diff tuples for
- * text1 to text2 (method 4) or undefined (methods 1,2,3).
- * @return {Array.<patch_obj>} Array of patch objects.
- */
- function patch_make($a, $opt_b = null, $opt_c = null ) {
- if (is_string($a) && is_string($opt_b) && $opt_c === null ) {
- // Method 1: text1, text2
- // Compute diffs from text1 and text2.
- $text1 = $a;
- $diffs = $this->diff_main($text1, $opt_b, true);
- if ( count($diffs) > 2) {
- $this->diff_cleanupSemantic($diffs);
- $this->diff_cleanupEfficiency($diffs);
- }
- } elseif ( is_array($a) && $opt_b === null && $opt_c === null) {
- // Method 2: diffs
- // Compute text1 from diffs.
- $diffs = $a;
- $text1 = $this->diff_text1($diffs);
- } elseif ( is_string($a) && is_array($opt_b) && $opt_c === null) {
- // Method 3: text1, diffs
- $text1 = $a;
- $diffs = $opt_b;
- } elseif ( is_string($a) && is_string($opt_b) && is_array($opt_c) ) {
- // Method 4: text1, text2, diffs
- // text2 is not used.
- $text1 = $a;
- $diffs = $opt_c;
- } else {
- echo_Exception('Unknown call format to patch_make.');
- }
-
- if ( count($diffs) === 0) {
- return array(); // Get rid of the null case.
- }
- $patches = array();
- $patch = new patch_obj();
- $patchDiffLength = 0; // Keeping our own length var is faster in JS.
- $char_count1 = 0; // Number of characters into the text1 string.
- $char_count2 = 0; // Number of characters into the text2 string.
- // Start with text1 (prepatch_text) and apply the diffs until we arrive at
- // text2 (postpatch_text). We recreate the patches one by one to determine
- // context info.
- $prepatch_text = $text1;
- $postpatch_text = $text1;
- for ($x = 0; $x < count($diffs); $x++) {
- $diff_type = $diffs[$x][0];
- $diff_text = $diffs[$x][1];
-
- if (!$patchDiffLength && $diff_type !== DIFF_EQUAL) {
- // A new patch starts here.
- $patch->start1 = $char_count1;
- $patch->start2 = $char_count2;
- }
-
- switch ($diff_type) {
- case DIFF_INSERT :
- $patch->diffs[$patchDiffLength++] = $diffs[$x];
- $patch->length2 += mb_strlen($diff_text);
- $postpatch_text = mb_substr($postpatch_text, 0, $char_count2) . $diff_text . mb_substr($postpatch_text,$char_count2);
- break;
- case DIFF_DELETE :
- $patch->length1 += mb_strlen($diff_text);
- $patch->diffs[$patchDiffLength++] = $diffs[$x];
- $postpatch_text = mb_substr($postpatch_text, 0, $char_count2) . mb_substr($postpatch_text, $char_count2 + mb_strlen($diff_text) );
- break;
- case DIFF_EQUAL :
- if ( mb_strlen($diff_text) <= 2 * $this->Patch_Margin && $patchDiffLength && count($diffs) != $x + 1) {
- // Small equality inside a patch.
- $patch->diffs[$patchDiffLength++] = $diffs[$x];
- $patch->length1 += mb_strlen($diff_text);
- $patch->length2 += mb_strlen($diff_text);
- } elseif ( mb_strlen($diff_text) >= 2 * $this->Patch_Margin ) {
- // Time for a new patch.
- if ($patchDiffLength) {
- $this->patch_addContext($patch, $prepatch_text);
- array_push($patches,$patch);
- $patch = new patch_obj();
- $patchDiffLength = 0;
- // Unlike Unidiff, our patch lists have a rolling context.
- // http://code.google.com/p/google-diff-match-patch/wiki/Unidiff
- // Update prepatch text & pos to reflect the application of the
- // just completed patch.
- $prepatch_text = $postpatch_text;
- $char_count1 = $char_count2;
- }
- }
- break;
- }
-
- // Update the current character count.
- if ($diff_type !== DIFF_INSERT) {
- $char_count1 += mb_strlen($diff_text);
- }
- if ($diff_type !== DIFF_DELETE) {
- $char_count2 += mb_strlen($diff_text);
- }
- }
- // Pick up the leftover patch if not empty.
- if ($patchDiffLength) {
- $this->patch_addContext($patch, $prepatch_text);
- array_push($patches, $patch);
- }
-
- return $patches;
- }
-
- /**
- * Given an array of patches, return another array that is identical.
- * @param {Array.<patch_obj>} patches Array of patch objects.
- * @return {Array.<patch_obj>} Array of patch objects.
- */
- function patch_deepCopy($patches) {
- // Making deep copies is hard in JavaScript.
- $patchesCopy = array();
- for ($x = 0; $x < count($patches); $x++) {
- $patch = $patches[$x];
- $patchCopy = new patch_obj();
- for ($y = 0; $y < count($patch->diffs); $y++) {
- $patchCopy->diffs[$y] = $patch->diffs[$y]; // ?? . slice();
- }
- $patchCopy->start1 = $patch->start1;
- $patchCopy->start2 = $patch->start2;
- $patchCopy->length1 = $patch->length1;
- $patchCopy->length2 = $patch->length2;
- $patchesCopy[$x] = $patchCopy;
- }
- return $patchesCopy;
- }
-
- /**
- * Merge a set of patches onto the text. Return a patched text, as well
- * as a list of true/false values indicating which patches were applied.
- * @param {Array.<patch_obj>} patches Array of patch objects.
- * @param {string} text Old text.
- * @return {Array.<string|Array.<boolean>>} Two element Array, containing the
- * new text and an array of boolean values.
- */
- function patch_apply($patches, $text) {
- if ( count($patches) == 0) {
- return array($text,array());
- }
-
- // Deep copy the patches so that no changes are made to originals.
- $patches = $this->patch_deepCopy($patches);
-
- $nullPadding = $this->patch_addPadding($patches);
- $text = $nullPadding . $text . $nullPadding;
-
- $this->patch_splitMax($patches);
- // delta keeps track of the offset between the expected and actual location
- // of the previous patch. If there are patches expected at positions 10 and
- // 20, but the first patch was found at 12, delta is 2 and the second patch
- // has an effective expected position of 22.
- $delta = 0;
- $results = array();
- for ($x = 0; $x < count($patches) ; $x++) {
- $expected_loc = $patches[$x]->start2 + $delta;
- $text1 = $this->diff_text1($patches[$x]->diffs);
- $start_loc = null;
- $end_loc = -1;
- if (mb_strlen($text1) > Match_MaxBits) {
- // patch_splitMax will only provide an oversized pattern in the case of
- // a monster delete.
- $start_loc = $this->match_main($text, mb_substr($text1, 0, Match_MaxBits ), $expected_loc);
- if ($start_loc != -1) {
- $end_loc = $this->match_main($text, mb_substr($text1,mb_strlen($text1) - Match_MaxBits), $expected_loc + mb_strlen($text1) - Match_MaxBits);
- if ($end_loc == -1 || $start_loc >= $end_loc) {
- // Can't find valid trailing context. Drop this patch.
- $start_loc = -1;
- }
- }
- } else {
- $start_loc = $this->match_main($text, $text1, $expected_loc);
- }
- if ($start_loc == -1) {
- // No match found. :(
- $results[$x] = false;
- // Subtract the delta for this failed patch from subsequent patches.
- $delta -= $patches[$x]->length2 - $patches[$x]->length1;
- } else {
- // Found a match. :)
- $results[$x] = true;
- $delta = $start_loc - $expected_loc;
- $text2 = null;
- if ($end_loc == -1) {
- $text2 = mb_substr($text, $start_loc, mb_strlen($text1) );
- } else {
- $text2 = mb_substr($text, $start_loc, $end_loc + Match_MaxBits - $start_loc);
- }
- if ($text1 == $text2) {
- // Perfect match, just shove the replacement text in.
- $text = mb_substr($text, 0, $start_loc) . $this->diff_text2($patches[$x]->diffs) . mb_substr($text,$start_loc + mb_strlen($text1) );
- } else {
- // Imperfect match. Run a diff to get a framework of equivalent
- // indices.
- $diffs = $this->diff_main($text1, $text2, false);
- if ( mb_strlen($text1) > Match_MaxBits && $this->diff_levenshtein($diffs) / mb_strlen($text1) > $this->Patch_DeleteThreshold) {
- // The end points match, but the content is unacceptably bad.
- $results[$x] = false;
- } else {
- $this->diff_cleanupSemanticLossless($diffs);
- $index1 = 0;
- $index2 = NULL;
- for ($y = 0; $y < count($patches[$x]->diffs); $y++) {
- $mod = $patches[$x]->diffs[$y];
- if ($mod[0] !== DIFF_EQUAL) {
- $index2 = $this->diff_xIndex($diffs, $index1);
- }
- if ($mod[0] === DIFF_INSERT) { // Insertion
- $text = mb_substr($text, 0, $start_loc + $index2) . $mod[1] . mb_substr($text, $start_loc + $index2);
- } elseif ($mod[0] === DIFF_DELETE) { // Deletion
- $text = mb_substr($text, 0, $start_loc + $index2) . mb_substr($text,$start_loc + $this->diff_xIndex($diffs, $index1 + mb_strlen($mod[1]) ));
- }
- if ($mod[0] !== DIFF_DELETE) {
- $index1 += mb_strlen($mod[1]);
- }
- }
- }
- }
- }
- }
- // Strip the padding off.
- $text = mb_substr($text, mb_strlen($nullPadding), mb_strlen($text) - 2*mb_strlen($nullPadding) );
- return array($text, $results);
- }
-
- /**
- * Add some padding on text start and end so that edges can match something.
- * Intended to be called only from within patch_apply.
- * @param {Array.<patch_obj>} patches Array of patch objects.
- * @return {string} The padding string added to each side.
- */
- function patch_addPadding(&$patches){
- $paddingLength = $this->Patch_Margin;
- $nullPadding = '';
- for ($x = 1; $x <= $paddingLength; $x++) {
- $nullPadding .= mb_chr($x);
- }
-
- // Bump all the patches forward.
- for ($x = 0; $x < count($patches); $x++) {
- $patches[$x]->start1 += $paddingLength;
- $patches[$x]->start2 += $paddingLength;
- }
-
- // Add some padding on start of first diff.
- $patch = &$patches[0];
- $diffs = &$patch->diffs;
- if (count($diffs) == 0 || $diffs[0][0] != DIFF_EQUAL) {
- // Add nullPadding equality.
- array_unshift($diffs, array(DIFF_EQUAL, $nullPadding));
- $patch->start1 -= $paddingLength; // Should be 0.
- $patch->start2 -= $paddingLength; // Should be 0.
- $patch->length1 += $paddingLength;
- $patch->length2 += $paddingLength;
- } elseif ($paddingLength > mb_strlen($diffs[0][1]) ) {
- // Grow first equality.
- $extraLength = $paddingLength - mb_strlen($diffs[0][1]);
- $diffs[0][1] = mb_substr( $nullPadding , mb_strlen($diffs[0][1]) ) . $diffs[0][1];
- $patch->start1 -= $extraLength;
- $patch->start2 -= $extraLength;
- $patch->length1 += $extraLength;
- $patch->length2 += $extraLength;
- }
-
- // Add some padding on end of last diff.
- $patch = &$patches[count($patches) - 1];
- $diffs = &$patch->diffs;
- if ( count($diffs) == 0 || $diffs[ count($diffs) - 1][0] != DIFF_EQUAL) {
- // Add nullPadding equality.
- array_push($diffs, array(DIFF_EQUAL, $nullPadding) );
- $patch->length1 += $paddingLength;
- $patch->length2 += $paddingLength;
- } elseif ($paddingLength > mb_strlen( $diffs[count($diffs)-1][1] ) ) {
- // Grow last equality.
- $extraLength = $paddingLength - mb_strlen( $diffs[count($diffs)-1][1] );
- $diffs[ count($diffs)-1][1] .= mb_substr($nullPadding,0,$extraLength);
- $patch->length1 += $extraLength;
- $patch->length2 += $extraLength;
- }
-
- return $nullPadding;
- }
-
- /**
- * Look through the patches and break up any which are longer than the maximum
- * limit of the match algorithm.
- * @param {Array.<patch_obj>} patches Array of patch objects.
- */
- function patch_splitMax(&$patches) {
- for ($x = 0; $x < count($patches); $x++) {
- if ( $patches[$x]->length1 > Match_MaxBits) {
- $bigpatch = $patches[$x];
- // Remove the big old patch.
- array_splice($patches,$x--,1);
- $patch_size = Match_MaxBits;
- $start1 = $bigpatch->start1;
- $start2 = $bigpatch->start2;
- $precontext = '';
- while ( count($bigpatch->diffs) !== 0) {
- // Create one of several smaller patches.
- $patch = new patch_obj();
- $empty = true;
- $patch->start1 = $start1 - mb_strlen($precontext);
- $patch->start2 = $start2 - mb_strlen($precontext);
- if ($precontext !== '') {
- $patch->length1 = $patch->length2 = mb_strlen($precontext);
- array_push($patch->diffs, array(DIFF_EQUAL, $precontext) );
- }
- while ( count($bigpatch->diffs) !== 0 && $patch->length1 < $patch_size - $this->Patch_Margin) {
- $diff_type = $bigpatch->diffs[0][0];
- $diff_text = $bigpatch->diffs[0][1];
- if ($diff_type === DIFF_INSERT) {
- // Insertions are harmless.
- $patch->length2 += mb_strlen($diff_text);
- $start2 += mb_strlen($diff_text);
- array_push($patch->diffs, array_shift($bigpatch->diffs) );
- $empty = false;
- } else
- if ($diff_type === DIFF_DELETE && count($patch->diffs) == 1 && $patch->diffs[0][0] == DIFF_EQUAL && (mb_strlen($diff_text) > 2 * $patch_size) ) {
- // This is a large deletion. Let it pass in one chunk.
- $patch->length1 += mb_strlen($diff_text);
- $start1 += mb_strlen($diff_text);
- $empty = false;
- array_push( $patch->diffs, array($diff_type, $diff_text) );
- array_shift($bigpatch->diffs);
- } else {
- // Deletion or equality. Only take as much as we can stomach.
- $diff_text = mb_substr($diff_text, 0, $patch_size - $patch->length1 - $this->Patch_Margin);
- $patch->length1 += mb_strlen($diff_text);
- $start1 += mb_strlen($diff_text);
- if ($diff_type === DIFF_EQUAL) {
- $patch->length2 += mb_strlen($diff_text);
- $start2 += mb_strlen($diff_text);
- } else {
- $empty = false;
- }
- array_push($patch->diffs, array($diff_type, $diff_text) );
- if ($diff_text == $bigpatch->diffs[0][1]) {
- array_shift($bigpatch->diffs);
- } else {
- $bigpatch->diffs[0][1] = mb_substr( $bigpatch->diffs[0][1],mb_strlen($diff_text) );
- }
- }
- }
- // Compute the head context for the next patch.
- $precontext = $this->diff_text2($patch->diffs);
- $precontext = mb_substr($precontext, mb_strlen($precontext)-$this->Patch_Margin);
- // Append the end context for this patch.
- $postcontext = mb_substr( $this->diff_text1($bigpatch->diffs), 0, $this->Patch_Margin );
- if ($postcontext !== '') {
- $patch->length1 += mb_strlen($postcontext);
- $patch->length2 += mb_strlen($postcontext);
- if ( count($patch->diffs) !== 0 && $patch->diffs[ count($patch->diffs) - 1][0] === DIFF_EQUAL) {
- $patch->diffs[ count($patch->diffs) - 1][1] .= $postcontext;
- } else {
- array_push($patch->diffs, array(DIFF_EQUAL, $postcontext));
- }
- }
- if (!$empty) {
- array_splice($patches, ++$x, 0, array($patch));
- }
- }
- }
- }
- }
-
- /**
- * Take a list of patches and return a textual representation.
- * @param {Array.<patch_obj>} patches Array of patch objects.
- * @return {string} Text representation of patches.
- */
- function patch_toText($patches) {
- $text = array();
- for ($x = 0; $x < count($patches) ; $x++) {
- $text[$x] = $patches[$x];
- }
- return implode('',$text);
- }
-
- /**
- * Parse a textual representation of patches and return a list of patch objects.
- * @param {string} textline Text representation of patches.
- * @return {Array.<patch_obj>} Array of patch objects.
- * @throws {Error} If invalid input.
- */
- function patch_fromText($textline) {
- $patches = array();
- if ($textline === '') {
- return $patches;
- }
- $text = explode("\n",$textline);
- foreach($text as $i=>$t){ if($t===''){ unset($text[$i]); } }
- $textPointer = 0;
- while ($textPointer < count($text) ) {
- $m = null;
- preg_match('/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/',$text[$textPointer],$m);
- if (!$m) {
- echo_Exception('Invalid patch string: ' . $text[$textPointer]);
- }
- $patch = new patch_obj();
- array_push($patches, $patch);
- @$patch->start1 = (int)$m[1];
- if (@$m[2] === '') {
- $patch->start1--;
- $patch->length1 = 1;
- } elseif ( @$m[2] == '0') {
- $patch->length1 = 0;
- } else {
- $patch->start1--;
- @$patch->length1 = (int)$m[2];
- }
-
- @$patch->start2 = (int)$m[3];
- if (@$m[4] === '') {
- $patch->start2--;
- $patch->length2 = 1;
- } elseif ( @$m[4] == '0') {
- $patch->length2 = 0;
- } else {
- $patch->start2--;
- @$patch->length2 = (int)$m[4];
- }
- $textPointer++;
-
- while ($textPointer < count($text) ) {
- $sign = $text[$textPointer][0];
- try {
- $line = decodeURI( mb_substr($text[$textPointer],1) );
- } catch (Exception $ex) {
- // Malformed URI sequence.
- throw new Exception('Illegal escape in patch_fromText: ' . $line);
- }
- if ($sign == '-') {
- // Deletion.
- array_push( $patch->diffs, array(DIFF_DELETE, $line) );
- } elseif ($sign == '+') {
- // Insertion.
- array_push($patch->diffs, array(DIFF_INSERT, $line) );
- } elseif ($sign == ' ') {
- // Minor equality.
- array_push($patch->diffs, array(DIFF_EQUAL, $line) );
- } elseif ($sign == '@') {
- // Start of next patch.
- break;
- } elseif ($sign === '') {
- // Blank line? Whatever.
- } else {
- // WTF?
- echo_Exception('Invalid patch mode "' . $sign . '" in: ' . $line);
- }
- $textPointer++;
- }
- }
- return $patches;
- }
-}
-
-/**
- * Class representing one patch operation.
- * @constructor
- */
-class patch_obj {
- /** @type {Array.<Array.<number|string>>} */
- public $diffs = array();
- /** @type {number?} */
- public $start1 = null;
- /** @type {number?} */
- public $start2 = null;
- /** @type {number} */
- public $length1 = 0;
- /** @type {number} */
- public $length2 = 0;
-
- /**
- * Emmulate GNU diff's format.
- * Header: @@ -382,8 +481,9 @@
- * Indicies are printed as 1-based, not 0-based.
- * @return {string} The GNU diff string.
- */
- function toString() {
- if ($this->length1 === 0) {
- $coords1 = $this->start1 . ',0';
- } elseif ($this->length1 == 1) {
- $coords1 = $this->start1 + 1;
- } else {
- $coords1 = ($this->start1 + 1) . ',' . $this->length1;
- }
- if ($this->length2 === 0) {
- $coords2 = $this->start2 . ',0';
- } elseif ($this->length2 == 1) {
- $coords2 = $this->start2 + 1;
- } else {
- $coords2 = ($this->start2 + 1) . ',' . $this->length2;
- }
- $text = array ( '@@ -' . $coords1 . ' +' . $coords2 . " @@\n" );
-
- // Escape the body of the patch with %xx notation.
- for ($x = 0; $x < count($this->diffs); $x++) {
- switch ($this->diffs[$x][0]) {
- case DIFF_INSERT :
- $op = '+';
- break;
- case DIFF_DELETE :
- $op = '-';
- break;
- case DIFF_EQUAL :
- $op = ' ';
- break;
- }
- $text[$x +1] = $op . encodeURI($this->diffs[$x][1]) . "\n";
- }
- return str_replace('%20', ' ', implode('',$text));
- }
- function __toString(){
- return $this->toString();
- }
-}
-
-define('DIFF_DELETE', -1);
-define('DIFF_INSERT', 1);
-define('DIFF_EQUAL', 0);
-
-define('Match_MaxBits', PHP_INT_SIZE * 8);
-
-
-function charCodeAt($str, $pos) {
- return mb_ord(mb_substr($str, $pos, 1));
-}
-function mb_ord($v) {
- $k = mb_convert_encoding($v, 'UCS-2LE', 'UTF-8');
- $k1 = ord(substr($k, 0, 1));
- $k2 = ord(substr($k, 1, 1));
- return $k2 * 256 + $k1;
-}
-function mb_chr($num){
- return mb_convert_encoding('&#'.intval($num).';', 'UTF-8', 'HTML-ENTITIES');
-}
-
-/**
- * as in javascript encodeURI() following the MDN description
- *
- * @link https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/encodeURI
- * @param $url
- * @return string
- */
-function encodeURI($url) {
- return strtr(rawurlencode($url), array (
- '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', '%26' => '&', '%3D' => '=',
- '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#',
- ));
-}
-
-function decodeURI($encoded) {
- static $dontDecode;
- if (!$dontDecode) {
- $table = array (
- '%3B' => ';', '%2C' => ',', '%2F' => '/', '%3F' => '?', '%3A' => ':', '%40' => '@', '%26' => '&', '%3D' => '=',
- '%2B' => '+', '%24' => '$', '%21' => '!', '%2A' => '*', '%27' => '\'', '%28' => '(', '%29' => ')', '%23' => '#',
- );
- $dontDecode = array();
- foreach ($table as $k => $v) {
- $dontDecode[$k] = encodeURI($k);
- }
- }
- return rawurldecode(strtr($encoded, $dontDecode));
-}
-
-function echo_Exception($str){
- global $lastException;
- $lastException = $str;
- echo $str;
-}
-//mb_internal_encoding("UTF-8");
-
-?>
\ No newline at end of file
diff --git a/resources/sql/quickstart.sql b/resources/sql/quickstart.sql
--- a/resources/sql/quickstart.sql
+++ b/resources/sql/quickstart.sql
@@ -7552,113 +7552,6 @@
KEY `key_merchant` (`merchantPHID`)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_phragment` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */;
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `edge` (
- `src` varbinary(64) NOT NULL,
- `type` int(10) unsigned NOT NULL,
- `dst` varbinary(64) NOT NULL,
- `dateCreated` int(10) unsigned NOT NULL,
- `seq` int(10) unsigned NOT NULL,
- `dataID` int(10) unsigned DEFAULT NULL,
- PRIMARY KEY (`src`,`type`,`dst`),
- UNIQUE KEY `key_dst` (`dst`,`type`,`src`),
- KEY `src` (`src`,`type`,`dateCreated`,`seq`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `edgedata` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `data` longtext CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `phragment_fragment` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `phid` varbinary(64) NOT NULL,
- `path` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL,
- `depth` int(10) unsigned NOT NULL,
- `latestVersionPHID` varbinary(64) DEFAULT NULL,
- `viewPolicy` varbinary(64) NOT NULL,
- `editPolicy` varbinary(64) NOT NULL,
- `dateCreated` int(10) unsigned NOT NULL,
- `dateModified` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `key_phid` (`phid`),
- UNIQUE KEY `key_path` (`path`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `phragment_fragmentversion` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `phid` varbinary(64) NOT NULL,
- `sequence` int(10) unsigned NOT NULL,
- `fragmentPHID` varbinary(64) NOT NULL,
- `filePHID` varbinary(64) DEFAULT NULL,
- `dateCreated` int(10) unsigned NOT NULL,
- `dateModified` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `key_version` (`fragmentPHID`,`sequence`),
- UNIQUE KEY `key_phid` (`phid`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `phragment_snapshot` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `phid` varbinary(64) NOT NULL,
- `primaryFragmentPHID` varbinary(64) NOT NULL,
- `name` varchar(128) CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} NOT NULL,
- `dateCreated` int(10) unsigned NOT NULL,
- `dateModified` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `key_phid` (`phid`),
- UNIQUE KEY `key_name` (`primaryFragmentPHID`,`name`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
-USE `{$NAMESPACE}_phragment`;
-
- SET NAMES utf8 ;
-
- SET character_set_client = {$CHARSET} ;
-
-CREATE TABLE `phragment_snapshotchild` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `snapshotPHID` varbinary(64) NOT NULL,
- `fragmentPHID` varbinary(64) NOT NULL,
- `fragmentVersionPHID` varbinary(64) DEFAULT NULL,
- `dateCreated` int(10) unsigned NOT NULL,
- `dateModified` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `key_child` (`snapshotPHID`,`fragmentPHID`,`fragmentVersionPHID`)
-) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};
-
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `{$NAMESPACE}_phrequent` /*!40100 DEFAULT CHARACTER SET {$CHARSET} COLLATE {$COLLATE_TEXT} */;
USE `{$NAMESPACE}_phrequent`;
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1536,7 +1536,6 @@
'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php',
'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php',
'HarbormasterPrototypeBuildStepGroup' => 'applications/harbormaster/stepgroup/HarbormasterPrototypeBuildStepGroup.php',
- 'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php',
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryAutotargetsConduitAPIMethod.php',
'HarbormasterQueryBuildablesConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildablesConduitAPIMethod.php',
'HarbormasterQueryBuildsConduitAPIMethod' => 'applications/harbormaster/conduit/HarbormasterQueryBuildsConduitAPIMethod.php',
@@ -4234,7 +4233,6 @@
'PhabricatorPhortuneManagementInvoiceWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementInvoiceWorkflow.php',
'PhabricatorPhortuneManagementWorkflow' => 'applications/phortune/management/PhabricatorPhortuneManagementWorkflow.php',
'PhabricatorPhortuneTestCase' => 'applications/phortune/__tests__/PhabricatorPhortuneTestCase.php',
- 'PhabricatorPhragmentApplication' => 'applications/phragment/application/PhabricatorPhragmentApplication.php',
'PhabricatorPhrequentApplication' => 'applications/phrequent/application/PhabricatorPhrequentApplication.php',
'PhabricatorPhrictionApplication' => 'applications/phriction/application/PhabricatorPhrictionApplication.php',
'PhabricatorPhurlApplication' => 'applications/phurl/application/PhabricatorPhurlApplication.php',
@@ -5559,38 +5557,6 @@
'PhortuneSubscriptionTransactionType' => 'applications/phortune/xaction/subscription/PhortuneSubscriptionTransactionType.php',
'PhortuneSubscriptionWorker' => 'applications/phortune/worker/PhortuneSubscriptionWorker.php',
'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php',
- 'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php',
- 'PhragmentCanCreateCapability' => 'applications/phragment/capability/PhragmentCanCreateCapability.php',
- 'PhragmentConduitAPIMethod' => 'applications/phragment/conduit/PhragmentConduitAPIMethod.php',
- 'PhragmentController' => 'applications/phragment/controller/PhragmentController.php',
- 'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php',
- 'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php',
- 'PhragmentFragment' => 'applications/phragment/storage/PhragmentFragment.php',
- 'PhragmentFragmentPHIDType' => 'applications/phragment/phid/PhragmentFragmentPHIDType.php',
- 'PhragmentFragmentQuery' => 'applications/phragment/query/PhragmentFragmentQuery.php',
- 'PhragmentFragmentVersion' => 'applications/phragment/storage/PhragmentFragmentVersion.php',
- 'PhragmentFragmentVersionPHIDType' => 'applications/phragment/phid/PhragmentFragmentVersionPHIDType.php',
- 'PhragmentFragmentVersionQuery' => 'applications/phragment/query/PhragmentFragmentVersionQuery.php',
- 'PhragmentGetPatchConduitAPIMethod' => 'applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php',
- 'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php',
- 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php',
- 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php',
- 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php',
- 'PhragmentQueryFragmentsConduitAPIMethod' => 'applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php',
- 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php',
- 'PhragmentSchemaSpec' => 'applications/phragment/storage/PhragmentSchemaSpec.php',
- 'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php',
- 'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php',
- 'PhragmentSnapshotChildQuery' => 'applications/phragment/query/PhragmentSnapshotChildQuery.php',
- 'PhragmentSnapshotCreateController' => 'applications/phragment/controller/PhragmentSnapshotCreateController.php',
- 'PhragmentSnapshotDeleteController' => 'applications/phragment/controller/PhragmentSnapshotDeleteController.php',
- 'PhragmentSnapshotPHIDType' => 'applications/phragment/phid/PhragmentSnapshotPHIDType.php',
- 'PhragmentSnapshotPromoteController' => 'applications/phragment/controller/PhragmentSnapshotPromoteController.php',
- 'PhragmentSnapshotQuery' => 'applications/phragment/query/PhragmentSnapshotQuery.php',
- 'PhragmentSnapshotViewController' => 'applications/phragment/controller/PhragmentSnapshotViewController.php',
- 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php',
- 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php',
- 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php',
'PhrequentConduitAPIMethod' => 'applications/phrequent/conduit/PhrequentConduitAPIMethod.php',
'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php',
'PhrequentCurtainExtension' => 'applications/phrequent/engineextension/PhrequentCurtainExtension.php',
@@ -7710,7 +7676,6 @@
'HarbormasterPlanRunController' => 'HarbormasterPlanController',
'HarbormasterPlanViewController' => 'HarbormasterPlanController',
'HarbormasterPrototypeBuildStepGroup' => 'HarbormasterBuildStepGroup',
- 'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation',
'HarbormasterQueryAutotargetsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterQueryBuildablesConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
'HarbormasterQueryBuildsConduitAPIMethod' => 'HarbormasterConduitAPIMethod',
@@ -10822,7 +10787,6 @@
'PhabricatorPhortuneManagementInvoiceWorkflow' => 'PhabricatorPhortuneManagementWorkflow',
'PhabricatorPhortuneManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorPhortuneTestCase' => 'PhabricatorTestCase',
- 'PhabricatorPhragmentApplication' => 'PhabricatorApplication',
'PhabricatorPhrequentApplication' => 'PhabricatorApplication',
'PhabricatorPhrictionApplication' => 'PhabricatorApplication',
'PhabricatorPhurlApplication' => 'PhabricatorApplication',
@@ -12442,50 +12406,6 @@
'PhortuneSubscriptionTransactionType' => 'PhabricatorModularTransactionType',
'PhortuneSubscriptionWorker' => 'PhabricatorWorker',
'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider',
- 'PhragmentBrowseController' => 'PhragmentController',
- 'PhragmentCanCreateCapability' => 'PhabricatorPolicyCapability',
- 'PhragmentConduitAPIMethod' => 'ConduitAPIMethod',
- 'PhragmentController' => 'PhabricatorController',
- 'PhragmentCreateController' => 'PhragmentController',
- 'PhragmentDAO' => 'PhabricatorLiskDAO',
- 'PhragmentFragment' => array(
- 'PhragmentDAO',
- 'PhabricatorPolicyInterface',
- ),
- 'PhragmentFragmentPHIDType' => 'PhabricatorPHIDType',
- 'PhragmentFragmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhragmentFragmentVersion' => array(
- 'PhragmentDAO',
- 'PhabricatorPolicyInterface',
- ),
- 'PhragmentFragmentVersionPHIDType' => 'PhabricatorPHIDType',
- 'PhragmentFragmentVersionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhragmentGetPatchConduitAPIMethod' => 'PhragmentConduitAPIMethod',
- 'PhragmentHistoryController' => 'PhragmentController',
- 'PhragmentPatchController' => 'PhragmentController',
- 'PhragmentPatchUtil' => 'Phobject',
- 'PhragmentPolicyController' => 'PhragmentController',
- 'PhragmentQueryFragmentsConduitAPIMethod' => 'PhragmentConduitAPIMethod',
- 'PhragmentRevertController' => 'PhragmentController',
- 'PhragmentSchemaSpec' => 'PhabricatorConfigSchemaSpec',
- 'PhragmentSnapshot' => array(
- 'PhragmentDAO',
- 'PhabricatorPolicyInterface',
- ),
- 'PhragmentSnapshotChild' => array(
- 'PhragmentDAO',
- 'PhabricatorPolicyInterface',
- ),
- 'PhragmentSnapshotChildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhragmentSnapshotCreateController' => 'PhragmentController',
- 'PhragmentSnapshotDeleteController' => 'PhragmentController',
- 'PhragmentSnapshotPHIDType' => 'PhabricatorPHIDType',
- 'PhragmentSnapshotPromoteController' => 'PhragmentController',
- 'PhragmentSnapshotQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
- 'PhragmentSnapshotViewController' => 'PhragmentController',
- 'PhragmentUpdateController' => 'PhragmentController',
- 'PhragmentVersionController' => 'PhragmentController',
- 'PhragmentZIPController' => 'PhragmentController',
'PhrequentConduitAPIMethod' => 'ConduitAPIMethod',
'PhrequentController' => 'PhabricatorController',
'PhrequentCurtainExtension' => 'PHUICurtainExtension',
diff --git a/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php b/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php
deleted file mode 100644
--- a/src/applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php
+++ /dev/null
@@ -1,89 +0,0 @@
-<?php
-
-final class HarbormasterPublishFragmentBuildStepImplementation
- extends HarbormasterBuildStepImplementation {
-
- public function getName() {
- return pht('Publish Fragment');
- }
-
- public function getGenericDescription() {
- return pht('Publish a fragment based on a file artifact.');
- }
-
-
- public function getBuildStepGroupKey() {
- return HarbormasterPrototypeBuildStepGroup::GROUPKEY;
- }
-
- public function getDescription() {
- return pht(
- 'Publish file artifact %s as fragment %s.',
- $this->formatSettingForDescription('artifact'),
- $this->formatSettingForDescription('path'));
- }
-
- public function execute(
- HarbormasterBuild $build,
- HarbormasterBuildTarget $build_target) {
-
- $settings = $this->getSettings();
- $variables = $build_target->getVariables();
- $viewer = PhabricatorUser::getOmnipotentUser();
-
- $path = $this->mergeVariables(
- 'vsprintf',
- $settings['path'],
- $variables);
-
- $artifact = $build_target->loadArtifact($settings['artifact']);
- $impl = $artifact->getArtifactImplementation();
- $file = $impl->loadArtifactFile($viewer);
-
- $fragment = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->withPaths(array($path))
- ->executeOne();
-
- if ($fragment === null) {
- PhragmentFragment::createFromFile(
- $viewer,
- $file,
- $path,
- PhabricatorPolicies::getMostOpenPolicy(),
- PhabricatorPolicies::POLICY_USER);
- } else {
- if ($file->getMimeType() === 'application/zip') {
- $fragment->updateFromZIP($viewer, $file);
- } else {
- $fragment->updateFromFile($viewer, $file);
- }
- }
- }
-
- public function getArtifactInputs() {
- return array(
- array(
- 'name' => pht('Publishes File'),
- 'key' => $this->getSetting('artifact'),
- 'type' => HarbormasterFileArtifact::ARTIFACTCONST,
- ),
- );
- }
-
- public function getFieldSpecifications() {
- return array(
- 'path' => array(
- 'name' => pht('Path'),
- 'type' => 'text',
- 'required' => true,
- ),
- 'artifact' => array(
- 'name' => pht('File Artifact'),
- 'type' => 'text',
- 'required' => true,
- ),
- );
- }
-
-}
diff --git a/src/applications/phragment/application/PhabricatorPhragmentApplication.php b/src/applications/phragment/application/PhabricatorPhragmentApplication.php
deleted file mode 100644
--- a/src/applications/phragment/application/PhabricatorPhragmentApplication.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-
-final class PhabricatorPhragmentApplication extends PhabricatorApplication {
-
- public function getName() {
- return pht('Phragment');
- }
-
- public function getBaseURI() {
- return '/phragment/';
- }
-
- public function getShortDescription() {
- return pht('Versioned Artifact Storage');
- }
-
- public function getIcon() {
- return 'fa-floppy-o';
- }
-
- public function getTitleGlyph() {
- return "\xE2\x96\x9B";
- }
-
- public function getApplicationGroup() {
- return self::GROUP_UTILITIES;
- }
-
- public function isPrototype() {
- return true;
- }
-
- public function getRoutes() {
- return array(
- '/phragment/' => array(
- '' => 'PhragmentBrowseController',
- 'browse/(?P<dblob>.*)' => 'PhragmentBrowseController',
- 'create/(?P<dblob>.*)' => 'PhragmentCreateController',
- 'update/(?P<dblob>.+)' => 'PhragmentUpdateController',
- 'policy/(?P<dblob>.+)' => 'PhragmentPolicyController',
- 'history/(?P<dblob>.+)' => 'PhragmentHistoryController',
- 'zip/(?P<dblob>.+)' => 'PhragmentZIPController',
- 'zip@(?P<snapshot>[^/]+)/(?P<dblob>.+)' => 'PhragmentZIPController',
- 'version/(?P<id>[0-9]*)/' => 'PhragmentVersionController',
- 'patch/(?P<aid>[0-9x]*)/(?P<bid>[0-9]*)/' => 'PhragmentPatchController',
- 'revert/(?P<id>[0-9]*)/(?P<dblob>.*)' => 'PhragmentRevertController',
- 'snapshot/' => array(
- 'create/(?P<dblob>.*)' => 'PhragmentSnapshotCreateController',
- 'view/(?P<id>[0-9]*)/' => 'PhragmentSnapshotViewController',
- 'delete/(?P<id>[0-9]*)/' => 'PhragmentSnapshotDeleteController',
- 'promote/' => array(
- 'latest/(?P<dblob>.*)' => 'PhragmentSnapshotPromoteController',
- '(?P<id>[0-9]*)/' => 'PhragmentSnapshotPromoteController',
- ),
- ),
- ),
- );
- }
-
- protected function getCustomCapabilities() {
- return array(
- PhragmentCanCreateCapability::CAPABILITY => array(),
- );
- }
-
-}
diff --git a/src/applications/phragment/capability/PhragmentCanCreateCapability.php b/src/applications/phragment/capability/PhragmentCanCreateCapability.php
deleted file mode 100644
--- a/src/applications/phragment/capability/PhragmentCanCreateCapability.php
+++ /dev/null
@@ -1,15 +0,0 @@
-<?php
-
-final class PhragmentCanCreateCapability extends PhabricatorPolicyCapability {
-
- const CAPABILITY = 'phragment.create';
-
- public function getCapabilityName() {
- return pht('Can Create Fragments');
- }
-
- public function describeCapabilityRejection() {
- return pht('You do not have permission to create fragments.');
- }
-
-}
diff --git a/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php
deleted file mode 100644
--- a/src/applications/phragment/conduit/PhragmentConduitAPIMethod.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-
-abstract class PhragmentConduitAPIMethod extends ConduitAPIMethod {
-
- final public function getApplication() {
- return PhabricatorApplication::getByClass(
- 'PhabricatorPhragmentApplication');
- }
-
-}
diff --git a/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php
deleted file mode 100644
--- a/src/applications/phragment/conduit/PhragmentGetPatchConduitAPIMethod.php
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-
-final class PhragmentGetPatchConduitAPIMethod
- extends PhragmentConduitAPIMethod {
-
- public function getAPIMethodName() {
- return 'phragment.getpatch';
- }
-
- public function getMethodStatus() {
- return self::METHOD_STATUS_UNSTABLE;
- }
-
- public function getMethodDescription() {
- return pht('Retrieve the patches to apply for a given set of files.');
- }
-
- protected function defineParamTypes() {
- return array(
- 'path' => 'required string',
- 'state' => 'required dict<string, string>',
- );
- }
-
- protected function defineReturnType() {
- return 'nonempty dict';
- }
-
- protected function defineErrorTypes() {
- return array(
- 'ERR_BAD_FRAGMENT' => pht('No such fragment exists.'),
- );
- }
-
- protected function execute(ConduitAPIRequest $request) {
- $path = $request->getValue('path');
- $state = $request->getValue('state');
- // The state is an array mapping file paths to hashes.
-
- $patches = array();
-
- // We need to get all of the mappings (like phragment.getstate) first
- // so that we can detect deletions and creations of files.
- $fragment = id(new PhragmentFragmentQuery())
- ->setViewer($request->getUser())
- ->withPaths(array($path))
- ->executeOne();
- if ($fragment === null) {
- throw new ConduitException('ERR_BAD_FRAGMENT');
- }
-
- $mappings = $fragment->getFragmentMappings(
- $request->getUser(),
- $fragment->getPath());
-
- $file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID');
- $files = id(new PhabricatorFileQuery())
- ->setViewer($request->getUser())
- ->withPHIDs($file_phids)
- ->execute();
- $files = mpull($files, null, 'getPHID');
-
- // Scan all of the files that the caller currently has and iterate
- // over that.
- foreach ($state as $path => $hash) {
- // If $mappings[$path] exists, then the user has the file and it's
- // also a fragment.
- if (array_key_exists($path, $mappings)) {
- $file_phid = $mappings[$path]->getLatestVersion()->getFilePHID();
- if ($file_phid !== null) {
- // If the file PHID is present, then we need to check the
- // hashes to see if they are the same.
- $hash_caller = strtolower($state[$path]);
- $hash_current = $files[$file_phid]->getContentHash();
- if ($hash_caller === $hash_current) {
- // The user's version is identical to our version, so
- // there is no update needed.
- } else {
- // The hash differs, and the user needs to update.
- $patches[] = array(
- 'path' => $path,
- 'fileOld' => null,
- 'fileNew' => $files[$file_phid],
- 'hashOld' => $hash_caller,
- 'hashNew' => $hash_current,
- 'patchURI' => null,
- );
- }
- } else {
- // We have a record of this as a file, but there is no file
- // attached to the latest version, so we consider this to be
- // a deletion.
- $patches[] = array(
- 'path' => $path,
- 'fileOld' => null,
- 'fileNew' => null,
- 'hashOld' => $hash_caller,
- 'hashNew' => PhragmentPatchUtil::EMPTY_HASH,
- 'patchURI' => null,
- );
- }
- } else {
- // If $mappings[$path] does not exist, then the user has a file,
- // and we have absolutely no record of it what-so-ever (we haven't
- // even recorded a deletion). Assuming most applications will store
- // some form of data near their own files, this is probably a data
- // file relevant for the application that is not versioned, so we
- // don't tell the client to do anything with it.
- }
- }
-
- // Check the remaining files that we know about but the caller has
- // not reported.
- foreach ($mappings as $path => $child) {
- if (array_key_exists($path, $state)) {
- // We have already evaluated this above.
- } else {
- $file_phid = $mappings[$path]->getLatestVersion()->getFilePHID();
- if ($file_phid !== null) {
- // If the file PHID is present, then this is a new file that
- // we know about, but the caller does not. We need to tell
- // the caller to create the file.
- $hash_current = $files[$file_phid]->getContentHash();
- $patches[] = array(
- 'path' => $path,
- 'fileOld' => null,
- 'fileNew' => $files[$file_phid],
- 'hashOld' => PhragmentPatchUtil::EMPTY_HASH,
- 'hashNew' => $hash_current,
- 'patchURI' => null,
- );
- } else {
- // We have a record of deleting this file, and the caller hasn't
- // reported it, so they've probably deleted it in a previous
- // update.
- }
- }
- }
-
- // Before we can calculate patches, we need to resolve the old versions
- // of files so we can draw diffs on them.
- $hashes = array();
- foreach ($patches as $patch) {
- if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) {
- $hashes[] = $patch['hashOld'];
- }
- }
- $old_files = array();
- if (count($hashes) !== 0) {
- $old_files = id(new PhabricatorFileQuery())
- ->setViewer($request->getUser())
- ->withContentHashes($hashes)
- ->execute();
- }
- $old_files = mpull($old_files, null, 'getContentHash');
- foreach ($patches as $key => $patch) {
- if ($patch['hashOld'] !== PhragmentPatchUtil::EMPTY_HASH) {
- if (array_key_exists($patch['hashOld'], $old_files)) {
- $patches[$key]['fileOld'] = $old_files[$patch['hashOld']];
- } else {
- // We either can't see or can't read the old file.
- $patches[$key]['hashOld'] = PhragmentPatchUtil::EMPTY_HASH;
- $patches[$key]['fileOld'] = null;
- }
- }
- }
-
- // Now run through all of the patch entries, calculate the patches
- // and return the results.
- foreach ($patches as $key => $patch) {
- $data = PhragmentPatchUtil::calculatePatch(
- $patches[$key]['fileOld'],
- $patches[$key]['fileNew']);
- unset($patches[$key]['fileOld']);
- unset($patches[$key]['fileNew']);
-
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
- $file = PhabricatorFile::newFromFileData(
- $data,
- array(
- 'name' => 'patch.dmp',
- 'ttl.relative' => phutil_units('24 hours in seconds'),
- ));
- unset($unguarded);
-
- $patches[$key]['patchURI'] = $file->getDownloadURI();
- }
-
- return $patches;
- }
-
-}
diff --git a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php b/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php
deleted file mode 100644
--- a/src/applications/phragment/conduit/PhragmentQueryFragmentsConduitAPIMethod.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-
-final class PhragmentQueryFragmentsConduitAPIMethod
- extends PhragmentConduitAPIMethod {
-
- public function getAPIMethodName() {
- return 'phragment.queryfragments';
- }
-
- public function getMethodStatus() {
- return self::METHOD_STATUS_UNSTABLE;
- }
-
- public function getMethodDescription() {
- return pht('Query fragments based on their paths.');
- }
-
- protected function defineParamTypes() {
- return array(
- 'paths' => 'required list<string>',
- );
- }
-
- protected function defineReturnType() {
- return 'nonempty dict';
- }
-
- protected function defineErrorTypes() {
- return array(
- 'ERR_BAD_FRAGMENT' => pht('No such fragment exists.'),
- );
- }
-
- protected function execute(ConduitAPIRequest $request) {
- $paths = $request->getValue('paths');
-
- $fragments = id(new PhragmentFragmentQuery())
- ->setViewer($request->getUser())
- ->withPaths($paths)
- ->execute();
- $fragments = mpull($fragments, null, 'getPath');
- foreach ($paths as $path) {
- if (!array_key_exists($path, $fragments)) {
- throw new ConduitException('ERR_BAD_FRAGMENT');
- }
- }
-
- $results = array();
- foreach ($fragments as $path => $fragment) {
- $mappings = $fragment->getFragmentMappings(
- $request->getUser(),
- $fragment->getPath());
-
- $file_phids = mpull(mpull($mappings, 'getLatestVersion'), 'getFilePHID');
- $files = id(new PhabricatorFileQuery())
- ->setViewer($request->getUser())
- ->withPHIDs($file_phids)
- ->execute();
- $files = mpull($files, null, 'getPHID');
-
- $result = array();
- foreach ($mappings as $cpath => $child) {
- $file_phid = $child->getLatestVersion()->getFilePHID();
- if (!isset($files[$file_phid])) {
- // Skip any files we don't have permission to access.
- continue;
- }
-
- $file = $files[$file_phid];
- $cpath = substr($child->getPath(), strlen($fragment->getPath()) + 1);
- $result[] = array(
- 'phid' => $child->getPHID(),
- 'phidVersion' => $child->getLatestVersionPHID(),
- 'path' => $cpath,
- 'hash' => $file->getContentHash(),
- 'version' => $child->getLatestVersion()->getSequence(),
- 'uri' => $file->getViewURI(),
- );
- }
- $results[$path] = $result;
- }
- return $results;
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentBrowseController.php b/src/applications/phragment/controller/PhragmentBrowseController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentBrowseController.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-final class PhragmentBrowseController extends PhragmentController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $current = nonempty(last($parents), null);
-
- $path = '';
- if ($current !== null) {
- $path = $current->getPath();
- }
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- if ($this->hasApplicationCapability(
- PhragmentCanCreateCapability::CAPABILITY)) {
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('fa-plus-square'));
- }
-
- $current_box = $this->createCurrentFragmentView($current, false);
-
- $list = id(new PHUIObjectItemListView())
- ->setUser($viewer);
-
- $fragments = null;
- if ($current === null) {
- // Find all root fragments.
- $fragments = id(new PhragmentFragmentQuery())
- ->setViewer($this->getRequest()->getUser())
- ->needLatestVersion(true)
- ->withDepths(array(1))
- ->execute();
- } else {
- // Find all child fragments.
- $fragments = id(new PhragmentFragmentQuery())
- ->setViewer($this->getRequest()->getUser())
- ->needLatestVersion(true)
- ->withLeadingPath($current->getPath().'/')
- ->withDepths(array($current->getDepth() + 1))
- ->execute();
- }
-
- foreach ($fragments as $fragment) {
- $item = id(new PHUIObjectItemView());
- $item->setHeader($fragment->getName());
- $item->setHref($fragment->getURI());
- if (!$fragment->isDirectory()) {
- $item->addAttribute(pht(
- 'Last Updated %s',
- phabricator_datetime(
- $fragment->getLatestVersion()->getDateCreated(),
- $viewer)));
- $item->addAttribute(pht(
- 'Latest Version %s',
- $fragment->getLatestVersion()->getSequence()));
- if ($fragment->isDeleted()) {
- $item->setDisabled(true);
- $item->addAttribute(pht('Deleted'));
- }
- } else {
- $item->addAttribute(pht('Directory'));
- }
- $list->addItem($item);
- }
-
- $title = pht('Browse Fragments');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $current_box,
- $list,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentController.php b/src/applications/phragment/controller/PhragmentController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentController.php
+++ /dev/null
@@ -1,232 +0,0 @@
-<?php
-
-abstract class PhragmentController extends PhabricatorController {
-
- protected function loadParentFragments($path) {
- $components = explode('/', $path);
-
- $combinations = array();
- $current = '';
- foreach ($components as $component) {
- $current .= '/'.$component;
- $current = trim($current, '/');
- if (trim($current) === '') {
- continue;
- }
-
- $combinations[] = $current;
- }
-
- $fragments = array();
- $results = id(new PhragmentFragmentQuery())
- ->setViewer($this->getRequest()->getUser())
- ->needLatestVersion(true)
- ->withPaths($combinations)
- ->execute();
- foreach ($combinations as $combination) {
- $found = false;
- foreach ($results as $fragment) {
- if ($fragment->getPath() === $combination) {
- $fragments[] = $fragment;
- $found = true;
- break;
- }
- }
- if (!$found) {
- return null;
- }
- }
- return $fragments;
- }
-
- protected function buildApplicationCrumbsWithPath(array $fragments) {
- $crumbs = $this->buildApplicationCrumbs();
- $crumbs->addTextCrumb('/', '/phragment/');
- foreach ($fragments as $parent) {
- $crumbs->addTextCrumb(
- $parent->getName(),
- '/phragment/browse/'.$parent->getPath());
- }
- return $crumbs;
- }
-
- protected function createCurrentFragmentView($fragment, $is_history_view) {
- if ($fragment === null) {
- return null;
- }
-
- $viewer = $this->getRequest()->getUser();
-
- $snapshot_phids = array();
- $snapshots = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withPrimaryFragmentPHIDs(array($fragment->getPHID()))
- ->execute();
- foreach ($snapshots as $snapshot) {
- $snapshot_phids[] = $snapshot->getPHID();
- }
-
- $file = null;
- $file_uri = null;
- if (!$fragment->isDirectory()) {
- $file = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($fragment->getLatestVersion()->getFilePHID()))
- ->executeOne();
- if ($file !== null) {
- $file_uri = $file->getDownloadURI();
- }
- }
-
- $header = id(new PHUIHeaderView())
- ->setHeader($fragment->getName())
- ->setPolicyObject($fragment)
- ->setUser($viewer);
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $fragment,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $zip_uri = $this->getApplicationURI('zip/'.$fragment->getPath());
-
- $actions = id(new PhabricatorActionListView())
- ->setUser($viewer)
- ->setObject($fragment);
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Download Fragment'))
- ->setHref($this->isCorrectlyConfigured() ? $file_uri : null)
- ->setDisabled($file === null || !$this->isCorrectlyConfigured())
- ->setIcon('fa-download'));
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Download Contents as ZIP'))
- ->setHref($this->isCorrectlyConfigured() ? $zip_uri : null)
- ->setDisabled(!$this->isCorrectlyConfigured())
- ->setIcon('fa-floppy-o'));
- if (!$fragment->isDirectory()) {
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Update Fragment'))
- ->setHref($this->getApplicationURI('update/'.$fragment->getPath()))
- ->setDisabled(!$can_edit)
- ->setWorkflow(!$can_edit)
- ->setIcon('fa-refresh'));
- } else {
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Convert to File'))
- ->setHref($this->getApplicationURI('update/'.$fragment->getPath()))
- ->setDisabled(!$can_edit)
- ->setWorkflow(!$can_edit)
- ->setIcon('fa-file-o'));
- }
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Set Fragment Policies'))
- ->setHref($this->getApplicationURI('policy/'.$fragment->getPath()))
- ->setDisabled(!$can_edit)
- ->setWorkflow(!$can_edit)
- ->setIcon('fa-asterisk'));
- if ($is_history_view) {
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('View Child Fragments'))
- ->setHref($this->getApplicationURI('browse/'.$fragment->getPath()))
- ->setIcon('fa-search-plus'));
- } else {
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('View History'))
- ->setHref($this->getApplicationURI('history/'.$fragment->getPath()))
- ->setIcon('fa-list'));
- }
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Create Snapshot'))
- ->setHref($this->getApplicationURI(
- 'snapshot/create/'.$fragment->getPath()))
- ->setDisabled(!$can_edit)
- ->setWorkflow(!$can_edit)
- ->setIcon('fa-files-o'));
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Promote Snapshot to Here'))
- ->setHref($this->getApplicationURI(
- 'snapshot/promote/latest/'.$fragment->getPath()))
- ->setWorkflow(true)
- ->setDisabled(!$can_edit)
- ->setIcon('fa-arrow-circle-up'));
-
- $properties = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setObject($fragment)
- ->setActionList($actions);
-
- if (!$fragment->isDirectory()) {
- if ($fragment->isDeleted()) {
- $properties->addProperty(
- pht('Type'),
- pht('File (Deleted)'));
- } else {
- $properties->addProperty(
- pht('Type'),
- pht('File'));
- }
- $properties->addProperty(
- pht('Latest Version'),
- $viewer->renderHandle($fragment->getLatestVersionPHID()));
- } else {
- $properties->addProperty(
- pht('Type'),
- pht('Directory'));
- }
-
- if (count($snapshot_phids) > 0) {
- $properties->addProperty(
- pht('Snapshots'),
- $viewer->renderHandleList($snapshot_phids));
- }
-
- return id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($properties);
- }
-
- public function renderConfigurationWarningIfRequired() {
- $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
- if ($alt === null) {
- return id(new PHUIInfoView())
- ->setTitle(pht(
- '%s must be configured!',
- 'security.alternate-file-domain'))
- ->setSeverity(PHUIInfoView::SEVERITY_ERROR)
- ->appendChild(
- phutil_tag(
- 'p',
- array(),
- pht(
- "Because Phragment generates files (such as ZIP archives and ".
- "patches) as they are requested, it requires that you configure ".
- "the `%s` option. This option on it's own will also provide ".
- "additional security when serving files across Phabricator.",
- 'security.alternate-file-domain')));
- }
- return null;
- }
-
- /**
- * We use this to disable the download links if the alternate domain is
- * not configured correctly. Although the download links will mostly work
- * for logged in users without an alternate domain, the behaviour is
- * reasonably non-consistent and will deny public users, even if policies
- * are configured otherwise (because the Files app does not support showing
- * the info page to viewers who are not logged in).
- */
- public function isCorrectlyConfigured() {
- $alt = PhabricatorEnv::getEnvConfig('security.alternate-file-domain');
- return $alt !== null;
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentCreateController.php b/src/applications/phragment/controller/PhragmentCreateController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentCreateController.php
+++ /dev/null
@@ -1,135 +0,0 @@
-<?php
-
-final class PhragmentCreateController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parent = null;
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- if (count($parents) !== 0) {
- $parent = idx($parents, count($parents) - 1, null);
- }
-
- $parent_path = '';
- if ($parent !== null) {
- $parent_path = $parent->getPath();
- }
- $parent_path = trim($parent_path, '/');
-
- $fragment = id(new PhragmentFragment());
-
- $error_view = null;
-
- if ($request->isFormPost()) {
- $errors = array();
-
- $v_name = $request->getStr('name');
- $v_fileid = $request->getInt('fileID');
- $v_viewpolicy = $request->getStr('viewPolicy');
- $v_editpolicy = $request->getStr('editPolicy');
-
- if (strpos($v_name, '/') !== false) {
- $errors[] = pht("The fragment name can not contain '/'.");
- }
-
- $file = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withIDs(array($v_fileid))
- ->executeOne();
- if (!$file) {
- $errors[] = pht("The specified file doesn't exist.");
- }
-
- if (!count($errors)) {
- $depth = 1;
- if ($parent !== null) {
- $depth = $parent->getDepth() + 1;
- }
-
- PhragmentFragment::createFromFile(
- $viewer,
- $file,
- trim($parent_path.'/'.$v_name, '/'),
- $v_viewpolicy,
- $v_editpolicy);
-
- return id(new AphrontRedirectResponse())
- ->setURI('/phragment/browse/'.trim($parent_path.'/'.$v_name, '/'));
- } else {
- $error_view = id(new PHUIInfoView())
- ->setErrors($errors)
- ->setTitle(pht('Errors while creating fragment'));
- }
- }
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($fragment)
- ->execute();
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Parent Path'))
- ->setDisabled(true)
- ->setValue('/'.trim($parent_path.'/', '/')))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Name'))
- ->setName('name'))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('File ID'))
- ->setName('fileID'))
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setName('viewPolicy')
- ->setPolicyObject($fragment)
- ->setPolicies($policies)
- ->setCapability(PhabricatorPolicyCapability::CAN_VIEW))
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setUser($viewer)
- ->setName('editPolicy')
- ->setPolicyObject($fragment)
- ->setPolicies($policies)
- ->setCapability(PhabricatorPolicyCapability::CAN_EDIT))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Create Fragment'))
- ->addCancelButton(
- $this->getApplicationURI('browse/'.$parent_path)));
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('Create Fragment'));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Create Fragment'))
- ->setForm($form);
-
- if ($error_view) {
- $box->setInfoView($error_view);
- }
-
- $title = pht('Create Fragments');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentHistoryController.php b/src/applications/phragment/controller/PhragmentHistoryController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentHistoryController.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-
-final class PhragmentHistoryController extends PhragmentController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $current = idx($parents, count($parents) - 1, null);
-
- $path = $current->getPath();
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- if ($this->hasApplicationCapability(
- PhragmentCanCreateCapability::CAPABILITY)) {
- $crumbs->addAction(
- id(new PHUIListItemView())
- ->setName(pht('Create Fragment'))
- ->setHref($this->getApplicationURI('/create/'.$path))
- ->setIcon('fa-plus-square'));
- }
-
- $current_box = $this->createCurrentFragmentView($current, true);
-
- $versions = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withFragmentPHIDs(array($current->getPHID()))
- ->execute();
-
- $list = id(new PHUIObjectItemListView())
- ->setUser($viewer);
-
- $file_phids = mpull($versions, 'getFilePHID');
- $files = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs($file_phids)
- ->execute();
- $files = mpull($files, null, 'getPHID');
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $current,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $first = true;
- foreach ($versions as $version) {
- $item = id(new PHUIObjectItemView());
- $item->setHeader(pht('Version %s', $version->getSequence()));
- $item->setHref($version->getURI());
- $item->addAttribute(phabricator_datetime(
- $version->getDateCreated(),
- $viewer));
-
- if ($version->getFilePHID() === null) {
- $item->setDisabled(true);
- $item->addAttribute(pht('Deletion'));
- }
-
- if (!$first && $can_edit) {
- $item->addAction(id(new PHUIListItemView())
- ->setIcon('fa-refresh')
- ->setRenderNameAsTooltip(true)
- ->setWorkflow(true)
- ->setName(pht('Revert to Here'))
- ->setHref($this->getApplicationURI(
- 'revert/'.$version->getID().'/'.$current->getPath())));
- }
-
- $disabled = !isset($files[$version->getFilePHID()]);
- $action = id(new PHUIListItemView())
- ->setIcon('fa-download')
- ->setDisabled($disabled || !$this->isCorrectlyConfigured())
- ->setRenderNameAsTooltip(true)
- ->setName(pht('Download'));
- if (!$disabled && $this->isCorrectlyConfigured()) {
- $action->setHref($files[$version->getFilePHID()]
- ->getDownloadURI($version->getURI()));
- }
- $item->addAction($action);
-
- $list->addItem($item);
-
- $first = false;
- }
-
- $title = pht('Fragment History');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $current_box,
- $list,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentPatchController.php b/src/applications/phragment/controller/PhragmentPatchController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentPatchController.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-
-final class PhragmentPatchController extends PhragmentController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $aid = $request->getURIData('aid');
- $bid = $request->getURIData('bid');
-
- // If "aid" is "x", then it means the user wants to generate
- // a patch of an empty file to the version specified by "bid".
-
- $ids = array($aid, $bid);
- if ($aid === 'x') {
- $ids = array($bid);
- }
-
- $versions = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withIDs($ids)
- ->execute();
-
- $version_a = null;
- if ($aid !== 'x') {
- $version_a = idx($versions, $aid, null);
- if ($version_a === null) {
- return new Aphront404Response();
- }
- }
-
- $version_b = idx($versions, $bid, null);
- if ($version_b === null) {
- return new Aphront404Response();
- }
-
- $file_phids = array();
- if ($version_a !== null) {
- $file_phids[] = $version_a->getFilePHID();
- }
- $file_phids[] = $version_b->getFilePHID();
-
- $files = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs($file_phids)
- ->execute();
- $files = mpull($files, null, 'getPHID');
-
- $file_a = null;
- if ($version_a != null) {
- $file_a = idx($files, $version_a->getFilePHID(), null);
- }
- $file_b = idx($files, $version_b->getFilePHID(), null);
-
- $patch = PhragmentPatchUtil::calculatePatch($file_a, $file_b);
-
- if ($patch === null) {
- // There are no differences between the two files, so we output
- // an empty patch.
- $patch = '';
- }
-
- $a_sequence = 'x';
- if ($version_a !== null) {
- $a_sequence = $version_a->getSequence();
- }
-
- $name =
- $version_b->getFragment()->getName().'.'.
- $a_sequence.'.'.
- $version_b->getSequence().'.patch';
-
- $return = $version_b->getURI();
- if ($request->getExists('return')) {
- $return = $request->getStr('return');
- }
-
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
- $result = PhabricatorFile::newFromFileData(
- $patch,
- array(
- 'name' => $name,
- 'mime-type' => 'text/plain',
- 'ttl.relative' => phutil_units('24 hours in seconds'),
- ));
-
- $result->attachToObject($version_b->getFragmentPHID());
- unset($unguarded);
-
- return id(new AphrontRedirectResponse())
- ->setURI($result->getDownloadURI($return));
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentPolicyController.php b/src/applications/phragment/controller/PhragmentPolicyController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentPolicyController.php
+++ /dev/null
@@ -1,106 +0,0 @@
-<?php
-
-final class PhragmentPolicyController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $fragment = idx($parents, count($parents) - 1, null);
-
- $error_view = null;
-
- if ($request->isFormPost()) {
- $errors = array();
-
- $v_view_policy = $request->getStr('viewPolicy');
- $v_edit_policy = $request->getStr('editPolicy');
- $v_replace_children = $request->getBool('replacePoliciesOnChildren');
-
- $fragment->setViewPolicy($v_view_policy);
- $fragment->setEditPolicy($v_edit_policy);
-
- $fragment->save();
-
- if ($v_replace_children) {
- // If you can edit a fragment, you can forcibly set the policies
- // on child fragments, regardless of whether you can see them or not.
- $children = id(new PhragmentFragmentQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withLeadingPath($fragment->getPath().'/')
- ->execute();
- $children_phids = mpull($children, 'getPHID');
-
- $fragment->openTransaction();
- foreach ($children as $child) {
- $child->setViewPolicy($v_view_policy);
- $child->setEditPolicy($v_edit_policy);
- $child->save();
- }
- $fragment->saveTransaction();
- }
-
- return id(new AphrontRedirectResponse())
- ->setURI('/phragment/browse/'.$fragment->getPath());
- }
-
- $policies = id(new PhabricatorPolicyQuery())
- ->setViewer($viewer)
- ->setObject($fragment)
- ->execute();
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setName('viewPolicy')
- ->setPolicyObject($fragment)
- ->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
- ->setPolicies($policies))
- ->appendChild(
- id(new AphrontFormPolicyControl())
- ->setName('editPolicy')
- ->setPolicyObject($fragment)
- ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
- ->setPolicies($policies))
- ->appendChild(
- id(new AphrontFormCheckboxControl())
- ->addCheckbox(
- 'replacePoliciesOnChildren',
- 'true',
- pht(
- 'Replace policies on child fragments with '.
- 'the policies above.')))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Save Fragment Policies'))
- ->addCancelButton(
- $this->getApplicationURI('browse/'.$fragment->getPath())));
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('Edit Fragment Policies'));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Edit Fragment Policies: %s', $fragment->getPath()))
- ->setValidationException(null)
- ->setForm($form);
-
- $title = pht('Edit Fragment Policies');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentRevertController.php b/src/applications/phragment/controller/PhragmentRevertController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentRevertController.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-
-final class PhragmentRevertController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
- $dblob = $request->getURIData('dblob');
-
- $fragment = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->withPaths(array($dblob))
- ->requireCapabilities(
- array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->executeOne();
- if ($fragment === null) {
- return new Aphront404Response();
- }
-
- $version = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withFragmentPHIDs(array($fragment->getPHID()))
- ->withIDs(array($id))
- ->executeOne();
- if ($version === null) {
- return new Aphront404Response();
- }
-
- if ($request->isDialogFormPost()) {
- $file_phid = $version->getFilePHID();
-
- $file = null;
- if ($file_phid !== null) {
- $file = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($file_phid))
- ->executeOne();
- if ($file === null) {
- throw new Exception(
- pht('The file associated with this version was not found.'));
- }
- }
-
- if ($file === null) {
- $fragment->deleteFile($viewer);
- } else {
- $fragment->updateFromFile($viewer, $file);
- }
-
- return id(new AphrontRedirectResponse())
- ->setURI($this->getApplicationURI('/history/'.$dblob));
- }
-
- return $this->createDialog($fragment, $version);
- }
-
- public function createDialog(
- PhragmentFragment $fragment,
- PhragmentFragmentVersion $version) {
-
- $viewer = $this->getViewer();
-
- $dialog = id(new AphrontDialogView())
- ->setTitle(pht('Really revert this fragment?'))
- ->setUser($this->getViewer())
- ->addSubmitButton(pht('Revert'))
- ->addCancelButton(pht('Cancel'))
- ->appendParagraph(pht(
- 'Reverting this fragment to version %d will create a new version of '.
- 'the fragment. It will not delete any version history.',
- $version->getSequence()));
- return id(new AphrontDialogResponse())->setDialog($dialog);
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentSnapshotCreateController.php b/src/applications/phragment/controller/PhragmentSnapshotCreateController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentSnapshotCreateController.php
+++ /dev/null
@@ -1,170 +0,0 @@
-<?php
-
-final class PhragmentSnapshotCreateController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $fragment = nonempty(last($parents), null);
- if ($fragment === null) {
- return new Aphront404Response();
- }
-
- PhabricatorPolicyFilter::requireCapability(
- $viewer,
- $fragment,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $children = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->needLatestVersion(true)
- ->withLeadingPath($fragment->getPath().'/')
- ->execute();
-
- $errors = array();
- if ($request->isFormPost()) {
-
- $v_name = $request->getStr('name');
- if (strlen($v_name) === 0) {
- $errors[] = pht('You must specify a name.');
- }
- if (strpos($v_name, '/') !== false) {
- $errors[] = pht('Snapshot names can not contain "/".');
- }
-
- if (!count($errors)) {
- $snapshot = null;
-
- try {
- // Create the snapshot.
- $snapshot = id(new PhragmentSnapshot())
- ->setPrimaryFragmentPHID($fragment->getPHID())
- ->setName($v_name)
- ->save();
- } catch (AphrontDuplicateKeyQueryException $e) {
- $errors[] = pht('A snapshot with this name already exists.');
- }
-
- if (!count($errors)) {
- // Add the primary fragment.
- id(new PhragmentSnapshotChild())
- ->setSnapshotPHID($snapshot->getPHID())
- ->setFragmentPHID($fragment->getPHID())
- ->setFragmentVersionPHID($fragment->getLatestVersionPHID())
- ->save();
-
- // Add all of the child fragments.
- foreach ($children as $child) {
- id(new PhragmentSnapshotChild())
- ->setSnapshotPHID($snapshot->getPHID())
- ->setFragmentPHID($child->getPHID())
- ->setFragmentVersionPHID($child->getLatestVersionPHID())
- ->save();
- }
-
- return id(new AphrontRedirectResponse())
- ->setURI('/phragment/snapshot/view/'.$snapshot->getID());
- }
- }
- }
-
- $fragment_sequence = '-';
- if ($fragment->getLatestVersion() !== null) {
- $fragment_sequence = $fragment->getLatestVersion()->getSequence();
- }
-
- $rows = array();
- $rows[] = phutil_tag(
- 'tr',
- array(),
- array(
- phutil_tag('th', array(), pht('Fragment')),
- phutil_tag('th', array(), pht('Version')),
- ));
- $rows[] = phutil_tag(
- 'tr',
- array(),
- array(
- phutil_tag('td', array(), $fragment->getPath()),
- phutil_tag('td', array(), $fragment_sequence),
- ));
- foreach ($children as $child) {
- $sequence = '-';
- if ($child->getLatestVersion() !== null) {
- $sequence = $child->getLatestVersion()->getSequence();
- }
- $rows[] = phutil_tag(
- 'tr',
- array(),
- array(
- phutil_tag('td', array(), $child->getPath()),
- phutil_tag('td', array(), $sequence),
- ));
- }
-
- $table = phutil_tag(
- 'table',
- array('class' => 'remarkup-table'),
- $rows);
-
- $container = phutil_tag(
- 'div',
- array('class' => 'phabricator-remarkup'),
- array(
- phutil_tag(
- 'p',
- array(),
- pht(
- 'The snapshot will contain the following fragments at '.
- 'the specified versions: ')),
- $table,
- ));
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Fragment Path'))
- ->setDisabled(true)
- ->setValue('/'.$fragment->getPath()))
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('Snapshot Name'))
- ->setName('name'))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Create Snapshot'))
- ->addCancelButton(
- $this->getApplicationURI('browse/'.$fragment->getPath())))
- ->appendChild(
- id(new PHUIFormDividerControl()))
- ->appendInstructions($container);
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('Create Snapshot'));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Create Snapshot of %s', $fragment->getName()))
- ->setFormErrors($errors)
- ->setForm($form);
-
- $title = pht('Create Snapshot');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php b/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentSnapshotDeleteController.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php
-
-final class PhragmentSnapshotDeleteController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $snapshot = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->requireCapabilities(array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->withIDs(array($id))
- ->executeOne();
- if ($snapshot === null) {
- return new Aphront404Response();
- }
-
- if ($request->isDialogFormPost()) {
- $fragment_uri = $snapshot->getPrimaryFragment()->getURI();
-
- $snapshot->delete();
-
- return id(new AphrontRedirectResponse())
- ->setURI($fragment_uri);
- }
-
- return $this->createDialog();
- }
-
- public function createDialog() {
- $viewer = $this->getViewer();
-
- $dialog = id(new AphrontDialogView())
- ->setTitle(pht('Really delete this snapshot?'))
- ->setUser($this->getViewer())
- ->addSubmitButton(pht('Delete'))
- ->addCancelButton(pht('Cancel'))
- ->appendParagraph(pht(
- 'Deleting this snapshot is a permanent operation. You can not '.
- 'recover the state of the snapshot.'));
- return id(new AphrontDialogResponse())->setDialog($dialog);
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php b/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentSnapshotPromoteController.php
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-
-final class PhragmentSnapshotPromoteController extends PhragmentController {
-
- private $targetSnapshot;
- private $targetFragment;
- private $snapshots;
- private $options;
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
- $dblob = $request->getURIData('dblob');
-
- // When the user is promoting a snapshot to the latest version, the
- // identifier is a fragment path.
- if ($dblob !== null) {
- $this->targetFragment = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->requireCapabilities(array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->withPaths(array($dblob))
- ->executeOne();
- if ($this->targetFragment === null) {
- return new Aphront404Response();
- }
-
- $this->snapshots = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withPrimaryFragmentPHIDs(array($this->targetFragment->getPHID()))
- ->execute();
- }
-
- // When the user is promoting a snapshot to another snapshot, the
- // identifier is another snapshot ID.
- if ($id !== null) {
- $this->targetSnapshot = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->requireCapabilities(array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- ))
- ->withIDs(array($id))
- ->executeOne();
- if ($this->targetSnapshot === null) {
- return new Aphront404Response();
- }
-
- $this->snapshots = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withPrimaryFragmentPHIDs(array(
- $this->targetSnapshot->getPrimaryFragmentPHID(),
- ))
- ->execute();
- }
-
- // If there's no identifier, just 404.
- if ($this->snapshots === null) {
- return new Aphront404Response();
- }
-
- // Work out what options the user has.
- $this->options = mpull(
- $this->snapshots,
- 'getName',
- 'getID');
- if ($id !== null) {
- unset($this->options[$id]);
- }
-
- // If there's no options, show a dialog telling the
- // user there are no snapshots to promote.
- if (count($this->options) === 0) {
- return id(new AphrontDialogResponse())->setDialog(
- id(new AphrontDialogView())
- ->setTitle(pht('No snapshots to promote'))
- ->appendParagraph(pht(
- 'There are no snapshots available to promote.'))
- ->setUser($this->getViewer())
- ->addCancelButton(pht('Cancel')));
- }
-
- // Handle snapshot promotion.
- if ($request->isDialogFormPost()) {
- $snapshot = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withIDs(array($request->getStr('snapshot')))
- ->executeOne();
- if ($snapshot === null) {
- return new Aphront404Response();
- }
-
- $snapshot->openTransaction();
- // Delete all existing child entries.
- $children = id(new PhragmentSnapshotChildQuery())
- ->setViewer(PhabricatorUser::getOmnipotentUser())
- ->withSnapshotPHIDs(array($snapshot->getPHID()))
- ->execute();
- foreach ($children as $child) {
- $child->delete();
- }
-
- if ($id === null) {
- // The user is promoting the snapshot to the latest version.
- $children = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->needLatestVersion(true)
- ->withLeadingPath($this->targetFragment->getPath().'/')
- ->execute();
-
- // Add the primary fragment.
- id(new PhragmentSnapshotChild())
- ->setSnapshotPHID($snapshot->getPHID())
- ->setFragmentPHID($this->targetFragment->getPHID())
- ->setFragmentVersionPHID(
- $this->targetFragment->getLatestVersionPHID())
- ->save();
-
- // Add all of the child fragments.
- foreach ($children as $child) {
- id(new PhragmentSnapshotChild())
- ->setSnapshotPHID($snapshot->getPHID())
- ->setFragmentPHID($child->getPHID())
- ->setFragmentVersionPHID($child->getLatestVersionPHID())
- ->save();
- }
- } else {
- // The user is promoting the snapshot to another snapshot. We just
- // copy the other snapshot's child entries and change the snapshot
- // PHID to make it identical.
- $children = id(new PhragmentSnapshotChildQuery())
- ->setViewer($viewer)
- ->withSnapshotPHIDs(array($this->targetSnapshot->getPHID()))
- ->execute();
- foreach ($children as $child) {
- id(new PhragmentSnapshotChild())
- ->setSnapshotPHID($snapshot->getPHID())
- ->setFragmentPHID($child->getFragmentPHID())
- ->setFragmentVersionPHID($child->getFragmentVersionPHID())
- ->save();
- }
- }
- $snapshot->saveTransaction();
-
- if ($id === null) {
- return id(new AphrontRedirectResponse())
- ->setURI($this->targetFragment->getURI());
- } else {
- return id(new AphrontRedirectResponse())
- ->setURI($this->targetSnapshot->getURI());
- }
- }
-
- return $this->createDialog($id);
- }
-
- public function createDialog($id) {
- $viewer = $this->getViewer();
-
- $dialog = id(new AphrontDialogView())
- ->setTitle(pht('Promote which snapshot?'))
- ->setUser($this->getViewer())
- ->addSubmitButton(pht('Promote'))
- ->addCancelButton(pht('Cancel'));
-
- if ($id === null) {
- // The user is promoting a snapshot to the latest version.
- $dialog->appendParagraph(pht(
- 'Select the snapshot you want to promote to the latest version:'));
- } else {
- // The user is promoting a snapshot to another snapshot.
- $dialog->appendParagraph(pht(
- "Select the snapshot you want to promote to '%s':",
- $this->targetSnapshot->getName()));
- }
-
- $dialog->appendChild(
- id(new AphrontFormSelectControl())
- ->setUser($viewer)
- ->setName('snapshot')
- ->setOptions($this->options));
-
- return id(new AphrontDialogResponse())->setDialog($dialog);
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentSnapshotViewController.php b/src/applications/phragment/controller/PhragmentSnapshotViewController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentSnapshotViewController.php
+++ /dev/null
@@ -1,145 +0,0 @@
-<?php
-
-final class PhragmentSnapshotViewController extends PhragmentController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $snapshot = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->executeOne();
- if ($snapshot === null) {
- return new Aphront404Response();
- }
-
- $box = $this->createSnapshotView($snapshot);
-
- $fragment = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($snapshot->getPrimaryFragmentPHID()))
- ->executeOne();
- if ($fragment === null) {
- return new Aphront404Response();
- }
-
- $parents = $this->loadParentFragments($fragment->getPath());
- if ($parents === null) {
- return new Aphront404Response();
- }
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('"%s" Snapshot', $snapshot->getName()));
-
- $children = id(new PhragmentSnapshotChildQuery())
- ->setViewer($viewer)
- ->needFragments(true)
- ->needFragmentVersions(true)
- ->withSnapshotPHIDs(array($snapshot->getPHID()))
- ->execute();
-
- $list = id(new PHUIObjectItemListView())
- ->setUser($viewer);
-
- foreach ($children as $child) {
- $item = id(new PHUIObjectItemView())
- ->setHeader($child->getFragment()->getPath());
-
- if ($child->getFragmentVersion() !== null) {
- $item
- ->setHref($child->getFragmentVersion()->getURI())
- ->addAttribute(pht(
- 'Version %s',
- $child->getFragmentVersion()->getSequence()));
- } else {
- $item
- ->setHref($child->getFragment()->getURI())
- ->addAttribute(pht('Directory'));
- }
-
- $list->addItem($item);
- }
-
- $title = pht('View Snapshot');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- $list,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
- }
-
- protected function createSnapshotView($snapshot) {
- if ($snapshot === null) {
- return null;
- }
-
- $viewer = $this->getRequest()->getUser();
-
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('"%s" Snapshot', $snapshot->getName()))
- ->setPolicyObject($snapshot)
- ->setUser($viewer);
-
- $zip_uri = $this->getApplicationURI(
- 'zip@'.$snapshot->getName().
- '/'.$snapshot->getPrimaryFragment()->getPath());
-
- $can_edit = PhabricatorPolicyFilter::hasCapability(
- $viewer,
- $snapshot,
- PhabricatorPolicyCapability::CAN_EDIT);
-
- $actions = id(new PhabricatorActionListView())
- ->setUser($viewer)
- ->setObject($snapshot);
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Download Snapshot as ZIP'))
- ->setHref($this->isCorrectlyConfigured() ? $zip_uri : null)
- ->setDisabled(!$this->isCorrectlyConfigured())
- ->setIcon('fa-floppy-o'));
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Delete Snapshot'))
- ->setHref($this->getApplicationURI(
- 'snapshot/delete/'.$snapshot->getID().'/'))
- ->setDisabled(!$can_edit)
- ->setWorkflow(true)
- ->setIcon('fa-times'));
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Promote Another Snapshot to Here'))
- ->setHref($this->getApplicationURI(
- 'snapshot/promote/'.$snapshot->getID().'/'))
- ->setDisabled(!$can_edit)
- ->setWorkflow(true)
- ->setIcon('fa-arrow-up'));
-
- $properties = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setObject($snapshot)
- ->setActionList($actions);
-
- $properties->addProperty(
- pht('Name'),
- $snapshot->getName());
- $properties->addProperty(
- pht('Fragment'),
- $viewer->renderHandle($snapshot->getPrimaryFragmentPHID()));
-
- return id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($properties);
- }
-}
diff --git a/src/applications/phragment/controller/PhragmentUpdateController.php b/src/applications/phragment/controller/PhragmentUpdateController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentUpdateController.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-
-final class PhragmentUpdateController extends PhragmentController {
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $fragment = idx($parents, count($parents) - 1, null);
-
- $error_view = null;
-
- if ($request->isFormPost()) {
- $errors = array();
-
- $v_fileid = $request->getInt('fileID');
-
- $file = id(new PhabricatorFile())->load($v_fileid);
- if ($file === null) {
- $errors[] = pht('The specified file doesn\'t exist.');
- }
-
- if (!count($errors)) {
- // If the file is a ZIP archive (has application/zip mimetype)
- // then we extract the zip and apply versions for each of the
- // individual fragments, creating and deleting files as needed.
- if ($file->getMimeType() === 'application/zip') {
- $fragment->updateFromZIP($viewer, $file);
- } else {
- $fragment->updateFromFile($viewer, $file);
- }
-
- return id(new AphrontRedirectResponse())
- ->setURI('/phragment/browse/'.$fragment->getPath());
- } else {
- $error_view = id(new PHUIInfoView())
- ->setErrors($errors)
- ->setTitle(pht('Errors while updating fragment'));
- }
- }
-
- $form = id(new AphrontFormView())
- ->setUser($viewer)
- ->appendChild(
- id(new AphrontFormTextControl())
- ->setLabel(pht('File ID'))
- ->setName('fileID'))
- ->appendChild(
- id(new AphrontFormSubmitControl())
- ->setValue(pht('Update Fragment'))
- ->addCancelButton(
- $this->getApplicationURI('browse/'.$fragment->getPath())));
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('Update Fragment'));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeaderText(pht('Update Fragment: %s', $fragment->getPath()))
- ->setValidationException(null)
- ->setForm($form);
-
- $title = pht('Update Fragment');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
-
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentVersionController.php b/src/applications/phragment/controller/PhragmentVersionController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentVersionController.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-final class PhragmentVersionController extends PhragmentController {
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $id = $request->getURIData('id');
-
- $version = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withIDs(array($id))
- ->executeOne();
- if ($version === null) {
- return new Aphront404Response();
- }
-
- $parents = $this->loadParentFragments($version->getFragment()->getPath());
- if ($parents === null) {
- return new Aphront404Response();
- }
- $current = idx($parents, count($parents) - 1, null);
-
- $crumbs = $this->buildApplicationCrumbsWithPath($parents);
- $crumbs->addTextCrumb(pht('View Version %d', $version->getSequence()));
-
- $file = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs(array($version->getFilePHID()))
- ->executeOne();
- if ($file !== null) {
- $file_uri = $file->getDownloadURI();
- }
-
- $header = id(new PHUIHeaderView())
- ->setHeader(pht(
- '%s at version %d',
- $version->getFragment()->getName(),
- $version->getSequence()))
- ->setPolicyObject($version)
- ->setUser($viewer);
-
- $actions = id(new PhabricatorActionListView())
- ->setUser($viewer)
- ->setObject($version);
- $actions->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Download Version'))
- ->setDisabled($file === null || !$this->isCorrectlyConfigured())
- ->setHref($this->isCorrectlyConfigured() ? $file_uri : null)
- ->setIcon('fa-download'));
-
- $properties = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setObject($version)
- ->setActionList($actions);
- $properties->addProperty(
- pht('File'),
- $viewer->renderHandle($version->getFilePHID()));
-
- $box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->addPropertyList($properties);
-
- $title = pht('View Version');
-
- $view = array(
- $this->renderConfigurationWarningIfRequired(),
- $box,
- $this->renderPreviousVersionList($version),
- );
-
- return $this->newPage()
- ->setTitle($title)
- ->setCrumbs($crumbs)
- ->appendChild($view);
- }
-
- private function renderPreviousVersionList(
- PhragmentFragmentVersion $version) {
- $viewer = $this->getViewer();
-
- $previous_versions = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withFragmentPHIDs(array($version->getFragmentPHID()))
- ->withSequenceBefore($version->getSequence())
- ->execute();
-
- $list = id(new PHUIObjectItemListView())
- ->setUser($viewer);
-
- foreach ($previous_versions as $previous_version) {
- $item = id(new PHUIObjectItemView());
- $item->setHeader(pht('Version %s', $previous_version->getSequence()));
- $item->setHref($previous_version->getURI());
- $item->addAttribute(phabricator_datetime(
- $previous_version->getDateCreated(),
- $viewer));
- $patch_uri = $this->getApplicationURI(
- 'patch/'.$previous_version->getID().'/'.$version->getID());
- $item->addAction(id(new PHUIListItemView())
- ->setIcon('fa-file-o')
- ->setName(pht('Get Patch'))
- ->setHref($this->isCorrectlyConfigured() ? $patch_uri : null)
- ->setDisabled(!$this->isCorrectlyConfigured()));
- $list->addItem($item);
- }
-
- $item = id(new PHUIObjectItemView());
- $item->setHeader(pht('Prior to Version 0'));
- $item->addAttribute(pht('Prior to any content (empty file)'));
- $item->addAction(id(new PHUIListItemView())
- ->setIcon('fa-file-o')
- ->setName(pht('Get Patch'))
- ->setHref($this->getApplicationURI(
- 'patch/x/'.$version->getID())));
- $list->addItem($item);
-
- return $list;
- }
-
-}
diff --git a/src/applications/phragment/controller/PhragmentZIPController.php b/src/applications/phragment/controller/PhragmentZIPController.php
deleted file mode 100644
--- a/src/applications/phragment/controller/PhragmentZIPController.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-
-final class PhragmentZIPController extends PhragmentController {
-
- private $snapshotCache;
-
- public function shouldAllowPublic() {
- return true;
- }
-
- public function handleRequest(AphrontRequest $request) {
- $viewer = $request->getViewer();
- $dblob = $request->getURIData('dblob');
- $snapshot = $request->getURIData('snapshot');
-
- $parents = $this->loadParentFragments($dblob);
- if ($parents === null) {
- return new Aphront404Response();
- }
- $fragment = idx($parents, count($parents) - 1, null);
-
- if ($snapshot !== null) {
- $snapshot = id(new PhragmentSnapshotQuery())
- ->setViewer($viewer)
- ->withPrimaryFragmentPHIDs(array($fragment->getPHID()))
- ->withNames(array($snapshot))
- ->executeOne();
- if ($snapshot === null) {
- return new Aphront404Response();
- }
-
- $cache = id(new PhragmentSnapshotChildQuery())
- ->setViewer($viewer)
- ->needFragmentVersions(true)
- ->withSnapshotPHIDs(array($snapshot->getPHID()))
- ->execute();
- $this->snapshotCache = mpull(
- $cache,
- 'getFragmentVersion',
- 'getFragmentPHID');
- }
-
- $temp = new TempFile();
-
- $zip = null;
- try {
- $zip = new ZipArchive();
- } catch (Exception $e) {
- $dialog = new AphrontDialogView();
- $dialog->setUser($viewer);
-
- $inst = pht(
- 'This system does not have the ZIP PHP extension installed. This '.
- 'is required to download ZIPs from Phragment.');
-
- $dialog->setTitle(pht('ZIP Extension Not Installed'));
- $dialog->appendParagraph($inst);
-
- $dialog->addCancelButton('/phragment/browse/'.$dblob);
- return id(new AphrontDialogResponse())->setDialog($dialog);
- }
-
- if (!$zip->open((string)$temp, ZipArchive::CREATE)) {
- throw new Exception(pht('Unable to create ZIP archive!'));
- }
-
- $mappings = $this->getFragmentMappings(
- $fragment, $fragment->getPath(), $snapshot);
-
- $phids = array();
- foreach ($mappings as $path => $file_phid) {
- $phids[] = $file_phid;
- }
-
- $files = id(new PhabricatorFileQuery())
- ->setViewer($viewer)
- ->withPHIDs($phids)
- ->execute();
- $files = mpull($files, null, 'getPHID');
- foreach ($mappings as $path => $file_phid) {
- if (!isset($files[$file_phid])) {
- // The path is most likely pointing to a deleted fragment, which
- // hence no longer has a file associated with it.
- unset($mappings[$path]);
- continue;
- }
- $mappings[$path] = $files[$file_phid];
- }
-
- foreach ($mappings as $path => $file) {
- if ($file !== null) {
- $zip->addFromString($path, $file->loadFileData());
- }
- }
- $zip->close();
-
- $zip_name = $fragment->getName();
- if (substr($zip_name, -4) !== '.zip') {
- $zip_name .= '.zip';
- }
-
- $data = Filesystem::readFile((string)$temp);
-
- $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
- $file = PhabricatorFile::newFromFileData(
- $data,
- array(
- 'name' => $zip_name,
- 'ttl.relative' => phutil_units('24 hours in seconds'),
- ));
-
- $file->attachToObject($fragment->getPHID());
- unset($unguarded);
-
- $return = $fragment->getURI();
- if ($request->getExists('return')) {
- $return = $request->getStr('return');
- }
-
- return id(new AphrontRedirectResponse())
- ->setIsExternal(true)
- ->setURI($file->getDownloadURI($return));
- }
-
- /**
- * Returns a list of mappings like array('some/path.txt' => 'file PHID');
- */
- private function getFragmentMappings(
- PhragmentFragment $current,
- $base_path,
- $snapshot) {
- $mappings = $current->getFragmentMappings(
- $this->getRequest()->getUser(),
- $base_path);
-
- $result = array();
- foreach ($mappings as $path => $fragment) {
- $version = $this->getVersion($fragment, $snapshot);
- if ($version !== null) {
- $result[$path] = $version->getFilePHID();
- }
- }
- return $result;
- }
-
- private function getVersion($fragment, $snapshot) {
- if ($snapshot === null) {
- return $fragment->getLatestVersion();
- } else {
- return idx($this->snapshotCache, $fragment->getPHID(), null);
- }
- }
-
-}
diff --git a/src/applications/phragment/phid/PhragmentFragmentPHIDType.php b/src/applications/phragment/phid/PhragmentFragmentPHIDType.php
deleted file mode 100644
--- a/src/applications/phragment/phid/PhragmentFragmentPHIDType.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-final class PhragmentFragmentPHIDType extends PhabricatorPHIDType {
-
- const TYPECONST = 'PHRF';
-
- public function getTypeName() {
- return pht('Fragment');
- }
-
- public function newObject() {
- return new PhragmentFragment();
- }
-
- public function getPHIDTypeApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-
- protected function buildQueryForObjects(
- PhabricatorObjectQuery $query,
- array $phids) {
-
- return id(new PhragmentFragmentQuery())
- ->withPHIDs($phids);
- }
-
- public function loadHandles(
- PhabricatorHandleQuery $query,
- array $handles,
- array $objects) {
-
- $viewer = $query->getViewer();
- foreach ($handles as $phid => $handle) {
- $fragment = $objects[$phid];
-
- $handle->setName(pht(
- 'Fragment %s: %s',
- $fragment->getID(),
- $fragment->getName()));
- $handle->setURI($fragment->getURI());
- }
- }
-
-}
diff --git a/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php b/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php
deleted file mode 100644
--- a/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-
-final class PhragmentFragmentVersionPHIDType extends PhabricatorPHIDType {
-
- const TYPECONST = 'PHRV';
-
- public function getTypeName() {
- return pht('Fragment Version');
- }
-
- public function newObject() {
- return new PhragmentFragmentVersion();
- }
-
- public function getPHIDTypeApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-
- protected function buildQueryForObjects(
- PhabricatorObjectQuery $query,
- array $phids) {
-
- return id(new PhragmentFragmentVersionQuery())
- ->withPHIDs($phids);
- }
-
- public function loadHandles(
- PhabricatorHandleQuery $query,
- array $handles,
- array $objects) {
-
- $viewer = $query->getViewer();
- foreach ($handles as $phid => $handle) {
- $version = $objects[$phid];
-
- $handle->setName(pht(
- 'Fragment Version %d: %s',
- $version->getSequence(),
- $version->getFragment()->getName()));
- $handle->setURI($version->getURI());
- }
- }
-
-}
diff --git a/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php b/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php
deleted file mode 100644
--- a/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-
-final class PhragmentSnapshotPHIDType extends PhabricatorPHIDType {
-
- const TYPECONST = 'PHRS';
-
- public function getTypeName() {
- return pht('Snapshot');
- }
-
- public function newObject() {
- return new PhragmentSnapshot();
- }
-
- public function getPHIDTypeApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-
- protected function buildQueryForObjects(
- PhabricatorObjectQuery $query,
- array $phids) {
-
- return id(new PhragmentSnapshotQuery())
- ->withPHIDs($phids);
- }
-
- public function loadHandles(
- PhabricatorHandleQuery $query,
- array $handles,
- array $objects) {
-
- $viewer = $query->getViewer();
- foreach ($handles as $phid => $handle) {
- $snapshot = $objects[$phid];
-
- $handle->setName(pht(
- 'Snapshot: %s',
- $snapshot->getName()));
- $handle->setURI($snapshot->getURI());
- }
- }
-
-}
diff --git a/src/applications/phragment/query/PhragmentFragmentQuery.php b/src/applications/phragment/query/PhragmentFragmentQuery.php
deleted file mode 100644
--- a/src/applications/phragment/query/PhragmentFragmentQuery.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-
-final class PhragmentFragmentQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
-
- private $ids;
- private $phids;
- private $paths;
- private $leadingPath;
- private $depths;
- private $needLatestVersion;
-
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withPHIDs(array $phids) {
- $this->phids = $phids;
- return $this;
- }
-
- public function withPaths(array $paths) {
- $this->paths = $paths;
- return $this;
- }
-
- public function withLeadingPath($path) {
- $this->leadingPath = $path;
- return $this;
- }
-
- public function withDepths($depths) {
- $this->depths = $depths;
- return $this;
- }
-
- public function needLatestVersion($need_latest_version) {
- $this->needLatestVersion = $need_latest_version;
- return $this;
- }
-
- protected function loadPage() {
- $table = new PhragmentFragment();
- $conn_r = $table->establishConnection('r');
-
- $data = queryfx_all(
- $conn_r,
- 'SELECT * FROM %T %Q %Q %Q',
- $table->getTableName(),
- $this->buildWhereClause($conn_r),
- $this->buildOrderClause($conn_r),
- $this->buildLimitClause($conn_r));
-
- return $table->loadAllFromArray($data);
- }
-
- protected function buildWhereClause(AphrontDatabaseConnection $conn) {
- $where = array();
-
- if ($this->ids) {
- $where[] = qsprintf(
- $conn,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->phids) {
- $where[] = qsprintf(
- $conn,
- 'phid IN (%Ls)',
- $this->phids);
- }
-
- if ($this->paths) {
- $where[] = qsprintf(
- $conn,
- 'path IN (%Ls)',
- $this->paths);
- }
-
- if ($this->leadingPath) {
- $where[] = qsprintf(
- $conn,
- 'path LIKE %>',
- $this->leadingPath);
- }
-
- if ($this->depths) {
- $where[] = qsprintf(
- $conn,
- 'depth IN (%Ld)',
- $this->depths);
- }
-
- $where[] = $this->buildPagingClause($conn);
-
- return $this->formatWhereClause($conn, $where);
- }
-
- protected function didFilterPage(array $page) {
- if ($this->needLatestVersion) {
- $versions = array();
-
- $version_phids = array_filter(mpull($page, 'getLatestVersionPHID'));
- if ($version_phids) {
- $versions = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($version_phids)
- ->setParentQuery($this)
- ->execute();
- $versions = mpull($versions, null, 'getPHID');
- }
-
- foreach ($page as $key => $fragment) {
- $version_phid = $fragment->getLatestVersionPHID();
- if (empty($versions[$version_phid])) {
- continue;
- }
- $fragment->attachLatestVersion($versions[$version_phid]);
- }
- }
-
- return $page;
- }
-
- public function getQueryApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-}
diff --git a/src/applications/phragment/query/PhragmentFragmentVersionQuery.php b/src/applications/phragment/query/PhragmentFragmentVersionQuery.php
deleted file mode 100644
--- a/src/applications/phragment/query/PhragmentFragmentVersionQuery.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-final class PhragmentFragmentVersionQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
-
- private $ids;
- private $phids;
- private $fragmentPHIDs;
- private $sequences;
- private $sequenceBefore;
-
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withPHIDs(array $phids) {
- $this->phids = $phids;
- return $this;
- }
-
- public function withFragmentPHIDs(array $fragment_phids) {
- $this->fragmentPHIDs = $fragment_phids;
- return $this;
- }
-
- public function withSequences(array $sequences) {
- $this->sequences = $sequences;
- return $this;
- }
-
- public function withSequenceBefore($current) {
- $this->sequenceBefore = $current;
- return $this;
- }
-
- protected function loadPage() {
- $table = new PhragmentFragmentVersion();
- $conn_r = $table->establishConnection('r');
-
- $data = queryfx_all(
- $conn_r,
- 'SELECT * FROM %T %Q %Q %Q',
- $table->getTableName(),
- $this->buildWhereClause($conn_r),
- $this->buildOrderClause($conn_r),
- $this->buildLimitClause($conn_r));
-
- return $table->loadAllFromArray($data);
- }
-
- protected function buildWhereClause(AphrontDatabaseConnection $conn) {
- $where = array();
-
- if ($this->ids) {
- $where[] = qsprintf(
- $conn,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->phids) {
- $where[] = qsprintf(
- $conn,
- 'phid IN (%Ls)',
- $this->phids);
- }
-
- if ($this->fragmentPHIDs) {
- $where[] = qsprintf(
- $conn,
- 'fragmentPHID IN (%Ls)',
- $this->fragmentPHIDs);
- }
-
- if ($this->sequences) {
- $where[] = qsprintf(
- $conn,
- 'sequence IN (%Ld)',
- $this->sequences);
- }
-
- if ($this->sequenceBefore !== null) {
- $where[] = qsprintf(
- $conn,
- 'sequence < %d',
- $this->sequenceBefore);
- }
-
- $where[] = $this->buildPagingClause($conn);
-
- return $this->formatWhereClause($conn, $where);
- }
-
- protected function willFilterPage(array $page) {
- $fragments = array();
-
- $fragment_phids = array_filter(mpull($page, 'getFragmentPHID'));
- if ($fragment_phids) {
- $fragments = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($fragment_phids)
- ->setParentQuery($this)
- ->execute();
- $fragments = mpull($fragments, null, 'getPHID');
- }
-
- foreach ($page as $key => $version) {
- $fragment_phid = $version->getFragmentPHID();
- if (empty($fragments[$fragment_phid])) {
- unset($page[$key]);
- continue;
- }
- $version->attachFragment($fragments[$fragment_phid]);
- }
-
- return $page;
- }
-
- public function getQueryApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-}
diff --git a/src/applications/phragment/query/PhragmentSnapshotChildQuery.php b/src/applications/phragment/query/PhragmentSnapshotChildQuery.php
deleted file mode 100644
--- a/src/applications/phragment/query/PhragmentSnapshotChildQuery.php
+++ /dev/null
@@ -1,174 +0,0 @@
-<?php
-
-final class PhragmentSnapshotChildQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
-
- private $ids;
- private $snapshotPHIDs;
- private $fragmentPHIDs;
- private $fragmentVersionPHIDs;
- private $needFragments;
- private $needFragmentVersions;
-
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withSnapshotPHIDs(array $snapshot_phids) {
- $this->snapshotPHIDs = $snapshot_phids;
- return $this;
- }
-
- public function withFragmentPHIDs(array $fragment_phids) {
- $this->fragmentPHIDs = $fragment_phids;
- return $this;
- }
-
- public function withFragmentVersionPHIDs(array $fragment_version_phids) {
- $this->fragmentVersionPHIDs = $fragment_version_phids;
- return $this;
- }
-
- public function needFragments($need_fragments) {
- $this->needFragments = $need_fragments;
- return $this;
- }
-
- public function needFragmentVersions($need_fragment_versions) {
- $this->needFragmentVersions = $need_fragment_versions;
- return $this;
- }
-
- protected function loadPage() {
- $table = new PhragmentSnapshotChild();
- $conn_r = $table->establishConnection('r');
-
- $data = queryfx_all(
- $conn_r,
- 'SELECT * FROM %T %Q %Q %Q',
- $table->getTableName(),
- $this->buildWhereClause($conn_r),
- $this->buildOrderClause($conn_r),
- $this->buildLimitClause($conn_r));
-
- return $table->loadAllFromArray($data);
- }
-
- protected function buildWhereClause(AphrontDatabaseConnection $conn) {
- $where = array();
-
- if ($this->ids) {
- $where[] = qsprintf(
- $conn,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->snapshotPHIDs) {
- $where[] = qsprintf(
- $conn,
- 'snapshotPHID IN (%Ls)',
- $this->snapshotPHIDs);
- }
-
- if ($this->fragmentPHIDs) {
- $where[] = qsprintf(
- $conn,
- 'fragmentPHID IN (%Ls)',
- $this->fragmentPHIDs);
- }
-
- if ($this->fragmentVersionPHIDs) {
- $where[] = qsprintf(
- $conn,
- 'fragmentVersionPHID IN (%Ls)',
- $this->fragmentVersionPHIDs);
- }
-
- $where[] = $this->buildPagingClause($conn);
-
- return $this->formatWhereClause($conn, $where);
- }
-
- protected function willFilterPage(array $page) {
- $snapshots = array();
-
- $snapshot_phids = array_filter(mpull($page, 'getSnapshotPHID'));
- if ($snapshot_phids) {
- $snapshots = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($snapshot_phids)
- ->setParentQuery($this)
- ->execute();
- $snapshots = mpull($snapshots, null, 'getPHID');
- }
-
- foreach ($page as $key => $child) {
- $snapshot_phid = $child->getSnapshotPHID();
- if (empty($snapshots[$snapshot_phid])) {
- unset($page[$key]);
- continue;
- }
- $child->attachSnapshot($snapshots[$snapshot_phid]);
- }
-
- return $page;
- }
-
- protected function didFilterPage(array $page) {
- if ($this->needFragments) {
- $fragments = array();
-
- $fragment_phids = array_filter(mpull($page, 'getFragmentPHID'));
- if ($fragment_phids) {
- $fragments = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($fragment_phids)
- ->setParentQuery($this)
- ->execute();
- $fragments = mpull($fragments, null, 'getPHID');
- }
-
- foreach ($page as $key => $child) {
- $fragment_phid = $child->getFragmentPHID();
- if (empty($fragments[$fragment_phid])) {
- unset($page[$key]);
- continue;
- }
- $child->attachFragment($fragments[$fragment_phid]);
- }
- }
-
- if ($this->needFragmentVersions) {
- $fragment_versions = array();
-
- $fragment_version_phids = array_filter(mpull(
- $page,
- 'getFragmentVersionPHID'));
- if ($fragment_version_phids) {
- $fragment_versions = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($fragment_version_phids)
- ->setParentQuery($this)
- ->execute();
- $fragment_versions = mpull($fragment_versions, null, 'getPHID');
- }
-
- foreach ($page as $key => $child) {
- $fragment_version_phid = $child->getFragmentVersionPHID();
- if (empty($fragment_versions[$fragment_version_phid])) {
- continue;
- }
- $child->attachFragmentVersion(
- $fragment_versions[$fragment_version_phid]);
- }
- }
-
- return $page;
- }
-
- public function getQueryApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-}
diff --git a/src/applications/phragment/query/PhragmentSnapshotQuery.php b/src/applications/phragment/query/PhragmentSnapshotQuery.php
deleted file mode 100644
--- a/src/applications/phragment/query/PhragmentSnapshotQuery.php
+++ /dev/null
@@ -1,111 +0,0 @@
-<?php
-
-final class PhragmentSnapshotQuery
- extends PhabricatorCursorPagedPolicyAwareQuery {
-
- private $ids;
- private $phids;
- private $primaryFragmentPHIDs;
- private $names;
-
- public function withIDs(array $ids) {
- $this->ids = $ids;
- return $this;
- }
-
- public function withPHIDs(array $phids) {
- $this->phids = $phids;
- return $this;
- }
-
- public function withPrimaryFragmentPHIDs(array $primary_fragment_phids) {
- $this->primaryFragmentPHIDs = $primary_fragment_phids;
- return $this;
- }
-
- public function withNames(array $names) {
- $this->names = $names;
- return $this;
- }
-
- protected function loadPage() {
- $table = new PhragmentSnapshot();
- $conn_r = $table->establishConnection('r');
-
- $data = queryfx_all(
- $conn_r,
- 'SELECT * FROM %T %Q %Q %Q',
- $table->getTableName(),
- $this->buildWhereClause($conn_r),
- $this->buildOrderClause($conn_r),
- $this->buildLimitClause($conn_r));
-
- return $table->loadAllFromArray($data);
- }
-
- protected function buildWhereClause(AphrontDatabaseConnection $conn) {
- $where = array();
-
- if ($this->ids !== null) {
- $where[] = qsprintf(
- $conn,
- 'id IN (%Ld)',
- $this->ids);
- }
-
- if ($this->phids !== null) {
- $where[] = qsprintf(
- $conn,
- 'phid IN (%Ls)',
- $this->phids);
- }
-
- if ($this->primaryFragmentPHIDs !== null) {
- $where[] = qsprintf(
- $conn,
- 'primaryFragmentPHID IN (%Ls)',
- $this->primaryFragmentPHIDs);
- }
-
- if ($this->names !== null) {
- $where[] = qsprintf(
- $conn,
- 'name IN (%Ls)',
- $this->names);
- }
-
- $where[] = $this->buildPagingClause($conn);
-
- return $this->formatWhereClause($conn, $where);
- }
-
- protected function willFilterPage(array $page) {
- $fragments = array();
-
- $fragment_phids = array_filter(mpull($page, 'getPrimaryFragmentPHID'));
- if ($fragment_phids) {
- $fragments = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
- ->withPHIDs($fragment_phids)
- ->setParentQuery($this)
- ->execute();
- $fragments = mpull($fragments, null, 'getPHID');
- }
-
- foreach ($page as $key => $snapshot) {
- $fragment_phid = $snapshot->getPrimaryFragmentPHID();
- if (empty($fragments[$fragment_phid])) {
- unset($page[$key]);
- continue;
- }
- $snapshot->attachPrimaryFragment($fragments[$fragment_phid]);
- }
-
- return $page;
- }
-
- public function getQueryApplicationClass() {
- return 'PhabricatorPhragmentApplication';
- }
-
-}
diff --git a/src/applications/phragment/storage/PhragmentDAO.php b/src/applications/phragment/storage/PhragmentDAO.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentDAO.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-abstract class PhragmentDAO extends PhabricatorLiskDAO {
-
- public function getApplicationName() {
- return 'phragment';
- }
-
-}
diff --git a/src/applications/phragment/storage/PhragmentFragment.php b/src/applications/phragment/storage/PhragmentFragment.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentFragment.php
+++ /dev/null
@@ -1,349 +0,0 @@
-<?php
-
-final class PhragmentFragment extends PhragmentDAO
- implements PhabricatorPolicyInterface {
-
- protected $path;
- protected $depth;
- protected $latestVersionPHID;
- protected $viewPolicy;
- protected $editPolicy;
-
- private $latestVersion = self::ATTACHABLE;
- private $file = self::ATTACHABLE;
-
- protected function getConfiguration() {
- return array(
- self::CONFIG_AUX_PHID => true,
- self::CONFIG_COLUMN_SCHEMA => array(
- 'path' => 'text128',
- 'depth' => 'uint32',
- 'latestVersionPHID' => 'phid?',
- ),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_path' => array(
- 'columns' => array('path'),
- 'unique' => true,
- ),
- ),
- ) + parent::getConfiguration();
- }
-
- public function generatePHID() {
- return PhabricatorPHID::generateNewPHID(
- PhragmentFragmentPHIDType::TYPECONST);
- }
-
- public function getURI() {
- return '/phragment/browse/'.$this->getPath();
- }
-
- public function getName() {
- return basename($this->path);
- }
-
- public function getFile() {
- return $this->assertAttached($this->file);
- }
-
- public function attachFile(PhabricatorFile $file) {
- return $this->file = $file;
- }
-
- public function isDirectory() {
- return $this->latestVersionPHID === null;
- }
-
- public function isDeleted() {
- return $this->getLatestVersion()->getFilePHID() === null;
- }
-
- public function getLatestVersion() {
- if ($this->latestVersionPHID === null) {
- return null;
- }
- return $this->assertAttached($this->latestVersion);
- }
-
- public function attachLatestVersion(PhragmentFragmentVersion $version) {
- return $this->latestVersion = $version;
- }
-
-
-/* -( Updating ) --------------------------------------------------------- */
-
-
- /**
- * Create a new fragment from a file.
- */
- public static function createFromFile(
- PhabricatorUser $viewer,
- PhabricatorFile $file = null,
- $path = null,
- $view_policy = null,
- $edit_policy = null) {
-
- $fragment = id(new PhragmentFragment());
- $fragment->setPath($path);
- $fragment->setDepth(count(explode('/', $path)));
- $fragment->setLatestVersionPHID(null);
- $fragment->setViewPolicy($view_policy);
- $fragment->setEditPolicy($edit_policy);
- $fragment->save();
-
- // Directory fragments have no versions associated with them, so we
- // just return the fragment at this point.
- if ($file === null) {
- return $fragment;
- }
-
- if ($file->getMimeType() === 'application/zip') {
- $fragment->updateFromZIP($viewer, $file);
- } else {
- $fragment->updateFromFile($viewer, $file);
- }
-
- return $fragment;
- }
-
-
- /**
- * Set the specified file as the next version for the fragment.
- */
- public function updateFromFile(
- PhabricatorUser $viewer,
- PhabricatorFile $file) {
-
- $existing = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withFragmentPHIDs(array($this->getPHID()))
- ->execute();
- $sequence = count($existing);
-
- $this->openTransaction();
- $version = id(new PhragmentFragmentVersion());
- $version->setSequence($sequence);
- $version->setFragmentPHID($this->getPHID());
- $version->setFilePHID($file->getPHID());
- $version->save();
-
- $this->setLatestVersionPHID($version->getPHID());
- $this->save();
- $this->saveTransaction();
-
- $file->attachToObject($version->getPHID());
- }
-
- /**
- * Apply the specified ZIP archive onto the fragment, removing
- * and creating fragments as needed.
- */
- public function updateFromZIP(
- PhabricatorUser $viewer,
- PhabricatorFile $file) {
-
- if ($file->getMimeType() !== 'application/zip') {
- throw new Exception(
- pht("File must have mimetype '%s'.", 'application/zip'));
- }
-
- // First apply the ZIP as normal.
- $this->updateFromFile($viewer, $file);
-
- // Ensure we have ZIP support.
- $zip = null;
- try {
- $zip = new ZipArchive();
- } catch (Exception $e) {
- // The server doesn't have php5-zip, so we can't do recursive updates.
- return;
- }
-
- $temp = new TempFile();
- Filesystem::writeFile($temp, $file->loadFileData());
- if (!$zip->open($temp)) {
- throw new Exception(pht('Unable to open ZIP.'));
- }
-
- // Get all of the paths and their data from the ZIP.
- $mappings = array();
- for ($i = 0; $i < $zip->numFiles; $i++) {
- $path = trim($zip->getNameIndex($i), '/');
- $stream = $zip->getStream($path);
- $data = null;
- // If the stream is false, then it is a directory entry. We leave
- // $data set to null for directories so we know not to create a
- // version entry for them.
- if ($stream !== false) {
- $data = stream_get_contents($stream);
- fclose($stream);
- }
- $mappings[$path] = $data;
- }
-
- // We need to detect any directories that are in the ZIP folder that
- // aren't explicitly noted in the ZIP. This can happen if the file
- // entries in the ZIP look like:
- //
- // * something/blah.png
- // * something/other.png
- // * test.png
- //
- // Where there is no explicit "something/" entry.
- foreach ($mappings as $path_key => $data) {
- if ($data === null) {
- continue;
- }
- $directory = dirname($path_key);
- while ($directory !== '.') {
- if (!array_key_exists($directory, $mappings)) {
- $mappings[$directory] = null;
- }
- if (dirname($directory) === $directory) {
- // dirname() will not reduce this directory any further; to
- // prevent infinite loop we just break out here.
- break;
- }
- $directory = dirname($directory);
- }
- }
-
- // Adjust the paths relative to this fragment so we can look existing
- // fragments up in the DB.
- $base_path = $this->getPath();
- $paths = array();
- foreach ($mappings as $p => $data) {
- $paths[] = $base_path.'/'.$p;
- }
-
- // FIXME: What happens when a child exists, but the current user
- // can't see it. We're going to create a new child with the exact
- // same path and then bad things will happen.
- $children = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->needLatestVersion(true)
- ->withLeadingPath($this->getPath().'/')
- ->execute();
- $children = mpull($children, null, 'getPath');
-
- // Iterate over the existing fragments.
- foreach ($children as $full_path => $child) {
- $path = substr($full_path, strlen($base_path) + 1);
- if (array_key_exists($path, $mappings)) {
- if ($child->isDirectory() && $mappings[$path] === null) {
- // Don't create a version entry for a directory
- // (unless it's been converted into a file).
- continue;
- }
-
- // The file is being updated.
- $file = PhabricatorFile::newFromFileData(
- $mappings[$path],
- array('name' => basename($path)));
- $child->updateFromFile($viewer, $file);
- } else {
- // The file is being deleted.
- $child->deleteFile($viewer);
- }
- }
-
- // Iterate over the mappings to find new files.
- foreach ($mappings as $path => $data) {
- if (!array_key_exists($base_path.'/'.$path, $children)) {
- // The file is being created. If the data is null,
- // then this is explicitly a directory being created.
- $file = null;
- if ($mappings[$path] !== null) {
- $file = PhabricatorFile::newFromFileData(
- $mappings[$path],
- array('name' => basename($path)));
- }
- self::createFromFile(
- $viewer,
- $file,
- $base_path.'/'.$path,
- $this->getViewPolicy(),
- $this->getEditPolicy());
- }
- }
- }
-
- /**
- * Delete the contents of the specified fragment.
- */
- public function deleteFile(PhabricatorUser $viewer) {
- $existing = id(new PhragmentFragmentVersionQuery())
- ->setViewer($viewer)
- ->withFragmentPHIDs(array($this->getPHID()))
- ->execute();
- $sequence = count($existing);
-
- $this->openTransaction();
- $version = id(new PhragmentFragmentVersion());
- $version->setSequence($sequence);
- $version->setFragmentPHID($this->getPHID());
- $version->setFilePHID(null);
- $version->save();
-
- $this->setLatestVersionPHID($version->getPHID());
- $this->save();
- $this->saveTransaction();
- }
-
-
-/* -( Utility ) ---------------------------------------------------------- */
-
-
- public function getFragmentMappings(
- PhabricatorUser $viewer,
- $base_path) {
-
- $children = id(new PhragmentFragmentQuery())
- ->setViewer($viewer)
- ->needLatestVersion(true)
- ->withLeadingPath($this->getPath().'/')
- ->withDepths(array($this->getDepth() + 1))
- ->execute();
-
- if (count($children) === 0) {
- $path = substr($this->getPath(), strlen($base_path) + 1);
- return array($path => $this);
- } else {
- $mappings = array();
- foreach ($children as $child) {
- $child_mappings = $child->getFragmentMappings(
- $viewer,
- $base_path);
- foreach ($child_mappings as $key => $value) {
- $mappings[$key] = $value;
- }
- }
- return $mappings;
- }
- }
-
-
-/* -( Policy Interface )--------------------------------------------------- */
-
-
- public function getCapabilities() {
- return array(
- PhabricatorPolicyCapability::CAN_VIEW,
- PhabricatorPolicyCapability::CAN_EDIT,
- );
- }
-
- public function getPolicy($capability) {
- switch ($capability) {
- case PhabricatorPolicyCapability::CAN_VIEW:
- return $this->getViewPolicy();
- case PhabricatorPolicyCapability::CAN_EDIT:
- return $this->getEditPolicy();
- }
- }
-
- public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return false;
- }
-
-}
diff --git a/src/applications/phragment/storage/PhragmentFragmentVersion.php b/src/applications/phragment/storage/PhragmentFragmentVersion.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentFragmentVersion.php
+++ /dev/null
@@ -1,72 +0,0 @@
-<?php
-
-final class PhragmentFragmentVersion extends PhragmentDAO
- implements PhabricatorPolicyInterface {
-
- protected $sequence;
- protected $fragmentPHID;
- protected $filePHID;
-
- private $fragment = self::ATTACHABLE;
- private $file = self::ATTACHABLE;
-
- protected function getConfiguration() {
- return array(
- self::CONFIG_AUX_PHID => true,
- self::CONFIG_COLUMN_SCHEMA => array(
- 'sequence' => 'uint32',
- 'filePHID' => 'phid?',
- ),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_version' => array(
- 'columns' => array('fragmentPHID', 'sequence'),
- 'unique' => true,
- ),
- ),
- ) + parent::getConfiguration();
- }
-
- public function generatePHID() {
- return PhabricatorPHID::generateNewPHID(
- PhragmentFragmentVersionPHIDType::TYPECONST);
- }
-
- public function getURI() {
- return '/phragment/version/'.$this->getID().'/';
- }
-
- public function getFragment() {
- return $this->assertAttached($this->fragment);
- }
-
- public function attachFragment(PhragmentFragment $fragment) {
- return $this->fragment = $fragment;
- }
-
- public function getFile() {
- return $this->assertAttached($this->file);
- }
-
- public function attachFile(PhabricatorFile $file) {
- return $this->file = $file;
- }
-
- public function getCapabilities() {
- return array(
- PhabricatorPolicyCapability::CAN_VIEW,
- );
- }
-
- public function getPolicy($capability) {
- return $this->getFragment()->getPolicy($capability);
- }
-
- public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return $this->getFragment()->hasAutomaticCapability($capability, $viewer);
- }
-
- public function describeAutomaticCapability($capability) {
- return $this->getFragment()->describeAutomaticCapability($capability);
- }
-
-}
diff --git a/src/applications/phragment/storage/PhragmentSchemaSpec.php b/src/applications/phragment/storage/PhragmentSchemaSpec.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentSchemaSpec.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-final class PhragmentSchemaSpec extends PhabricatorConfigSchemaSpec {
-
- public function buildSchemata() {
- $this->buildEdgeSchemata(new PhragmentFragment());
- }
-
-}
diff --git a/src/applications/phragment/storage/PhragmentSnapshot.php b/src/applications/phragment/storage/PhragmentSnapshot.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentSnapshot.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-
-final class PhragmentSnapshot extends PhragmentDAO
- implements PhabricatorPolicyInterface {
-
- protected $primaryFragmentPHID;
- protected $name;
-
- private $primaryFragment = self::ATTACHABLE;
-
- protected function getConfiguration() {
- return array(
- self::CONFIG_AUX_PHID => true,
- self::CONFIG_COLUMN_SCHEMA => array(
- 'name' => 'text128',
- ),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_name' => array(
- 'columns' => array('primaryFragmentPHID', 'name'),
- 'unique' => true,
- ),
- ),
- ) + parent::getConfiguration();
- }
-
- public function generatePHID() {
- return PhabricatorPHID::generateNewPHID(
- PhragmentSnapshotPHIDType::TYPECONST);
- }
-
- public function getURI() {
- return '/phragment/snapshot/view/'.$this->getID().'/';
- }
-
- public function getPrimaryFragment() {
- return $this->assertAttached($this->primaryFragment);
- }
-
- public function attachPrimaryFragment(PhragmentFragment $fragment) {
- return $this->primaryFragment = $fragment;
- }
-
- public function delete() {
- $children = id(new PhragmentSnapshotChild())
- ->loadAllWhere('snapshotPHID = %s', $this->getPHID());
- $this->openTransaction();
- foreach ($children as $child) {
- $child->delete();
- }
- $result = parent::delete();
- $this->saveTransaction();
- return $result;
- }
-
-
-/* -( Policy Interface )--------------------------------------------------- */
-
-
- public function getCapabilities() {
- return $this->getPrimaryFragment()->getCapabilities();
- }
-
- public function getPolicy($capability) {
- return $this->getPrimaryFragment()->getPolicy($capability);
- }
-
- public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return $this->getPrimaryFragment()
- ->hasAutomaticCapability($capability, $viewer);
- }
-
- public function describeAutomaticCapability($capability) {
- return $this->getPrimaryFragment()
- ->describeAutomaticCapability($capability);
- }
-}
diff --git a/src/applications/phragment/storage/PhragmentSnapshotChild.php b/src/applications/phragment/storage/PhragmentSnapshotChild.php
deleted file mode 100644
--- a/src/applications/phragment/storage/PhragmentSnapshotChild.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-
-final class PhragmentSnapshotChild extends PhragmentDAO
- implements PhabricatorPolicyInterface {
-
- protected $snapshotPHID;
- protected $fragmentPHID;
- protected $fragmentVersionPHID;
-
- private $snapshot = self::ATTACHABLE;
- private $fragment = self::ATTACHABLE;
- private $fragmentVersion = self::ATTACHABLE;
-
- protected function getConfiguration() {
- return array(
- self::CONFIG_COLUMN_SCHEMA => array(
- 'fragmentVersionPHID' => 'phid?',
- ),
- self::CONFIG_KEY_SCHEMA => array(
- 'key_child' => array(
- 'columns' => array(
- 'snapshotPHID',
- 'fragmentPHID',
- 'fragmentVersionPHID',
- ),
- 'unique' => true,
- ),
- ),
- ) + parent::getConfiguration();
- }
-
- public function getSnapshot() {
- return $this->assertAttached($this->snapshot);
- }
-
- public function attachSnapshot(PhragmentSnapshot $snapshot) {
- return $this->snapshot = $snapshot;
- }
-
- public function getFragment() {
- return $this->assertAttached($this->fragment);
- }
-
- public function attachFragment(PhragmentFragment $fragment) {
- return $this->fragment = $fragment;
- }
-
- public function getFragmentVersion() {
- if ($this->fragmentVersionPHID === null) {
- return null;
- }
- return $this->assertAttached($this->fragmentVersion);
- }
-
- public function attachFragmentVersion(PhragmentFragmentVersion $version) {
- return $this->fragmentVersion = $version;
- }
-
-
-/* -( Policy Interface )--------------------------------------------------- */
-
-
- public function getCapabilities() {
- return array(
- PhabricatorPolicyCapability::CAN_VIEW,
- );
- }
-
- public function getPolicy($capability) {
- return $this->getSnapshot()->getPolicy($capability);
- }
-
- public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- return $this->getSnapshot()
- ->hasAutomaticCapability($capability, $viewer);
- }
-
- public function describeAutomaticCapability($capability) {
- return $this->getSnapshot()
- ->describeAutomaticCapability($capability);
- }
-}
diff --git a/src/applications/phragment/util/PhragmentPatchUtil.php b/src/applications/phragment/util/PhragmentPatchUtil.php
deleted file mode 100644
--- a/src/applications/phragment/util/PhragmentPatchUtil.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-
-final class PhragmentPatchUtil extends Phobject {
-
- const EMPTY_HASH = '0000000000000000000000000000000000000000';
-
- /**
- * Calculate the DiffMatchPatch patch between two Phabricator files.
- *
- * @phutil-external-symbol class diff_match_patch
- */
- public static function calculatePatch(
- PhabricatorFile $old = null,
- PhabricatorFile $new = null) {
-
- $root = dirname(phutil_get_library_root('phabricator'));
- require_once $root.'/externals/diff_match_patch/diff_match_patch.php';
-
- $old_hash = self::EMPTY_HASH;
- $new_hash = self::EMPTY_HASH;
-
- if ($old !== null) {
- $old_hash = $old->getContentHash();
- }
- if ($new !== null) {
- $new_hash = $new->getContentHash();
- }
-
- $old_content = '';
- $new_content = '';
-
- if ($old_hash === $new_hash) {
- return null;
- }
-
- if ($old_hash !== self::EMPTY_HASH) {
- $old_content = $old->loadFileData();
- } else {
- $old_content = '';
- }
-
- if ($new_hash !== self::EMPTY_HASH) {
- $new_content = $new->loadFileData();
- } else {
- $new_content = '';
- }
-
- $dmp = new diff_match_patch();
- $dmp_patches = $dmp->patch_make($old_content, $new_content);
- return $dmp->patch_toText($dmp_patches);
- }
-
-}
diff --git a/src/docs/book/phabricator.book b/src/docs/book/phabricator.book
--- a/src/docs/book/phabricator.book
+++ b/src/docs/book/phabricator.book
@@ -244,10 +244,6 @@
"name": "PHPAST",
"include": "(^src/applications/phpast/)"
},
- "phragment": {
- "name": "Phragment",
- "include": "(^src/applications/phragment/)"
- },
"phrequent": {
"name": "Phrequent",
"include": "(^src/applications/phrequent/)"
diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
--- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
+++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
@@ -103,7 +103,6 @@
'db.policy' => array(),
'db.nuance' => array(),
'db.passphrase' => array(),
- 'db.phragment' => array(),
'db.dashboard' => array(),
'db.system' => array(),
'db.fund' => array(),

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 3:46 PM (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6273157
Default Alt Text
D21793.diff (195 KB)

Event Timeline