/** * Start an benchmarking timer. * * @param string $name The name of the timer to start. * @param string $message A message for your timer * @return bool Always true */ public static function start($name = null, $message = null) { $start = microtime(true); if (!$name) { $named = false; $calledFrom = debug_backtrace(); $name = Debugger::trimPath($calledFrom[0]['file']) . ' line ' . $calledFrom[0]['line']; } else { $named = true; } if (!$message) { $message = $name; } $_name = $name; $i = 1; while (isset(self::$_timers[$name])) { $i++; $name = $_name . ' #' . $i; } if ($i > 1) { $message .= ' #' . $i; } self::$_timers[$name] = ['start' => $start, 'message' => $message, 'named' => $named]; return true; }
/** * Make tasks callable * * @return void */ public function main() { if (!empty($this->params['dry-run'])) { $this->out('<warning>Dry-run mode enabled!</warning>', 1, Shell::QUIET); } $exclude = ['.git', '.svn', 'vendor', 'Vendor', 'webroot', 'tmp', 'logs']; if (empty($this->params['plugin']) && !empty($this->params['namespace']) && $this->params['namespace'] === 'App') { $exclude[] = 'plugins'; $exclude[] = 'Plugin'; } $files = $this->Stage->files($exclude); foreach ($files as $file) { $this->out(sprintf('<info>Processing %s</info>', Debugger::trimPath($file))); $this->process($file); } $this->Stage->commit(); }
/** * Stores a memory point in the internal tracker. * Takes a optional message name which can be used to identify the memory point. * If no message is supplied a debug_backtrace will be done to identify the memory point. * * @param string $message Message to identify this memory point. * @return bool */ public static function record($message = null) { $memoryUse = self::getCurrent(); if (!$message) { $trace = debug_backtrace(); $message = Debugger::trimPath($trace[0]['file']) . ' line ' . $trace[0]['line']; } if (isset(self::$_points[$message])) { $originalMessage = $message; $i = 1; while (isset(self::$_points[$message])) { $i++; $message = $originalMessage . ' #' . $i; } } self::$_points[$message] = $memoryUse; return true; }
/** * All command. * * @return void */ public function all() { if (!empty($this->params['dry-run'])) { $this->out('<warning>Dry-run mode enabled!</warning>', 1, Shell::QUIET); } $exclude = ['.git', '.svn', 'vendor', 'Vendor', 'webroot', 'tmp', 'logs']; if (empty($this->params['plugin']) && !empty($this->params['namespace']) && $this->params['namespace'] === 'App') { $exclude[] = 'plugins'; $exclude[] = 'Plugin'; } $files = $this->Stage->files($exclude); $actions = $this->_getActions(); foreach ($actions as $action) { $this->out(sprintf('<info>*** Upgrade step %s ***</info>', $action)); if (!empty($this->params['interactive'])) { $continue = $this->in('Continue with `' . $action . '`?', array('y', 'n', 'q'), 'y'); if ($continue === 'q') { return $this->error('Aborted. Changes are not commited.'); } if ($continue === 'n') { $this->out('Skipping this step.'); continue; } } foreach ($files as $file) { $this->out(sprintf('<info> * Processing %s</info>', Debugger::trimPath($file)), 1, Shell::VERBOSE); $this->{$action}->Stage = $this->Stage; $this->{$action}->process($file); if (!empty($this->params['interactive'])) { $this->Stage->commit(); $this->Stage->clear(); } } } if (empty($this->params['interactive'])) { $this->Stage->commit(); } }
/** * Set as the default error handler by CakePHP. * * Use config/error.php to customize or replace this error handler. * This function will use Debugger to display errors when debug > 0. And * will log errors to Log, when debug == 0. * * You can use the 'errorLevel' option to set what type of errors will be handled. * Stack traces for errors can be enabled with the 'trace' option. * * @param int $code Code of error * @param string $description Error description * @param string|null $file File on which error occurred * @param int|null $line Line that triggered the error * @param array|null $context Context * @return bool True if error was handled */ public function handleError($code, $description, $file = null, $line = null, $context = null) { if (error_reporting() === 0) { return false; } list($error, $log) = $this->mapErrorCode($code); if ($log === LOG_ERR) { return $this->handleFatalError($code, $description, $file, $line); } $data = ['level' => $log, 'code' => $code, 'error' => $error, 'description' => $description, 'file' => $file, 'line' => $line]; $debug = Configure::read('debug'); if ($debug) { $data += ['context' => $context, 'start' => 3, 'path' => Debugger::trimPath($file)]; } $this->_displayError($data, $debug); $this->_logError($log, $data); return true; }
/** * testTrimPath method * * @return void */ public function testTrimPath() { $this->assertEquals('APP/', Debugger::trimPath(APP)); $this->assertEquals('CORE' . DS . 'src' . DS, Debugger::trimPath(CAKE)); $this->assertEquals('Some/Other/Path', Debugger::trimPath('Some/Other/Path')); }
/** * Assert that nested anonymous timers don't get mixed up. * * @return void */ public function testNestedAnonymousTimers() { $this->assertTrue(DebugTimer::start()); usleep(100); $this->assertTrue(DebugTimer::start()); usleep(100); $this->assertTrue(DebugTimer::stop()); $this->assertTrue(DebugTimer::stop()); $timers = DebugTimer::getAll(); $this->assertEquals(3, count($timers), 'incorrect number of timers %s'); $firstTimerLine = __LINE__ - 9; $secondTimerLine = __LINE__ - 8; $file = Debugger::trimPath(__FILE__); $this->assertTrue(isset($timers[$file . ' line ' . $firstTimerLine]), 'first timer is not set %s'); $this->assertTrue(isset($timers[$file . ' line ' . $secondTimerLine]), 'second timer is not set %s'); $firstTimer = $timers[$file . ' line ' . $firstTimerLine]; $secondTimer = $timers[$file . ' line ' . $secondTimerLine]; $this->assertTrue($firstTimer['time'] > $secondTimer['time']); }
/** * Write staged changes * * If it's a dry run though - only show what will be done, don't do anything * * @param string $path file path * @return void */ public function commit($path = null) { if (!$path) { foreach (array_keys($this->_staged['change']) as $path) { $this->commit($path); } foreach ($this->_staged['move'] as $path => $to) { if (isset($this->_staged['change'][$path])) { continue; } $this->commit($path); } foreach ($this->_staged['delete'] as $path) { $this->commit($path); } $Folder = new Folder(TMP . 'upgrade'); $Folder->delete(); return; } $dryRun = !empty($this->params['dry-run']); $isMove = isset($this->_staged['move'][$path]); $isChanged = isset($this->_staged['change'][$path]) && count($this->_staged['change'][$path]) > 1; $isDelete = in_array($path, $this->_staged['delete']); if (!$isMove && !$isChanged && !$isDelete) { return; } $gitCd = sprintf('cd %s && ', escapeshellarg(dirname($path))); if ($isDelete) { $this->out(sprintf('<info>Delete %s</info>', Debugger::trimPath($path))); if ($dryRun) { return true; } if (!empty($this->params['git'])) { exec($gitCd . sprintf('git rm -f %s', escapeshellarg($path))); return; } if (is_dir($path)) { $Folder = new Folder($path); return $Folder->delete(); } $File = new File($path, true); return $File->delete(); } if ($isMove && !$isChanged) { $to = $this->_staged['move'][$path]; $this->out(sprintf('<info>Move %s to %s</info>', Debugger::trimPath($path), Debugger::trimPath($to))); if ($dryRun || !file_exists($path)) { return true; } if (!empty($this->params['git'])) { return $this->_gitMove($gitCd, $path, $to); } if (is_dir($path)) { $Folder = new Folder($path); return $Folder->move($to); } $File = new File($to, true); return $File->write(file_get_contents($path)) && unlink($path); } $start = reset($this->_staged['change'][$path]); end($this->_staged['change'][$path]); $final = end($this->_staged['change'][$path]); $oPath = TMP . 'upgrade' . DS . $start; $uPath = TMP . 'upgrade' . DS . $final; exec('git diff --no-index ' . escapeshellarg($oPath) . ' ' . escapeshellarg($uPath), $output); $output = implode($output, "\n"); $i = strrpos($output, $final); $diff = substr($output, $i + 41); if ($isMove) { $to = $this->_staged['move'][$path]; $this->out(sprintf('<info>Move %s to %s and update</info>', Debugger::trimPath($path), Debugger::trimPath($to))); } else { $this->out(sprintf('<info>Update %s</info>', Debugger::trimPath($path))); } $this->out($diff, 1, $dryRun ? Shell::NORMAL : SHELL::VERBOSE); if ($dryRun || !file_exists($path)) { return true; } if ($isMove) { if (!empty($this->params['git'])) { $this->_gitMove($gitCd, $path, $to); } else { unlink($path); } $path = $to; } $File = new File($path, true); return $File->write(file_get_contents($uPath)); }