mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-06-26 10:54:28 +02:00
CmdStart: Honor the :adjust flag when overwriting a currently open interval
Move the adjustment of a new open interval that is enclosed by the current open interval into the validation processing, where the other overlap resolution takes place. This will allow the start command to honor the :adjust flag when starting a new interval that predates the current open interval. Closes #326 Signed-off-by: Shaun Ruffell <sruffell@sruffell.net> Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
This commit is contained in:
parent
1c1066ae6c
commit
cc82f468e1
3 changed files with 43 additions and 57 deletions
|
@ -38,83 +38,47 @@ int CmdStart (
|
|||
auto verbose = rules.getBoolean ("verbose");
|
||||
const Datetime now {};
|
||||
|
||||
auto filter = cli.getFilter ({now, 0});
|
||||
auto interval = cli.getFilter ({now, 0});
|
||||
|
||||
if (filter.start > now)
|
||||
if (interval.start > now)
|
||||
{
|
||||
throw std::string ("Time tracking cannot be set in the future.");
|
||||
}
|
||||
else if (!filter.is_started ())
|
||||
else if (!interval.is_started ())
|
||||
{
|
||||
// The :all hint provides a filter that is neither started nor ended, which
|
||||
// the start command cannot handle and we do not want to auto start it now.
|
||||
throw std::string ("Interval start must be specified");
|
||||
}
|
||||
else if (interval.is_ended ())
|
||||
{
|
||||
return CmdTrack (cli, rules, database, journal);
|
||||
}
|
||||
|
||||
auto latest = getLatestInterval (database);
|
||||
|
||||
journal.startTransaction ();
|
||||
|
||||
// If the latest interval is open, close it.
|
||||
if (latest.is_open ())
|
||||
{
|
||||
// If the new interval tags match those of the currently open interval, then
|
||||
// do nothing - the tags are already being tracked.
|
||||
if (latest.encloses (filter) && latest.tags () == filter.tags ())
|
||||
if (latest.encloses (interval) && latest.tags () == interval.tags ())
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
std::cout << intervalSummarize (database, rules, latest);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stop it, at the given start time, if applicable.
|
||||
Interval modified {latest};
|
||||
if (filter.start.toEpoch () != 0)
|
||||
{
|
||||
if (modified.start >= filter.start)
|
||||
{
|
||||
throw std::string ("The end of a date range must be after the start.");
|
||||
}
|
||||
|
||||
modified.end = filter.start;
|
||||
}
|
||||
else
|
||||
{
|
||||
modified.end = Datetime ();
|
||||
}
|
||||
|
||||
// Update database.
|
||||
database.deleteInterval (latest);
|
||||
validate (cli, rules, database, modified);
|
||||
|
||||
for (auto& interval : flatten (modified, getAllExclusions (rules, modified)))
|
||||
{
|
||||
journal.startTransaction ();
|
||||
validate (cli, rules, database, interval);
|
||||
database.addInterval (interval, verbose);
|
||||
journal.endTransaction ();
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
std::cout << intervalSummarize (database, rules, interval);
|
||||
}
|
||||
}
|
||||
|
||||
// Now add the new open interval.
|
||||
Interval started;
|
||||
if (filter.start.toEpoch () != 0)
|
||||
started.start = filter.start;
|
||||
else
|
||||
started.start = Datetime ();
|
||||
|
||||
for (auto& tag : filter.tags ())
|
||||
started.tag (tag);
|
||||
|
||||
// Update database. An open interval does not need to be flattened.
|
||||
validate (cli, rules, database, started);
|
||||
database.addInterval (started, verbose);
|
||||
|
||||
if (verbose)
|
||||
std::cout << intervalSummarize (database, rules, started);
|
||||
|
||||
journal.endTransaction ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -99,6 +99,23 @@ static void autoAdjust (
|
|||
{
|
||||
const bool verbose = rules.getBoolean ("verbose");
|
||||
|
||||
// We do not need the adjust flag set to "flatten" the database if the last
|
||||
// interval is open and encloses the current interval that we're adding.
|
||||
Interval latest = getLatestInterval (database);
|
||||
if (interval.is_open () && latest.encloses (interval))
|
||||
{
|
||||
database.deleteInterval (latest);
|
||||
latest.end = interval.start;
|
||||
for (auto& interval : flatten (latest, getAllExclusions (rules, latest)))
|
||||
{
|
||||
database.addInterval (interval, verbose);
|
||||
if (verbose)
|
||||
{
|
||||
std::cout << intervalSummarize (database, rules, interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Interval overlaps_filter {interval.start, interval.end};
|
||||
auto overlaps = getTracked (database, rules, overlaps_filter);
|
||||
|
||||
|
|
13
test/start.t
13
test/start.t
|
@ -27,11 +27,10 @@
|
|||
###############################################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
import sys
|
||||
|
||||
# Ensure python finds the local simpletap module
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
@ -102,7 +101,7 @@ class TestStart(TestCase):
|
|||
|
||||
code, out, err = self.t.runError("start BAR 1h ago")
|
||||
|
||||
self.assertIn("The end of a date range must be after the start.", err)
|
||||
self.assertIn("You cannot overlap intervals. Correct the start/end time, or specify the :adjust hint.", err)
|
||||
|
||||
def test_start_with_start_date_earlier_than_closed_interval(self):
|
||||
"""Test start with start date earlier than closed interval"""
|
||||
|
@ -261,12 +260,18 @@ class TestStart(TestCase):
|
|||
"""Start will not silently fail when tags are the same and time is earlier"""
|
||||
self.t("start 1h ago proja")
|
||||
code, out, err = self.t.runError("start 2h ago proja")
|
||||
self.assertIn("The end of a date range must be after the start.", err)
|
||||
self.assertIn("You cannot overlap intervals. Correct the start/end time, or specify the :adjust hint", err)
|
||||
|
||||
def test_start_will_error_with_all_hint(self):
|
||||
"""Start will return an error when passed the :all hint"""
|
||||
code, out, err = self.t.runError("start :all proja")
|
||||
|
||||
def test_start_with_start_date_earlier_than_closed_interval_with_adjust(self):
|
||||
"""Start will honor the :adjust hint when overlapping an open interval"""
|
||||
self.t("start 1h ago proja")
|
||||
code, out, err = self.t("start 2h ago proja :adjust")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from simpletap import TAPTestRunner
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue