Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15289409
D21793.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
195 KB
Referenced Files
None
Subscribers
None
D21793.diff
View Options
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 (
- '&',
- '<',
- '>',
- '¶<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
Details
Attached
Mime Type
text/plain
Expires
Wed, Mar 5, 9:49 PM (1 w, 23 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7227508
Default Alt Text
D21793.diff (195 KB)
Attached To
Mode
D21793: Remove the "Phragment" application
Attached
Detach File
Event Timeline
Log In to Comment