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 @@ ->} 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 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.>} 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.>} diffs Array of diff tuples. - * @param {Array.} 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 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.} 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 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.} 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 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.?} 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.?} 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.>} 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 cat came. -> The cat came. - * @param {Array.>} 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.>} 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: - * ABXYCD - * AXCD - * ABXC - * AXCD - * ABXC - */ - 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.>} 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: ABAC -> ABAC - $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.>} 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.>} 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 ( - '&', - '<', - '>', - '¶
' - ), $data); - - switch ($op) { - case DIFF_INSERT : - $html[$x] = '' . $text . ''; - break; - case DIFF_DELETE : - $html[$x] = '' . $text . ''; - break; - case DIFF_EQUAL : - $html[$x] = '' . $text . ''; - break; - } - if ($op !== DIFF_DELETE) { - $i += mb_strlen($data); - } - } - return implode('',$html); - } - - /** - * Compute and return the source text (all equalities and deletions). - * @param {Array.>} 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.>} 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.>} 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.>} 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 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.>} a text1 (methods 1,3,4) or - * Array of diff tuples for text1 to text2 (method 2). - * @param {string|Array.>} opt_b text2 (methods 1,4) or - * Array of diff tuples for text1 to text2 (method 3) or undefined (method 2). - * @param {string|Array.>} opt_c Array of diff tuples for - * text1 to text2 (method 4) or undefined (methods 1,2,3). - * @return {Array.} 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.} patches Array of patch objects. - * @return {Array.} 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.} patches Array of patch objects. - * @param {string} text Old text. - * @return {Array.>} 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.} 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.} 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.} 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.} 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.>} */ - 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 @@ -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 @@ - array( - '' => 'PhragmentBrowseController', - 'browse/(?P.*)' => 'PhragmentBrowseController', - 'create/(?P.*)' => 'PhragmentCreateController', - 'update/(?P.+)' => 'PhragmentUpdateController', - 'policy/(?P.+)' => 'PhragmentPolicyController', - 'history/(?P.+)' => 'PhragmentHistoryController', - 'zip/(?P.+)' => 'PhragmentZIPController', - 'zip@(?P[^/]+)/(?P.+)' => 'PhragmentZIPController', - 'version/(?P[0-9]*)/' => 'PhragmentVersionController', - 'patch/(?P[0-9x]*)/(?P[0-9]*)/' => 'PhragmentPatchController', - 'revert/(?P[0-9]*)/(?P.*)' => 'PhragmentRevertController', - 'snapshot/' => array( - 'create/(?P.*)' => 'PhragmentSnapshotCreateController', - 'view/(?P[0-9]*)/' => 'PhragmentSnapshotViewController', - 'delete/(?P[0-9]*)/' => 'PhragmentSnapshotDeleteController', - 'promote/' => array( - 'latest/(?P.*)' => 'PhragmentSnapshotPromoteController', - '(?P[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 @@ - 'required string', - 'state' => 'required dict', - ); - } - - 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 @@ - 'required list', - ); - } - - 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ - 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 @@ - 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 @@ -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 @@ - 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 @@ - 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 @@ -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(),