Commit graph

1705 commits

Author SHA1 Message Date
Thomas Lauf
422e49bacb Extract function getDomReferences and move it to CLI
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-05-10 21:44:30 +02:00
Shaun Ruffell
29cc9e8a0a Fix another place where json::parse() result was leaked
Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-05-10 21:33:31 +02:00
Shaun Ruffell
42ede4104c Remove naked pointer in initializeTagDatabase
The json::object pointer was allocated in the parse function but never
freed.

The way timwarrior is used currently, this leak does not cause any
problems, but...

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-05-10 21:33:31 +02:00
Shaun Ruffell
85d991704b Speed up deserialization of Intervals
When the Lexer breaks a line into tokens, it also wants to return the
type of the token. This information isn't used by the IntervalFactory
and it slows down the operation since dates end up being parsed at least
twice, once by the Lexer to determine that the string is a date, then
again in the IntervalFactory to actually construct the Date.

Before are the before and after results when exporting a database with
100 lines. The number of instructions executed went from roughly 31,552,467 to
12,952,372 on debug builds. Release builds saw a change from around 14K
to 7K instructions.

Before:

  $ rm -fr ~/.timewarrior; src/timew :yes >/dev/null; for x in {100..1}; do src/timew start ${x}sec ago proj_${x} >/dev/null; done;
  $ sudo chrt -f 99 valgrind --tool=callgrind --callgrind-out-file=callgrind.out src/timew export >/dev/null
  ==20888== Callgrind, a call-graph generating cache profiler
  ==20888== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al.
  ==20888== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
  ==20888== Command: src/timew export
  ==20888==
  ==20888== For interactive control, run 'callgrind_control -h'.
  ==20888==
  ==20888== Events    : Ir
  ==20888== Collected : 31552467
  ==20888==
  ==20888== I   refs:      31,552,467

After:

  $ sudo chrt -f 99 valgrind --tool=callgrind --callgrind-out-file=callgrind.out src/timew export >/dev/null
  ==24088== Callgrind, a call-graph generating cache profiler
  ==24088== Copyright (C) 2002-2017, and GNU GPL'd, by Josef Weidendorfer et al.
  ==24088== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
  ==24088== Command: src/timew export
  ==24088==
  ==24088== For interactive control, run 'callgrind_control -h'.
  ==24088==
  ==24088== Events    : Ir
  ==24088== Collected : 12952372
  ==24088==
  ==24088== I   refs:      12,952,372

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-05-10 21:16:08 +02:00
Thomas Lauf
ad58309159 Update Copyright
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-04-19 12:41:23 +02:00
Thomas Lauf
d73143b6cb remove unnecessary line breaks
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-04-14 10:11:39 +02:00
Daniel
13fb0ad8e3 ENH: Add new interval hint :fortnight (sopw - eow). 2020-03-06 21:56:43 +01:00
Shaun Ruffell
0b39a83a92 Filtering with tags should preserve the interval IDs.
This fixes the bug where, when filtering by tags, the interval IDs are not
preserved when not using any tags in the filter. Notice below how when
filtering with tag1, the two intervals are @4 and @5 instead of @1 and @5 like
they should be:

  $ timew summ :ids

  Wk Date       Day ID Tags    Start      End    Time   Total
  W9 2020-02-29 Sat @5 tag1 15:28:31 15:28:33 0:00:02
                    @4 tag2 15:28:33 15:28:35 0:00:02
                    @3 tag3 15:28:35 15:28:36 0:00:01
                    @2 tag4 15:28:36 15:28:48 0:00:12
                    @1 tag1 15:28:48        - 0:02:25 0:02:42

                                                      0:02:42

  $ timew summ tag1 :ids

  Wk Date       Day ID Tags    Start      End    Time   Total
  W9 2020-02-29 Sat @5 tag1 15:28:31 15:28:33 0:00:02
                    @4 tag1 15:28:48        - 0:02:28 0:02:30

                                                      0:02:30

This fixes a bug introduced in 86bb1465e8.

Closes issue #293 (thanks sskras)

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-06 16:10:19 +01:00
Shaun Ruffell
b62b7b3435 Interval: We can return a const reference to tags.
Interval is already marked as a constant object here and we can eliminate
creating unnecessary copies when filtering large databases.

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-06 16:10:19 +01:00
Shaun Ruffell
c1f3d8be72 Check serialization before writing to database
Ensure that the IntervalFactory can parse the string returned by
Interval::serialize before writing to database.

If a user attempts to add a non-parseable date, you will get an error like:

  $ TZ="GMT" timew track 7h before 1970-01-01T00:00:00 test
  Note: 'test' is a new tag.
  Internal error. Failed encode / decode check.

Or if the user attempts to add a tag that is not supported:

  $ timew start 1970-01-01T00:00:00 '\"TEST\"'
  Note: '"\\"TEST\\""' is a new tag.
  Internal error. Failed encode / decode check.

On #159, the serializer / deserializer should be able to handle the escaped
quotes, but it is another example where we do not want any entry written into
the database that cannot be properly parsed. This change will also add more
verbose debugging information if the :debug flag is passed, like:

  $ timew start 1970-01-01T00:00:00 '\"TEST\"' :debug
  CLI Parser
    _original_args
      timew start 1970-01-01T00:00:00 \"TEST\" :debug
    _args
      word basename='timew' raw='timew' BINARY
      word canonical='start' raw='start' ORIGINAL CMD
      date raw='1970-01-01T00:00:00' ORIGINAL FILTER
      word raw='\"TEST\"' ORIGINAL FILTER TAG
      word canonical=':debug' raw=':debug' ORIGINAL HINT FILTER

  >> 2020-02.data: 0 intervals
  >> 1970-01.data: 0 intervals
  >> 1969-12.data: 0 intervals
  >> Loaded 0 tracked intervals
  Note: '"\\"TEST\\""' is a new tag.
  >> Datafile::addInterval() failed.
  >> Encode / decode check failed:
  >>   inc 19700101T060000Z # "\\"TEST\\""
  >> is not equal to:
  >>   inc 19700101T060000Z # "TEST\\\"\"" \
  Internal error. Failed encode / decode check.
  >> Timer timew 0.002137 sec

Closes #290
Related to #159

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-04 07:44:05 +01:00
Shaun Ruffell
fda978c8cc Support multiline debug log messages
With this change, if there are debug messages that are multiple lines, each line
will be prefaced with the '>>' marker.

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-04 07:44:05 +01:00
Shaun Ruffell
1b968e8aa3 Interval: Add operators == and !=
Can be used to check the database format before committing.

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-04 07:44:05 +01:00
Thomas Lauf
bf87509329 Handle case of empty interval, fix tests
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-03-03 22:24:45 +01:00
Johannes Hertenstein
da27fdcdf0 285: Pass interval id to extensions 2020-03-03 22:23:21 +01:00
Thomas Lauf
e8511c5efd Extract function CLI::getDuration ()
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-03-03 07:58:04 +01:00
Thomas Lauf
0c1d7291e2 Use <..> instead of ".." for #include statements
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-03-03 07:57:33 +01:00
Thomas Lauf
888e715782 Streamline generation of additional help
- do filtering outside CmdHelp.cpp
- generate only concepts
- use join from libshared

Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-03-01 21:08:32 +01:00
Thomas Lauf
f1cf29d0ec Add some whitespace
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-03-01 21:08:32 +01:00
Shaun Ruffell
a796baec32 CmdHelp: Generate 'additional help' section from man pages
This will ensure that the additional help displayed will match valid
help targets.

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-01 21:02:43 +01:00
Shaun Ruffell
b5df2a2aa5 CmdHelp: Return error if man command fails
I feel this is expected behavior, but also eliminates the following compile time
warning on one of my systems:

  warning: ignoring return value of ‘int system(const char*)’, declared with
    attribute warn_unused_result [-Wunused-result]

Signed-off-by: Shaun Ruffell <sruffell@sruffell.net>
2020-03-01 21:02:43 +01:00
Thomas Lauf
28da1b55f2 Hoist verbose flag 2020-02-23 19:03:54 +01:00
Shaun Ruffell
213eb44954 Do not always create timewarrior.cfg file
I tried placing my timewarrior database in Dropbox and noticed that everytime
I ran a command, Dropbox would indicate that it was syncing. Running fswatch
on macOS I saw that there was an event for timewarrior.cfg on every run. This
change eliminates the file system events when not writing to the database.

Related to #284
2020-02-23 19:03:40 +01:00
Shaun Ruffell
4798e6f26b Database: Recreate tags.data from interval data if parsing fails.
If the tags database has been corrupted for any reason we should recreate it.
This commit simplified some of the negative testing for AtomicFiles.
2020-02-23 19:03:40 +01:00
Shaun Ruffell
aa7a674ca6 Do not write tag database if it is not changed.
Database objects were unconditionally writing out the tags database
file. For commands that are not modifying any tags, this is unnecessary.
We will now track if there have been modifications so we can use it to
determine if we need to save the tags to a file.

Closes #284
2020-02-23 19:03:40 +01:00
Shaun Ruffell
4b3a907cbb Use AtomicFile for data, tags, undo, and config files
Now changes accross all of these files either happen all together or not
at all.

Related to issue #155
2020-02-23 19:03:40 +01:00
Shaun Ruffell
8e99c07d85 Introduce AtomicFiles
Introduce AtomicFile and a test of this module to the code.

AtomicFile is like File, except all writes go to temporary files until
the class method finalize_all () is called and the temporary files are
copied over the real files. If any writes fail, like when there is no
more space on the filesystem, none of the files in the database will be
modified.

Since we need version 1.00 of libfiu, I have only added it to the debian
testing container, which includes libfiu-1.00 in the default repository.

Related to #155
2020-02-23 19:03:40 +01:00
Shaun Ruffell
6db1d2b859 Do not construct File when a Path will suffice
There were places in Database, CmdReport, and CmdHelp that were using a File
object when only the Path interface was needed. This is some minor cleanup I
noticed while studying the File usage as part of preparating for converting to
AtomicFile.
2020-02-23 19:03:40 +01:00
Thomas Lauf
35a38d628c Optimize handling of implicit latest interval
- If no id is given but active time tracking (i.e. open interval) is present
  then apply the command to the open interval
2020-02-01 23:49:56 +01:00
Thomas Lauf
711848915b Test for no ids
Signed-off-by: Thomas Lauf <thomas.lauf@tngtech.com>
2020-02-01 23:49:56 +01:00
Shaun Ruffell
7261c23fa7 Database: Fix error when empty datafile is most recent / oldest
This fixes an error I introduced in the recent code to avoid loading the
entire database. It only now appeared because I happened to run the test
suite on the first of the month.

Below is the error I was seeing:

  $ test/delete.t
  1..5
  ok 1 - delete.t: Delete a single closed interval
  ok 2 - delete.t: Delete an interval which encloses a month border
  ok 3 - delete.t: Delete a mix of open/closed intervals
  not ok 4 - delete.t: Delete a single open interval
  # FAIL: AssertionError on file test/delete.t line 56 in test_delete_open:
  # 'self.assertEqual(len(j), 1)':
  #       0 != 1
  ok 5 - delete.t: Delete an open interval that spans over an exclusion

The problem is that when there was one entry in the 2020-01.data file
and one in the 2020-02.data file, when I deleted the single one in the
2020-02.data file, the interator constructor was not updating the lines
iterator when moving to a new file.
2020-02-01 23:36:18 +01:00
Shaun Ruffell
1abf6e9320 Database: firstLine -> getLatestEntry
firstLine is ambiguous (the first line that was added in time? The first line
that will be returned when iterating the database?)

See https://github.com/GothenburgBitFactory/timewarrior/pull/269#discussion_r367922757
2020-01-26 19:49:23 +01:00
Shaun Ruffell
c7c1ea632a CmdUntag: Fix copy-paste errors from recent changes 2020-01-26 19:49:23 +01:00
Shaun Ruffell
2fcca6f949 trivial:coding-style: Add curly braces around blocks modified recently
timwarrior coding standard is for there to be curly braces around all code
blocks.

See https://github.com/GothenburgBitFactory/timewarrior/pull/269#discussion_r367937920
2020-01-26 19:49:23 +01:00
Shaun Ruffell
d9480b591a CmdModify: Allow modification of synthetic intervals
This fixes an issue in the modify command since it was first added. This will
allow modify to work in the presence of synthetic intervals.
2020-01-17 17:48:57 +01:00
Shaun Ruffell
9aac57c518 CmdSplit: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
a5493787ad CmdShorten: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
52115accb6 CmdResize: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
1b8c674771 CmdMove: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
62bde62961 CmdLenghten: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
c65c899926 CmdJoin: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
6a62d2297e CmdDelete: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
8c8f6b7c7c CmdAnnotate: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
a5785dd41a CmdUntag: Do not load entire database when untagging intervals
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
aa44df24c0 CmdModify: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
16d2c13f55 CmdTag: Do not load entire database
Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
2c1a4a146d CmdContinue: Do not load entire database
This change eliminates the call to getTracked with an empty filter,
which causes the entire database to be parsed.

Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
59ee7e47d4 Database: add assert in addInterval if start is greater than end 2020-01-17 17:48:57 +01:00
Shaun Ruffell
894f8ba5d8 Database: Add method empty 2020-01-17 17:48:57 +01:00
Shaun Ruffell
2df76a2ef0 Add helpers flattenDatabase and getIntervalsByIds
getIntervalsByIds will be used by commands that are loading complete database
currently when they really want a few intervals that the user specified by ID.

Related to issue #245
2020-01-17 17:48:57 +01:00
Shaun Ruffell
610e78fede Remove getAllInclusions helper function
All locations in the code that was creating Intervals for all entries in
the database have been removed. This function can now be removed as
well.
2020-01-17 17:48:57 +01:00