Add options to "guess" unknown tags
This will be the default option so that the script "just works" without configuration. Also, the config setting "skip_unknown_tags" has been changed to "unknown_tags" to allow choosing among multiple behaviours.
This commit is contained in:
parent
031c654e09
commit
bde5c22636
2 changed files with 108 additions and 43 deletions
94
README.md
94
README.md
|
@ -12,13 +12,7 @@ tools like [ledger](https://ledger-cli.org) and
|
|||
extensions directory (usually something like
|
||||
`~/.timewarrior/extensions` and make sure that it's
|
||||
executable.
|
||||
2. Update your configuration:
|
||||
```sh
|
||||
timew config ext.timewclock.accounts 'work = Expenses:Time:Work; play = Expenses:Time:Play; test = Expenses:Other'
|
||||
```
|
||||
Add your own Timewarrior tags instead of `work`,
|
||||
`play`, etc.
|
||||
3. Run `timew timeclock` to generate your report! You
|
||||
2. Run `timew timeclock` to generate your report! You
|
||||
can add any filters you want, like `timew timeclock
|
||||
today`
|
||||
|
||||
|
@ -31,8 +25,8 @@ added to `timewarrior.cfg` or using the command
|
|||
`timewarrior config SETTING_NAME VALUE`
|
||||
|
||||
The configuration variables for this script are
|
||||
described below. You only need to set the first one
|
||||
to get started, the others are optional.
|
||||
described below.
|
||||
|
||||
|
||||
### `ext.timeclock.accounts`
|
||||
|
||||
|
@ -56,40 +50,72 @@ will be stripped automatically before parsing. Note
|
|||
that this means tags with spaces at the end like
|
||||
` play` will not be supported.
|
||||
|
||||
**Default:** empty (needs to be set before use)
|
||||
If a timewarrior entry has multiple tags, this srcript
|
||||
will attempt to match against each one. If none of the
|
||||
tags match, the behaviour specified by
|
||||
`ext.timeclock.unknown_tags` will be used.
|
||||
|
||||
**Default:** empty
|
||||
|
||||
|
||||
### `ext.timeclock.unknown_tags`
|
||||
|
||||
Define how to handle unknown tags.
|
||||
|
||||
This setting defines how to handle tags that are not
|
||||
mapped to accounts in the `ext.timeclock.accounts`
|
||||
setting defined above. The default behaviour is to
|
||||
"guess" the unknown tag, i.e. use the tag name as
|
||||
the account name. This way you can just use whatever
|
||||
account names you want when tracking time with
|
||||
Timewarrior, and it'll automatically be passed on to
|
||||
your timeclock file.
|
||||
|
||||
There are four possible settings in total:
|
||||
|
||||
- **`guess`** - "guess" the account name based on the tag
|
||||
name (in other words, take the first tag and use that
|
||||
as the account name). If the record is untagged, the
|
||||
default tag (from `ext.timeclock.default_tag`,
|
||||
described below) is used instead. If no default tag
|
||||
is set, an error is thrown.
|
||||
- **`default`** - use a "default" tag from the
|
||||
`ext.timeclock.default_account` setting when a record
|
||||
with no known tags is found. This default tag is also
|
||||
used for untagged records. Note that "default" doesn't
|
||||
mean this is the default setting; it just describes
|
||||
what account name is to be used!
|
||||
- **`fail`** - fail immediately whenever an unknown
|
||||
tag or a record with no tags is encountered. This
|
||||
is the strictest behaviour and forces you to either
|
||||
define the tags or tell Timewarrior to filter them
|
||||
out.
|
||||
- **`ignore`** - silently ignore records where the tags
|
||||
are blank or the account names can't be matched. This
|
||||
is the most permissive, but you should be careful
|
||||
while using this to make sure you don't accidentally
|
||||
miss out on some records! When possible, try to use
|
||||
some other setting and choose which records you want
|
||||
using timewarrior filters instead.
|
||||
|
||||
**Default:** guess
|
||||
|
||||
|
||||
### `ext.timeclock.default_account`
|
||||
|
||||
A default account to set records to if a tag mapping
|
||||
is not specified.
|
||||
A default account to set records to if a record is
|
||||
untagged or if a tag mapping is not specified.
|
||||
|
||||
If no tag mapping is found for a specific record, this
|
||||
default account will be used instead. Note that if a
|
||||
record has multiple tags, the script will check them
|
||||
one by one until it finds a matching tag, and only
|
||||
give up if all the unknown tags fail to match.
|
||||
This setting is used in one of the following situations:
|
||||
|
||||
**Default:** empty
|
||||
- an untagged record comes up, and
|
||||
`ext.timeclock.unknown_tags` is set to `guess` or
|
||||
`default`
|
||||
- no matching tag is found, and
|
||||
`ext.timeclock.unknown_tags` is set to `default`
|
||||
|
||||
### `ext.timeclock.skip_unknown_tags`
|
||||
**Default:** empty (needs to be set)
|
||||
|
||||
Silently skip records with unknown tags.
|
||||
|
||||
The default behaviour is to abort with an error when
|
||||
an unknown tag (i.e. a tag not mapped in the
|
||||
`ext.timeclock.accounts setting` above) is encountered.
|
||||
|
||||
With this setting, records for the unknown tags will
|
||||
be skipped silently. Note that this means not all
|
||||
Timewarrior records will be exported; a better way to
|
||||
do this would be to set appropriate filters in the
|
||||
Timewarrior command itself.
|
||||
|
||||
This command overrides `ext.timeclock.default_account`
|
||||
|
||||
**Default:** false
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
57
timeclock.pl
57
timeclock.pl
|
@ -24,12 +24,14 @@
|
|||
# General Public License along with this program.
|
||||
# If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use v5.14;
|
||||
use experimental qw( switch );
|
||||
use JSON;
|
||||
|
||||
# Process the headers
|
||||
my %tag_for_account;
|
||||
my $default_account;
|
||||
my $skip_unknown_tags;
|
||||
my $unknown_tags;
|
||||
while(<>) {
|
||||
last if /^\n/;
|
||||
|
||||
|
@ -54,19 +56,35 @@ while(<>) {
|
|||
$default_account = $1;
|
||||
}
|
||||
|
||||
if (/^ext\.timeclock\.skip_unknown_tags: (.*)$/) {
|
||||
$skip_unknown_tags = $1;
|
||||
if (/^ext\.timeclock\.unknown_tags: (.*)$/) {
|
||||
$unknown_tags = do {
|
||||
given($1) {
|
||||
"default" when /d(efault)?$/i;
|
||||
"fail" when /f(alse)?$/i;
|
||||
"fail" when /f(ail)?$/i;
|
||||
"fail" when /no?$/i;
|
||||
"ignore" when /t(rue)?$/i;
|
||||
"ignore" when /y(es)?$/i;
|
||||
"guess" when /g(uess(Instead)?)?$/i;
|
||||
default {
|
||||
die "Error: invalid option '$_' for setting ext.timeclock.unknown_tags. Should be one of 'fail', 'guess', 'default', or 'ignore'.";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
# If tags are not set, exit with an error message
|
||||
if (!keys %tag_for_account) {
|
||||
# If guessing tag names in disabled but tags are not
|
||||
# set, exit with an error message
|
||||
if (!keys %tag_for_account && $unknown_tags ne "guess") {
|
||||
print STDERR <<HELPTEXT;
|
||||
Error: guessing is disabled but no tag-to-account mappings were found! To use this script, please specify some tags in your timewarrior config file, under the setting `ext.timeclock.accounts`. The format for this setting is:
|
||||
|
||||
TAG1=ACCOUNT1;TAG1=ACCOUNT2;...
|
||||
|
||||
...where tags are the timewarrior tags and accounts are the accounts to be used for the timeclock output. You can put spaces around the semicolor (;) and equals (=) signs; those will be ignored before processing.
|
||||
|
||||
Alternatively, you can set 'ext.timeclock.unknown_tags` to `guess`.
|
||||
HELPTEXT
|
||||
exit 1;
|
||||
}
|
||||
|
@ -124,10 +142,31 @@ sub decide_account {
|
|||
}
|
||||
}
|
||||
|
||||
# Set a default account if needed
|
||||
if (!$account && !$skip_unknown_tags) {
|
||||
$account = $default_account
|
||||
or die "Error: No matching account found for '@tags' and no default tag was set. Try setting ext.timeclock.default_tag or ext.timeclock.skip_unknown_tags to get around this error.\n";
|
||||
# Handle unknown tags
|
||||
if (!$account) {
|
||||
$account = do {
|
||||
given ($unknown_tags) {
|
||||
|
||||
when("default") {
|
||||
$default_account
|
||||
or die "Error: No matching account found for '@tags' and no default tag was set. Try setting ext.timeclock.default_tag or ext.timeclock.unknown_tags to get around this error.\n";
|
||||
|
||||
}
|
||||
|
||||
when ("guess") {
|
||||
# Return the first tag we find
|
||||
shift @tags;
|
||||
}
|
||||
|
||||
when ("ignore") {
|
||||
return;
|
||||
}
|
||||
|
||||
default {
|
||||
die "Error: No matching account found for '@tags'. Try adding it to ext.timeclock.accounts or set ext.timeclock.unknown_tags to change handling behaviour.\n"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return $account;
|
||||
|
|
Loading…
Reference in a new issue