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 @@ -398,6 +398,7 @@ 'ArcanistVariableVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableVariableXHPASTLinterRule.php', 'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableVariableXHPASTLinterRuleTestCase.php', 'ArcanistVersionWorkflow' => 'workflow/ArcanistVersionWorkflow.php', + 'ArcanistWeldWorkflow' => 'workflow/ArcanistWeldWorkflow.php', 'ArcanistWhichWorkflow' => 'workflow/ArcanistWhichWorkflow.php', 'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php', 'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php', @@ -816,6 +817,7 @@ 'ArcanistVariableVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistVersionWorkflow' => 'ArcanistWorkflow', + 'ArcanistWeldWorkflow' => 'ArcanistWorkflow', 'ArcanistWhichWorkflow' => 'ArcanistWorkflow', 'ArcanistWorkflow' => 'Phobject', 'ArcanistWorkingCopyIdentity' => 'Phobject', diff --git a/src/workflow/ArcanistWeldWorkflow.php b/src/workflow/ArcanistWeldWorkflow.php new file mode 100644 --- /dev/null +++ b/src/workflow/ArcanistWeldWorkflow.php @@ -0,0 +1,133 @@ + 'files', + ); + } + + public function run() { + $files = $this->getArgument('files'); + if (count($files) < 2) { + throw new ArcanistUsageException( + pht('Specify two or more files to weld together.')); + } + + $buffer = array(); + foreach ($files as $file) { + $data = Filesystem::readFile($file); + if (!strlen($data)) { + continue; + } + $lines = phutil_split_lines($data, true); + + $overlap = mt_rand(16, 32); + + if (count($buffer) > 6) { + $overlap = min($overlap, ceil(count($buffer) / 2)); + } + + if (count($lines) > 6) { + $overlap = min($overlap, ceil(count($lines) / 2)); + } + + $overlap = min($overlap, count($buffer)); + $overlap = min($overlap, count($lines)); + + $buffer_len = count($buffer); + for ($ii = 0; $ii < $overlap; $ii++) { + $buffer[$buffer_len - $overlap + $ii] = $this->weldLines( + $buffer[$buffer_len - $overlap + $ii], + $lines[$ii], + ($ii + 0.5) / $overlap); + } + + for ($ii = $overlap; $ii < count($lines); $ii++) { + $buffer[] = $lines[$ii]; + } + } + + echo implode('', $buffer); + } + + private function weldLines($u, $v, $bias) { + $newline = null; + $matches = null; + + if (preg_match('/([\r\n]+)\z/', $u, $matches)) { + $newline = $matches[1]; + } + + if (preg_match('/([\r\n]+)\z/', $v, $matches)) { + $newline = $matches[1]; + } + + $u = rtrim($u, "\r\n"); + $v = rtrim($v, "\r\n"); + + $u = phutil_utf8v_combined($u); + $v = phutil_utf8v_combined($v); + + $len = max(count($u), count($v)); + + while (count($u) < $len) { + $u[] = ' '; + } + while (count($v) < $len) { + $v[] = ' '; + } + + $rand_max = mt_getrandmax(); + + $result = array(); + for ($ii = 0; $ii < $len; $ii++) { + $uc = $u[$ii]; + $vc = $v[$ii]; + + $threshold = $bias; + if ($uc == ' ') { + $threshold = 1; + } + + if ($vc == ' ') { + $threshold = 0; + } + + if ((mt_rand() / $rand_max) > $threshold) { + $r = $uc; + } else { + $r = $vc; + } + + $result[] = $r; + } + + if ($newline !== null) { + $result[] = $newline; + } + + return implode('', $result); + } + +}