diff --git a/src/Exception/CommandException.php b/src/Exception/CommandException.php new file mode 100644 index 0000000..c913db0 --- /dev/null +++ b/src/Exception/CommandException.php @@ -0,0 +1,98 @@ + + */ +class CommandException extends TaskwarriorException +{ + /** + * @var string + */ + private $command; + + /** + * @var int + */ + private $exitCode; + + /** + * @var string + */ + private $output; + + /** + * @var string + */ + private $errorOutput; + + /** + * @param Process $process + */ + public function __construct(Process $process) + { + $this->command = $process->getCommandLine(); + $this->exitCode = $process->getExitCode(); + $this->output = $process->getOutput(); + $this->errorOutput = $process->getErrorOutput(); + + if (!$message = $this->getCleanErrorOutput()) { + $message = $this->output; + } + + parent::__construct($message, $this->getExitCode()); + } + + /** + * @return string + */ + public function getCommand() + { + return $this->command; + } + + /** + * @return int + */ + public function getExitCode() + { + return $this->exitCode; + } + + /** + * @return string + */ + public function getOutput() + { + return $this->output; + } + + /** + * @return string + */ + public function getErrorOutput() + { + return $this->errorOutput; + } + + /** + * @return string + */ + public function getCleanErrorOutput() + { + $message = ''; + + foreach (explode("\n", $this->errorOutput) as $line) { + if (strpos($line, 'Using alternate') === 0 || strpos($line, 'Configuration override') === 0) { + continue; + } + + $message .= $line . "\n"; + } + + return trim($message); + } +} \ No newline at end of file diff --git a/src/Exception/DatetimeParseException.php b/src/Exception/DatetimeParseException.php new file mode 100644 index 0000000..6994253 --- /dev/null +++ b/src/Exception/DatetimeParseException.php @@ -0,0 +1,10 @@ + + */ +class DatetimeParseException extends TaskwarriorException +{ +} \ No newline at end of file diff --git a/src/Exception/RecurringParseException.php b/src/Exception/RecurringParseException.php new file mode 100644 index 0000000..ce5789f --- /dev/null +++ b/src/Exception/RecurringParseException.php @@ -0,0 +1,10 @@ + + */ +class RecurringParseException extends TaskwarriorException +{ +} \ No newline at end of file diff --git a/src/Exception/TaskwarriorException.php b/src/Exception/TaskwarriorException.php new file mode 100644 index 0000000..f9c37ec --- /dev/null +++ b/src/Exception/TaskwarriorException.php @@ -0,0 +1,10 @@ + + */ +class TaskwarriorException extends \Exception +{ +} \ No newline at end of file diff --git a/src/Recurring.php b/src/Recurring.php index d7dd8c5..d52825f 100644 --- a/src/Recurring.php +++ b/src/Recurring.php @@ -5,21 +5,23 @@ namespace DavidBadura\Taskwarrior; +use DavidBadura\Taskwarrior\Exception\RecurringParseException; + /** * @author David Badura */ class Recurring { - const DAILY = 'daily'; - const WEEKDAYS = 'weekdays'; - const WEEKLY = 'weekly'; - const BIWEEKLY = 'biweekly'; - const QUARTERLY = 'quarterly'; + const DAILY = 'daily'; + const WEEKDAYS = 'weekdays'; + const WEEKLY = 'weekly'; + const BIWEEKLY = 'biweekly'; + const QUARTERLY = 'quarterly'; const SEMIANNUAL = 'semiannual'; - const ANNUAL = 'annual'; - const YEARLY = 'yearly'; - const BIANNUAL = 'biannual'; - const BIYEARLY = 'biyearly'; + const ANNUAL = 'annual'; + const YEARLY = 'yearly'; + const BIANNUAL = 'biannual'; + const BIYEARLY = 'biyearly'; /** * @var string @@ -28,15 +30,15 @@ class Recurring /** * @param string $recurring - * @throws TaskwarriorException + * @throws RecurringParseException */ public function __construct($recurring) { - if (self::isValid($recurring)) { - $this->recurring = $recurring; - } else { - throw new TaskwarriorException(); + if (!self::isValid($recurring)) { + throw new RecurringParseException(sprintf('recurring "%s" is not valid', $recurring)); } + + $this->recurring = $recurring; } /** @@ -61,7 +63,7 @@ class Recurring */ public static function isValid($recur) { - $refClass = new \ReflectionClass(__CLASS__); + $refClass = new \ReflectionClass(__CLASS__); $constants = $refClass->getConstants(); if (in_array($recur, $constants)) { diff --git a/src/Task.php b/src/Task.php index cd3717a..edcd274 100644 --- a/src/Task.php +++ b/src/Task.php @@ -3,6 +3,7 @@ namespace DavidBadura\Taskwarrior; use Carbon\Carbon; +use DavidBadura\Taskwarrior\Exception\DatetimeParseException; use JMS\Serializer\Annotation as JMS; /** @@ -381,7 +382,7 @@ class Task /** * @param string|\DateTime|null $date * @return \DateTime|null - * @throws TaskwarriorException + * @throws DatetimeParseException */ private function parseDateTime($date) { @@ -404,7 +405,7 @@ class Task return null; } - throw new TaskwarriorException(); + throw new DatetimeParseException($date); } /** diff --git a/src/TaskManager.php b/src/TaskManager.php index 8e60a6f..8c1130f 100644 --- a/src/TaskManager.php +++ b/src/TaskManager.php @@ -2,13 +2,14 @@ namespace DavidBadura\Taskwarrior; +use Carbon\Carbon; +use DavidBadura\Taskwarrior\Exception\TaskwarriorException; use DavidBadura\Taskwarrior\Serializer\Handler\CarbonHandler; use DavidBadura\Taskwarrior\Serializer\Handler\RecurringHandler; use JMS\Serializer\Handler\HandlerRegistryInterface; use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; -use JMS\Serializer\SerializationContext; use JMS\Serializer\Serializer; use JMS\Serializer\SerializerBuilder; @@ -133,8 +134,13 @@ class TaskManager return; } - $this->taskwarrior->delete($task->getUuid()); - $this->refresh($task); + if ($task->isRecurring()) { + $task->setUntil('now'); + $this->save($task); + } else { + $this->taskwarrior->delete($task->getUuid()); + $this->refresh($task); + } } /** diff --git a/src/Taskwarrior.php b/src/Taskwarrior.php index c910e06..f1d711b 100644 --- a/src/Taskwarrior.php +++ b/src/Taskwarrior.php @@ -2,7 +2,8 @@ namespace DavidBadura\Taskwarrior; -use JMS\Serializer\SerializerBuilder; +use DavidBadura\Taskwarrior\Exception\CommandException; +use DavidBadura\Taskwarrior\Exception\TaskwarriorException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Process\ProcessBuilder; @@ -57,7 +58,6 @@ class Taskwarrior /** * @param array $params - * @throws TaskwarriorException */ public function add(array $params) { @@ -76,7 +76,6 @@ class Taskwarrior /** * @param null $filter * @return array - * @throws TaskwarriorException */ public function projects($filter = null) { @@ -88,7 +87,6 @@ class Taskwarrior /** * @param null $filter * @return array - * @throws TaskwarriorException */ public function tags($filter = null) { @@ -104,6 +102,7 @@ class Taskwarrior /** * @param string $json * @return string + * @throws CommandException * @throws TaskwarriorException */ public function import($json) @@ -175,11 +174,7 @@ class Taskwarrior $process->run(); if (!$process->isSuccessful()) { - throw new TaskwarriorException( - $this->extractErrorMessage($process->getErrorOutput()), - $process->getExitCode(), - $process->getCommandLine() - ); + throw new CommandException($process); } return $process->getOutput(); @@ -187,7 +182,6 @@ class Taskwarrior /** * @return string - * @throws TaskwarriorException */ public function version() { @@ -266,25 +260,6 @@ class Taskwarrior return $builder; } - /** - * @param string $string - * @return string - */ - private function extractErrorMessage($string) - { - $message = ''; - - foreach (explode("\n", $string) as $line) { - if (strpos($line, 'Using alternate') === 0 || strpos($line, 'Configuration override') === 0) { - continue; - } - - $message .= $line . "\n"; - } - - return trim($message); - } - /** * @param string $string * @return array diff --git a/src/TaskwarriorException.php b/src/TaskwarriorException.php deleted file mode 100644 index 157fd25..0000000 --- a/src/TaskwarriorException.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -class TaskwarriorException extends \Exception -{ - /** - * @var string - */ - private $command; - - /** - * @param string $message - * @param int $code - * @param string $command - */ - public function __construct($message = "", $code = 0, $command = '') - { - parent::__construct($message, $code, null); - } - - /** - * @return string - */ - public function getCommand() - { - return $this->command; - } -} \ No newline at end of file diff --git a/tests/RecurringTest.php b/tests/RecurringTest.php index c8663ee..a692396 100644 --- a/tests/RecurringTest.php +++ b/tests/RecurringTest.php @@ -67,7 +67,7 @@ class RecurringTest extends \PHPUnit_Framework_TestCase */ public function testInvalid($recur) { - $this->setExpectedException('DavidBadura\Taskwarrior\TaskwarriorException'); + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\RecurringParseException'); $obj = new Recurring($recur); } diff --git a/tests/TaskManagerTest.php b/tests/TaskManagerTest.php index 11534ae..61aad8b 100644 --- a/tests/TaskManagerTest.php +++ b/tests/TaskManagerTest.php @@ -61,7 +61,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase public function testSaveTaskWithoutDescription() { - $this->setExpectedException('DavidBadura\Taskwarrior\TaskwarriorException'); + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException'); $task = new Task(); @@ -547,7 +547,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase public function testRecurringRemoveRecurringException() { - $this->setExpectedException('DavidBadura\Taskwarrior\TaskwarriorException', + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException', 'You cannot remove the recurrence from a recurring task.'); $task1 = new Task(); @@ -564,7 +564,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase public function testRecurringRemoveDueException() { - $this->setExpectedException('DavidBadura\Taskwarrior\TaskwarriorException', + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException', 'You cannot remove the due date from a recurring task.'); $task1 = new Task(); @@ -581,7 +581,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase public function testRecurringWithoutDue() { - $this->setExpectedException('DavidBadura\Taskwarrior\TaskwarriorException', + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException', "A recurring task must also have a 'due' date."); $task1 = new Task(); @@ -629,6 +629,29 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->assertEquals($recur2, $task1->getRecurring()); } + public function testRecurringDelete() + { + $this->markTestIncomplete('not working yet'); + + $recur1 = new Recurring(Recurring::DAILY); + + $task1 = new Task(); + $task1->setDescription('foo1'); + $task1->setDue('tomorrow'); + $task1->setRecurring($recur1); + + $this->taskManager->save($task1); + $this->taskManager->clear(); + + $this->assertCount(1, $this->taskManager->filterAll('status:recurring')); + + $this->taskManager->delete($task1); + + $this->taskManager->clear(); + + $this->assertCount(0, $this->taskManager->filterAll('status:recurring')); + } + public function testUntil() { $task1 = new Task();