Import design docs (RFCs)
This commit is contained in:
committed by
Tomas Babej
parent
07493d5fa6
commit
8747cc9f94
@@ -13,3 +13,22 @@ For all other documenation, see https://taskwarrior.org.
|
|||||||
* [Building Taskwarrior](./contrib/build)
|
* [Building Taskwarrior](./contrib/build)
|
||||||
* [Coding Style](./contrib/coding_style)
|
* [Coding Style](./contrib/coding_style)
|
||||||
* [Branching Model](./contrib/branching)
|
* [Branching Model](./contrib/branching)
|
||||||
|
|
||||||
|
## RFC's
|
||||||
|
|
||||||
|
This is where design documents (RFCs) are kept.
|
||||||
|
|
||||||
|
Although these documents are less formal than [IETF RFCs](https://www.ietf.org/rfc) they serve a similar purpose.
|
||||||
|
These documents apply only to the Taskwarrior family of products, and are placed here to invite comment before designs finalize.
|
||||||
|
|
||||||
|
- [General Plans](./rfcs/plans)
|
||||||
|
- [Rules System](./rfcs/rules)
|
||||||
|
- [Full DOM Support ](./rfcs/dom)
|
||||||
|
- [Work Week Support](./rfcs/workweek)
|
||||||
|
- [Recurrence](./rfcs/recurrence)
|
||||||
|
- [Taskwarrior JSON Format](./rfcs/task)
|
||||||
|
- [CLI Updates ](./rfcs/cli)
|
||||||
|
- [Taskserver Sync Protocol](./rfcs/protocol)
|
||||||
|
- [Taskserver Message Format](./rfcs/request)
|
||||||
|
- [Taskserver Sync Algorithm](./rfcs/sync)
|
||||||
|
- [Taskserver Client](./rfcs/client)
|
||||||
|
|||||||
24
docs/rfcs/_index.md
Normal file
24
docs/rfcs/_index.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - What's next?"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design
|
||||||
|
|
||||||
|
## Plans
|
||||||
|
|
||||||
|
- [Task warrior/Taskserver/Tasksh/Timewarrior Plans](/docs/design/plans)
|
||||||
|
|
||||||
|
## RFCs
|
||||||
|
|
||||||
|
|
||||||
|
### Tasksh
|
||||||
|
|
||||||
|
- (No announced plans)
|
||||||
|
|
||||||
|
### Timewarrior
|
||||||
|
|
||||||
|
- (No announced plans)
|
||||||
|
|
||||||
|
### Upcoming
|
||||||
|
|
||||||
|
- Lazy Dates (Deferred Evaluation)
|
||||||
162
docs/rfcs/cli.md
Normal file
162
docs/rfcs/cli.md
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Command Line Interface"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work in Progress
|
||||||
|
|
||||||
|
This design document is a work in progress, and subject to change. Once
|
||||||
|
finalized, the feature will be scheduled for an upcoming release.
|
||||||
|
|
||||||
|
|
||||||
|
# CLI Syntax Update
|
||||||
|
|
||||||
|
The Taskwarrior command line syntax is being updated to allow more consistent
|
||||||
|
and predictable results, while making room for new features.
|
||||||
|
|
||||||
|
Adding support for arbitrary expressions on the command line has become
|
||||||
|
complicated because of the relaxed syntax of Taskwarrior. While the relaxed
|
||||||
|
syntax allows for a very expressive command line, it also creates ambiguity for
|
||||||
|
the parser, which needs to be reduced.
|
||||||
|
|
||||||
|
With some limited and careful changes it will be possible to have a clear and
|
||||||
|
unambiguous command line syntax, which means a predictable and deterministic
|
||||||
|
experience.
|
||||||
|
|
||||||
|
It should be stated that for straightforward and even current usage patterns,
|
||||||
|
the command line will likely not change for you. Another goal is to not require
|
||||||
|
changes to 3rd-party software, where possible. Only the more advanced and as-yet
|
||||||
|
unintroduced features will require a more strict syntax. This is why now is an
|
||||||
|
ideal time to tighten the requirements.
|
||||||
|
|
||||||
|
|
||||||
|
## Argument Types
|
||||||
|
|
||||||
|
The argument types supported remain the same, adding some new constructs.
|
||||||
|
|
||||||
|
--------------------------------------- ---------------------------------------
|
||||||
|
Config file override `rc:<file>`
|
||||||
|
|
||||||
|
Configuration override `rc:<name>:<value>` Literal value\
|
||||||
|
`rc:<name>=<value>` Literal value\
|
||||||
|
`rc:<name>:=<value>` Calculated value
|
||||||
|
|
||||||
|
Tag `+<tag>`\
|
||||||
|
`-<tag>`\
|
||||||
|
`'+tag one'` Multi-word tag
|
||||||
|
|
||||||
|
Attribute modifier `rc:<name>.<modifier>:<value>`\
|
||||||
|
Modifier is one of:\
|
||||||
|
`before`\
|
||||||
|
`after`\
|
||||||
|
`under`\
|
||||||
|
`over`\
|
||||||
|
`above`\
|
||||||
|
`below`\
|
||||||
|
`none`\
|
||||||
|
`any`\
|
||||||
|
`is`\
|
||||||
|
`isnt`\
|
||||||
|
`equals`\
|
||||||
|
`not`\
|
||||||
|
`contains`\
|
||||||
|
`has`\
|
||||||
|
`hasnt`\
|
||||||
|
`left`\
|
||||||
|
`right`\
|
||||||
|
`startswith`\
|
||||||
|
`endswith`\
|
||||||
|
`word`\
|
||||||
|
`noword`
|
||||||
|
|
||||||
|
Search pattern `/<pattern>/`
|
||||||
|
|
||||||
|
Substitution `/<from>/<to>/`\
|
||||||
|
`/<from>/<to>/g`
|
||||||
|
|
||||||
|
Command `add`\
|
||||||
|
`done`\
|
||||||
|
`delete`\
|
||||||
|
`list`\
|
||||||
|
etc.
|
||||||
|
|
||||||
|
Separator `--`
|
||||||
|
|
||||||
|
ID Ranges `<id>[-<id>][,<id>[-<id>]...]`
|
||||||
|
|
||||||
|
UUID `<uuid>`
|
||||||
|
|
||||||
|
Everything Else `<word>`\
|
||||||
|
`'<word> <word> ...'`
|
||||||
|
--------------------------------------- ---------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
## New Command Line Rules
|
||||||
|
|
||||||
|
Certain command line constructs will no longer be supported, and this is imposed
|
||||||
|
by the new rules:
|
||||||
|
|
||||||
|
1. Each command line argument may contain only one instance of one argument
|
||||||
|
type, unless that type is `<word>`.
|
||||||
|
|
||||||
|
task add project:Home +tag Repair the thing # Good
|
||||||
|
task add project:Home +tag 'Repair the thing' # Good
|
||||||
|
task add 'project:Home +tag Repair the thing' # Bad
|
||||||
|
|
||||||
|
Putting two arguments into one quoted arg makes that arg a `<word>`.
|
||||||
|
|
||||||
|
2. If an argument type contains spaces, it must either be quoted or escaped.
|
||||||
|
|
||||||
|
task add project:'Home & Garden' ... # Good
|
||||||
|
task add 'project:Home & Garden' ... # Good
|
||||||
|
task add project:Home\ \&\ Garden ... # Good
|
||||||
|
task add project:Home' & 'Garden ... # Good
|
||||||
|
task add project:Home \& Garden ... # Bad
|
||||||
|
|
||||||
|
The parser will not combine multiple arguments, for example:
|
||||||
|
|
||||||
|
task '/one two/' list # Good
|
||||||
|
task /one two/ list # Bad
|
||||||
|
task /'one two'/ list # Bad, unless ' is part of the pattern
|
||||||
|
|
||||||
|
3. By default, *no* calculations are made, unless the `:=` eval operator is
|
||||||
|
used, and if so, the whole argument may need to be quoted or escaped to
|
||||||
|
satisfy Rule 1.
|
||||||
|
|
||||||
|
task add project:3.project+x # Literal
|
||||||
|
task add project:=3.project+x # DOM reference + concatenation
|
||||||
|
|
||||||
|
4. Bare word search terms are no longer supported. Use the pattern type
|
||||||
|
argument instead.
|
||||||
|
|
||||||
|
task /foo/ list # Good
|
||||||
|
task foo list # Bad
|
||||||
|
|
||||||
|
5. Expressions must be a series of arguments, not a quoted string.
|
||||||
|
|
||||||
|
task urgency \< 5.0 list # Good
|
||||||
|
task 'urgency < 5.0 list' # Bad
|
||||||
|
|
||||||
|
|
||||||
|
## Other Changes
|
||||||
|
|
||||||
|
Aside from the command line parser, there are other changes needed:
|
||||||
|
|
||||||
|
- Many online documents will need to be modified.
|
||||||
|
|
||||||
|
- Filters will be automatically parenthesized, so that every command line will
|
||||||
|
now looke like:
|
||||||
|
|
||||||
|
task [overrides] [(cli-filter)] [(context-filter)] [(report-filter)] command [modifications]
|
||||||
|
|
||||||
|
- There will be more errors when the command line is not understood.
|
||||||
|
|
||||||
|
- Ambiguous ISO date formats are dropped.
|
||||||
|
|
||||||
|
YYYYMMDD # Bad
|
||||||
|
YYYY-MM-DD # Good
|
||||||
|
|
||||||
|
hhmmss # Bad
|
||||||
|
hh:mm:ss # Good
|
||||||
|
|
||||||
|
- The tutorial videos will be even more out of date, and will be replaced by a
|
||||||
|
large number of smaller demo \'movies\'.
|
||||||
444
docs/rfcs/client.md
Normal file
444
docs/rfcs/client.md
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Creating a Taskserver Client"
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Creating a Taskserver Client
|
||||||
|
|
||||||
|
A Taskserver client is a todo-list manager. It may be as simple as a program
|
||||||
|
that captures a single task, as complex as Taskwarrior, or anything in between.
|
||||||
|
It can be a mobile client, a web application, or any other type of program.
|
||||||
|
|
||||||
|
This document describes how such a client would interact with the server.
|
||||||
|
|
||||||
|
A client to the Taskserver is a program that manages a task list, and wishes to
|
||||||
|
exchange data with the server so that the task list may be shared.
|
||||||
|
|
||||||
|
In order to do this, a client must store tasks locally, upload local changes,
|
||||||
|
download remote changes, and apply remote changes to the local tasks.
|
||||||
|
|
||||||
|
The client must consider that there may be no network connectivity, or no desire
|
||||||
|
by the user to synchronize.
|
||||||
|
|
||||||
|
The client will need proper credentials to talk to the server.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In this document, we adopt the convention discussed in Section 1.3.2 of
|
||||||
|
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized
|
||||||
|
words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the
|
||||||
|
significance of each particular requirement specified in this document.
|
||||||
|
|
||||||
|
In brief: \"MUST\" (or \"REQUIRED\") means that the item is an absolute
|
||||||
|
requirement of the specification; \"SHOULD\" (or \"RECOMMENDED\") means there
|
||||||
|
may exist valid reasons for ignoring this item, but the full implications should
|
||||||
|
be understood before doing so; and \"MAY\" (or \"OPTIONAL\") means that this
|
||||||
|
item is optional, and may be omitted without careful consideration.
|
||||||
|
|
||||||
|
|
||||||
|
## Taskserver Account
|
||||||
|
|
||||||
|
A Taskserver account must be created. This process creates a storage area, and
|
||||||
|
generates the necessary credentials.
|
||||||
|
|
||||||
|
|
||||||
|
## Credentials
|
||||||
|
|
||||||
|
A Taskserver client needs the following credentials in order to communicate with
|
||||||
|
a server:
|
||||||
|
|
||||||
|
- Server address and port
|
||||||
|
- Organization name
|
||||||
|
- User name
|
||||||
|
- Password
|
||||||
|
- Certificate
|
||||||
|
- Key
|
||||||
|
|
||||||
|
The server address and port are the network location of the server. An example
|
||||||
|
of this value is:
|
||||||
|
|
||||||
|
foo.example.com:53589
|
||||||
|
|
||||||
|
In addition to a DNS name, this can be an IPv4 or IPv6 address.
|
||||||
|
|
||||||
|
The organization name is an arbitrary grouping, and is typically \'PUBLIC\',
|
||||||
|
reflecting the individual nature of server accounts. Future capabilities will
|
||||||
|
provide functionality that support groups of users, called an organization.
|
||||||
|
|
||||||
|
The user name is the full name. This will be the name used to identify other
|
||||||
|
users in an organization, in a future release. Example \'John Doe\'.
|
||||||
|
|
||||||
|
The password is a text string generated by the server at account creation time.
|
||||||
|
It should be considered a secret.
|
||||||
|
|
||||||
|
The certificate is an X.509 PEM file generated by the server at account creation
|
||||||
|
time. This is used for authentication. It should be considered a secret.
|
||||||
|
|
||||||
|
The key is an X.509 PEM file generated by the server at account creation time.
|
||||||
|
This is used for encryption. It should be considered a secret.
|
||||||
|
|
||||||
|
These credentials need to be stored on the client, and used during the sync
|
||||||
|
operation.
|
||||||
|
|
||||||
|
|
||||||
|
## Description of a Taskserver Client
|
||||||
|
|
||||||
|
This section describes how a client might behave in order to facilitate
|
||||||
|
integration with the Taskserver.
|
||||||
|
|
||||||
|
|
||||||
|
## Encryption
|
||||||
|
|
||||||
|
The Taskserver only communicates using encryption. Therefore all user data is
|
||||||
|
encrypted while in transit. The Taskserver currently uses
|
||||||
|
[GnuTLS](https://gnutls.org) to support this encryption, and therefore supports
|
||||||
|
the following protocols:
|
||||||
|
|
||||||
|
- SSL 3.0
|
||||||
|
- TLS 1.0
|
||||||
|
- TLS 1.1
|
||||||
|
- TLS 1.2
|
||||||
|
|
||||||
|
The client may use any library that supports the above.
|
||||||
|
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The client needs to store configuration, which matches the credentials needed
|
||||||
|
for Taskserver communication. See section 2.1 \"Credentials\".
|
||||||
|
|
||||||
|
The credentials may not be modified by the user without losing server access.
|
||||||
|
|
||||||
|
The server:port data may need to be changed automatically following a redirect
|
||||||
|
response from the server. See section 5 \"Server Errors\".
|
||||||
|
|
||||||
|
|
||||||
|
## Local Storage
|
||||||
|
|
||||||
|
The client needs to store task data locally. The client will need to be able to
|
||||||
|
find tasks by their UUID and overwrite them. Uploaded and downloaded task
|
||||||
|
changes will use the [Taskwarrior Data Interchange
|
||||||
|
Format](/docs/design/task).
|
||||||
|
|
||||||
|
|
||||||
|
## Local Changes
|
||||||
|
|
||||||
|
Whenever local data is modified, that change MUST be synced with the server. But
|
||||||
|
this does not have to occur immediately, in fact the client SHOULD NOT assume
|
||||||
|
connectivity at any time.
|
||||||
|
|
||||||
|
A client SHOULD NOT also assume that the server is available. If the server is
|
||||||
|
not available, the local changes should be retained, and the sync operation
|
||||||
|
repeated later.
|
||||||
|
|
||||||
|
Ideally the client will give the user full control over sync operations.
|
||||||
|
Automatically syncing after all local modifications is not recommended. If a
|
||||||
|
client performs too many sync operations, the server MAY revoke the certificate.
|
||||||
|
|
||||||
|
Effectively, the client should maintain a separate list of tasks changed since
|
||||||
|
the last successful sync operation.
|
||||||
|
|
||||||
|
Note that tasks have a \"modified\" attribute, which should be updated whenever
|
||||||
|
a change is made. This attribute contributes to conflict resolution on the
|
||||||
|
server.
|
||||||
|
|
||||||
|
|
||||||
|
## Remote Changes
|
||||||
|
|
||||||
|
When a server sends remote changes to a client, in the response to a sync
|
||||||
|
request, the changes have already been merged by the server, and therefore the
|
||||||
|
client should simply store them intact.
|
||||||
|
|
||||||
|
Based on the UUID in the task, the client can determine whether a task is new
|
||||||
|
(and should be added to the local list of tasks), or whether it represents a
|
||||||
|
modification (and should overwrite it\'s existing entry).
|
||||||
|
|
||||||
|
The client MUST NOT perform any merges.
|
||||||
|
|
||||||
|
|
||||||
|
## Sync Key
|
||||||
|
|
||||||
|
Whenever a sync is performed, the server responds by sending a sync key and any
|
||||||
|
remote changes. The sync key is important, and should be included in the next
|
||||||
|
sync request. The client is REQUIRED to store the sync key in every server
|
||||||
|
response message.
|
||||||
|
|
||||||
|
If a client omits the sync key in a sync message, the response will be a
|
||||||
|
complete set of all tasks and modifications.
|
||||||
|
|
||||||
|
|
||||||
|
## Data Integrity
|
||||||
|
|
||||||
|
Although a task is guaranteed to contain at least \'entry\', \'description\' and
|
||||||
|
\'uuid\' attributes, it may also contain other known fields, and unknown
|
||||||
|
user-defined fields. An example might be an attribute named \'estimate\'.
|
||||||
|
|
||||||
|
If a task is received via sync that contains an attribute named \'estimate\',
|
||||||
|
then a client has the responsibility of preserving the attribute intact. If that
|
||||||
|
data is shown, then it is assumed to be of type \'string\', which is the format
|
||||||
|
used by JSON for all values.
|
||||||
|
|
||||||
|
Conversely, if a client wishes to add a custom attribute, it is guaranteed that
|
||||||
|
the server and other clients will preserve that attribute.
|
||||||
|
|
||||||
|
Using this rule, two clients of differing capabilities can exchange data and
|
||||||
|
still maintain custom attributes.
|
||||||
|
|
||||||
|
This is a requirement. Any client that does not obey this requirement is broken.
|
||||||
|
|
||||||
|
|
||||||
|
## Synchronizing
|
||||||
|
|
||||||
|
Synchronizing with the Taskserver consists of a single transaction. Once an
|
||||||
|
encrypted connection is made with the server, the client MUST compose a [sync
|
||||||
|
request message](/docs/design/request). This message includes credentials
|
||||||
|
and local changes. The response message contains status and remote changes,
|
||||||
|
which MUST be stored locally.
|
||||||
|
|
||||||
|
|
||||||
|
## Establishing Encrypted Connection
|
||||||
|
|
||||||
|
All communication with the Taskserver is encrypted using the certificate and key
|
||||||
|
provided to each user. Using the \'server\' configuration setting, establish a
|
||||||
|
connection.
|
||||||
|
|
||||||
|
|
||||||
|
## Sync Request
|
||||||
|
|
||||||
|
See [sync request message](/docs/design/request). A sync request MUST
|
||||||
|
contain a sync key if one was provided by a previous sync. A sync request MUST
|
||||||
|
contain a list of modified tasks, in JSON format (see [Task
|
||||||
|
JSON](/docs/design/task)), if local modifications have been made.
|
||||||
|
|
||||||
|
|
||||||
|
## Sync Response
|
||||||
|
|
||||||
|
A sync response WILL contain a \'code\' and \'status\' header variable, WILL
|
||||||
|
contain a sync key in the payload, and MAY contain a list of tasks from the
|
||||||
|
server in JSON format (see [Task JSON](/docs/design/task)).
|
||||||
|
|
||||||
|
|
||||||
|
## Server Messages
|
||||||
|
|
||||||
|
There are cases when the server needs to inform the user of some condition. This
|
||||||
|
may be anticipated server downtime, for example. The response message is
|
||||||
|
typically not present, but may be present in the header, containing a string:
|
||||||
|
|
||||||
|
...
|
||||||
|
message: Scheduled maintenance 2013-07-14 08:00UTC for 10 minutes.
|
||||||
|
...
|
||||||
|
|
||||||
|
If such a message is returned by the server, it SHOULD be made available to the
|
||||||
|
user. This is a recommendation, not a requirement.
|
||||||
|
|
||||||
|
|
||||||
|
## Server Errors
|
||||||
|
|
||||||
|
The server may generate many errors (See
|
||||||
|
[Protocol](/docs/design/protocol)), but the following is a list of the ones
|
||||||
|
most in need of special handling:
|
||||||
|
|
||||||
|
- 200 Success
|
||||||
|
- 201 No change
|
||||||
|
- 301 Redirect
|
||||||
|
- 430 Access denied
|
||||||
|
- 431 Account suspended
|
||||||
|
- 432 Account terminated
|
||||||
|
- 5xx Error
|
||||||
|
|
||||||
|
The 200 indicates success, and that a change was recorded. The 201 indicates
|
||||||
|
success but no changes were necessary. The 301 is a redirect message indicating
|
||||||
|
that the client MUST re-request from a new server. The 43x series messages are
|
||||||
|
account-related. Any 5xx series code is a server error of some kind. All errors
|
||||||
|
consist of a code and a status message:
|
||||||
|
|
||||||
|
code: 200
|
||||||
|
status: Success
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Here are examples of properly formatted request and response messages. Note that
|
||||||
|
the messages are indented for clarity in this document, but is not the case in a
|
||||||
|
properly formatted message. Also note that newline characters U+000D are not
|
||||||
|
shown, but are implied by the separate lines. Because some messages have
|
||||||
|
trailing newline characters, the text is delimited by the \'cut\' markers:
|
||||||
|
|
||||||
|
foo
|
||||||
|
|
||||||
|
The example above illustrates text consisting of:
|
||||||
|
|
||||||
|
U+0066 f
|
||||||
|
U+006F o
|
||||||
|
U+006F o
|
||||||
|
U+000D newline
|
||||||
|
U+000D newline
|
||||||
|
|
||||||
|
Note that these values are left unspecified, but should be clear from the
|
||||||
|
context, and the [message format](/docs/design/request) spec:
|
||||||
|
|
||||||
|
<size>
|
||||||
|
<organization>
|
||||||
|
<user>
|
||||||
|
<password>
|
||||||
|
|
||||||
|
|
||||||
|
## First Sync
|
||||||
|
|
||||||
|
The first time a client syncs, there is (perhaps) no data to upload, and no sync
|
||||||
|
key from a previous sync.
|
||||||
|
|
||||||
|
<size>type: sync
|
||||||
|
org: <organization>
|
||||||
|
user: <user>
|
||||||
|
key: <password>
|
||||||
|
client: task 2.3.0
|
||||||
|
protocol: v1
|
||||||
|
|
||||||
|
Note the double newline character separating header from payload, with an empty
|
||||||
|
payload.
|
||||||
|
|
||||||
|
|
||||||
|
## Request: Sync No Data
|
||||||
|
|
||||||
|
Ordinarily when a client syncs, there is a sync key from the previous sync
|
||||||
|
response to send. This example shows a sync with no local changes, but a sync
|
||||||
|
key from a previous sync.
|
||||||
|
|
||||||
|
<size>type: sync
|
||||||
|
org: <organization>
|
||||||
|
user: <user>
|
||||||
|
key: <password>
|
||||||
|
client: task 2.3.0
|
||||||
|
protocol: v1
|
||||||
|
|
||||||
|
2e4685f8-34bc-4f9b-b7ed-399388e182e1
|
||||||
|
|
||||||
|
|
||||||
|
## Request: Sync Data
|
||||||
|
|
||||||
|
This sync request shows a sync key from the previous sync, and a locally
|
||||||
|
modified task.
|
||||||
|
|
||||||
|
<size>type: sync
|
||||||
|
org: <organization>
|
||||||
|
user: <user>
|
||||||
|
key: <password>
|
||||||
|
client: task 2.3.0
|
||||||
|
protocol: v1
|
||||||
|
|
||||||
|
2e4685f8-34bc-4f9b-b7ed-399388e182e1
|
||||||
|
{"description":"An example","uuid":"8ad2e3db-914d-4832-b0e6-72fa04f6e331",...}
|
||||||
|
|
||||||
|
|
||||||
|
## Response: No Data
|
||||||
|
|
||||||
|
If a sync results in no downloads to the client, the response will look like
|
||||||
|
this.
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 200
|
||||||
|
status: Ok
|
||||||
|
|
||||||
|
45da7110-1bcc-4318-d33e-12267a774e0f
|
||||||
|
|
||||||
|
Note that there is a sync key which must be stored and used in the next sync
|
||||||
|
request, but there are no remote changes to store.
|
||||||
|
|
||||||
|
|
||||||
|
## Response: Remote Data
|
||||||
|
|
||||||
|
This shows a sync response providing a new sync key, and a remote change to two
|
||||||
|
tasks.
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 200
|
||||||
|
status: Ok
|
||||||
|
|
||||||
|
45da7110-1bcc-4318-d33e-12267a774e0f
|
||||||
|
{"description":"Test data","uuid":"8ad2e3db-914d-4832-b0e6-72fa04f6e331",...}
|
||||||
|
{"description":"Test data2","uuid":"3b6218f9-726a-44fc-aa63-889ff52be442",...}
|
||||||
|
|
||||||
|
Note that the sync key must be stored for the next sync request.
|
||||||
|
|
||||||
|
Note that the two changed tasks must be stored locally, and if the UUID in the
|
||||||
|
tasks matches local tasks, then the local tasks must be overwritten.
|
||||||
|
|
||||||
|
|
||||||
|
## Response: Error
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 431
|
||||||
|
status: Account suspended
|
||||||
|
|
||||||
|
Note the double newline character separating header from payload, with an empty
|
||||||
|
payload.
|
||||||
|
|
||||||
|
|
||||||
|
## Response: Relocate
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 301
|
||||||
|
status: Redirect
|
||||||
|
info:
|
||||||
|
|
||||||
|
Note the \'info\' field will contain a \':\' string that should be used for all
|
||||||
|
future sync requests. This indicates that a user account was moved to another
|
||||||
|
server.
|
||||||
|
|
||||||
|
Note the double newline character separating header from payload, with an empty
|
||||||
|
payload.
|
||||||
|
|
||||||
|
|
||||||
|
## Response: Message
|
||||||
|
|
||||||
|
Occasionally the server will need to convey a message, and will include an
|
||||||
|
additional header variable containing that message.
|
||||||
|
|
||||||
|
The server [protocol](/docs/design/protocol) states that the message SHOULD
|
||||||
|
be shown to the user. This message will be used for system event messages, used
|
||||||
|
rarely, and never used for advertising or promotion.
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 200
|
||||||
|
status: Ok
|
||||||
|
message: Scheduled maintenance 2013-07-14 08:00UTC for 10 minutes.
|
||||||
|
|
||||||
|
45da7110-1bcc-4318-d33e-12267a774e0f
|
||||||
|
|
||||||
|
Note that the same message will likely be included in consecutive responses.
|
||||||
|
|
||||||
|
|
||||||
|
## Reference Implementation
|
||||||
|
|
||||||
|
The Taskserver 1.1.0 codebase contains a reference implementation of an SSL/TLS
|
||||||
|
client and server program, which communicate text strings.
|
||||||
|
|
||||||
|
taskd.git/src/tls/Makefile # To build the example
|
||||||
|
taskd.git/src/tls/README # How to run the example
|
||||||
|
taskd.git/src/tls/TLSClient.cpp # TLS client code
|
||||||
|
taskd.git/src/tls/TLSClient.h
|
||||||
|
taskd.git/src/tls/TLSServer.cpp # TLS Server code
|
||||||
|
taskd.git/src/tls/TLSServer.h
|
||||||
|
taskd.git/src/tls/c.cpp # Client program
|
||||||
|
taskd.git/src/tls/s.cpp # Server program
|
||||||
|
taskd.git/src/tls/text.cpp # Text manipulation
|
||||||
|
taskd.git/src/tls/text.h # Text manipulation
|
||||||
|
|
||||||
|
The Taskwarrior codebase, version 2.4.0, is the reference implementation.
|
||||||
|
|
||||||
|
task.git/src/TLSClient.cpp # TLS client code
|
||||||
|
task.git/src/TLSClient.h
|
||||||
|
task.git/src/commands/CmdSync.cpp # Sync implementation
|
||||||
|
task.git/src/commands/CmdSync.h
|
||||||
259
docs/rfcs/dom.md
Normal file
259
docs/rfcs/dom.md
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Full DOM Support"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work in Progress
|
||||||
|
|
||||||
|
This design document is a work in progress, and subject to change. Once
|
||||||
|
finalized, the feature will be scheduled for an upcoming release.
|
||||||
|
|
||||||
|
|
||||||
|
# Full DOM Support
|
||||||
|
|
||||||
|
Taskwarrior currently supports DOM references that can access any stored data
|
||||||
|
item. The general forms supported are:
|
||||||
|
|
||||||
|
[ <id> | <uuid> ] <attribute> [ <part> ]
|
||||||
|
|
||||||
|
Examples include:
|
||||||
|
|
||||||
|
due
|
||||||
|
123.uuid
|
||||||
|
entry.month
|
||||||
|
123.annotations.0.entry.year
|
||||||
|
a87bc10f-931b-4558-a44a-e901a77db011.description
|
||||||
|
|
||||||
|
Additionally there are references for accessing configuration and system/program
|
||||||
|
level items.
|
||||||
|
|
||||||
|
rc.<name>
|
||||||
|
context.program
|
||||||
|
context.args
|
||||||
|
context.width
|
||||||
|
context.height
|
||||||
|
system.version
|
||||||
|
system.os
|
||||||
|
|
||||||
|
While this is adequate for data retrieval, we have the possibility of extending
|
||||||
|
it further to include data formats, higher-level constructs, and then to make
|
||||||
|
use of DOM references in more locations. This contributes to our goal of
|
||||||
|
simplifying Taskwarrior.
|
||||||
|
|
||||||
|
|
||||||
|
## Proposed Format Support
|
||||||
|
|
||||||
|
When defining a custom report, the columns shown are defined like this:
|
||||||
|
|
||||||
|
report.x.columns=uuid.short,description.oneline ...
|
||||||
|
|
||||||
|
This syntax is:
|
||||||
|
|
||||||
|
<attribute> [ . <format> ]
|
||||||
|
|
||||||
|
If no `format` is specified, then `default` is assumed. The src/columns/ColΧ\*
|
||||||
|
objects are responsible for supporting and rendering these formats. There is
|
||||||
|
currently no consistency among these formats based on data type.
|
||||||
|
|
||||||
|
By incorporating formats into DOM references, we eliminate the need for a
|
||||||
|
separate syntax for custom reports, and provide this:
|
||||||
|
|
||||||
|
123.due.iso
|
||||||
|
123.due.month.short
|
||||||
|
123.uuid.short
|
||||||
|
|
||||||
|
A standard set of formats per data type would be:
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
Formats
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
Numeric
|
||||||
|
|
||||||
|
default
|
||||||
|
|
||||||
|
`123 `
|
||||||
|
|
||||||
|
indicator
|
||||||
|
|
||||||
|
Based on `rc.<attribute>.indicator` which overrides `rc.numeric.indicator`.
|
||||||
|
|
||||||
|
json
|
||||||
|
|
||||||
|
`"<attribute>":"<value>"`
|
||||||
|
|
||||||
|
String
|
||||||
|
|
||||||
|
default
|
||||||
|
|
||||||
|
Buy milk
|
||||||
|
|
||||||
|
short
|
||||||
|
|
||||||
|
Feb
|
||||||
|
|
||||||
|
indicator
|
||||||
|
|
||||||
|
Based on `rc.<attribute>.indicator` which overrides `rc.string.indicator`.
|
||||||
|
|
||||||
|
json
|
||||||
|
|
||||||
|
`"<attribute>":"<value>"`
|
||||||
|
|
||||||
|
Date
|
||||||
|
|
||||||
|
default
|
||||||
|
|
||||||
|
Based on `rc.dateformat`
|
||||||
|
|
||||||
|
iso
|
||||||
|
|
||||||
|
2017-02-20T09:02:12
|
||||||
|
|
||||||
|
julian
|
||||||
|
|
||||||
|
2457805.12858
|
||||||
|
|
||||||
|
epoch
|
||||||
|
|
||||||
|
1234567890
|
||||||
|
|
||||||
|
age
|
||||||
|
|
||||||
|
2min
|
||||||
|
|
||||||
|
relative
|
||||||
|
|
||||||
|
-2min
|
||||||
|
|
||||||
|
remaining
|
||||||
|
|
||||||
|
0:02:04
|
||||||
|
|
||||||
|
countdown
|
||||||
|
|
||||||
|
0:02:04
|
||||||
|
|
||||||
|
indicator
|
||||||
|
|
||||||
|
Based on `rc.<attribute>.indicator` which overrides `rc.date.indicator`.
|
||||||
|
|
||||||
|
json
|
||||||
|
|
||||||
|
`"<attribute>":"<value>"`
|
||||||
|
|
||||||
|
Duration
|
||||||
|
|
||||||
|
default
|
||||||
|
|
||||||
|
1wk
|
||||||
|
|
||||||
|
iso
|
||||||
|
|
||||||
|
P1W
|
||||||
|
|
||||||
|
indicator
|
||||||
|
|
||||||
|
Based on `rc.<attribute>.indicator` which overrides `rc.duration.indicator`.
|
||||||
|
|
||||||
|
json
|
||||||
|
|
||||||
|
`"<attribute>":"<value>"`
|
||||||
|
|
||||||
|
There will also be a set of attribute-specific formats, similar to the currently
|
||||||
|
supported set:
|
||||||
|
|
||||||
|
depends.list
|
||||||
|
depends.count
|
||||||
|
description.combined
|
||||||
|
description.desc
|
||||||
|
description.oneline
|
||||||
|
description.truncated
|
||||||
|
description.count
|
||||||
|
description.truncated_count
|
||||||
|
parent.default|long
|
||||||
|
parent.short
|
||||||
|
project.full
|
||||||
|
project.parent
|
||||||
|
project.indented
|
||||||
|
status.default|long
|
||||||
|
status.short
|
||||||
|
tags.default|list
|
||||||
|
tags.count
|
||||||
|
urgency.default|real
|
||||||
|
urgency.integer
|
||||||
|
uuid.default|long
|
||||||
|
uuid.short
|
||||||
|
|
||||||
|
Custom report sort criteria will also use DOM references. This will be augmented
|
||||||
|
by the `+`/`-` sort direction and `/` break indicator, which are not part of the
|
||||||
|
DOM.
|
||||||
|
|
||||||
|
|
||||||
|
## High Level Construct Support
|
||||||
|
|
||||||
|
There need to be read-only DOM references that do not correspond directly to
|
||||||
|
stored attributes. Tasks have emergent properties represented by virtual tags,
|
||||||
|
which will be accessible, in this case returning a `0` or `1`:
|
||||||
|
|
||||||
|
123.tags.OVERDUE
|
||||||
|
|
||||||
|
Using `rc.due` and the `due` attribute, the `OVERDUE` virtual tag is a
|
||||||
|
combination of the two. Other examples may include:
|
||||||
|
|
||||||
|
task.syncneeded
|
||||||
|
task.pending.count
|
||||||
|
task.hooks.installed
|
||||||
|
|
||||||
|
|
||||||
|
## Writable References
|
||||||
|
|
||||||
|
When a DOM reference refers to an attribute or RC setting, and does not extend
|
||||||
|
further and reference a component or format, it may be writable. For example:
|
||||||
|
|
||||||
|
rc.hooks # writable
|
||||||
|
123.description # writable
|
||||||
|
123.entry.month # not writable, not an attribute
|
||||||
|
|
||||||
|
|
||||||
|
## Data Interchange
|
||||||
|
|
||||||
|
The export command can be used to show a filtered set of tasks in JSON format,
|
||||||
|
and this will also be available as a DOM format:
|
||||||
|
|
||||||
|
123.json
|
||||||
|
a87bc10f-931b-4558-a44a-e901a77db011.json
|
||||||
|
|
||||||
|
|
||||||
|
## RC File Support
|
||||||
|
|
||||||
|
The RC file (`~/.taskrc`) will support DOM references in values. This will form
|
||||||
|
a late-bound reference, which is evaluated at runtime, every time.
|
||||||
|
|
||||||
|
An example is to make two reports share the same description:
|
||||||
|
|
||||||
|
$ task config -- report.ls.description rc.report.list.description
|
||||||
|
|
||||||
|
This sets the description for the `ls` report to be a reference to the
|
||||||
|
description of the `list` report. This reference is not evaluated when the entry
|
||||||
|
is written, but is evaluated every time the value is read, thus providing
|
||||||
|
late-bound behavior. Then if the description of the `list` report changes, so
|
||||||
|
does that of the `ls` report automatically.
|
||||||
|
|
||||||
|
|
||||||
|
## Implementation Details
|
||||||
|
|
||||||
|
These notes list a series of anticipated changes to the codebase.
|
||||||
|
|
||||||
|
- The `src/columns/Col*` objects will implement type-specific and
|
||||||
|
attribute-specific DOM support. DOM reference lookup will defer to the
|
||||||
|
column objects first.
|
||||||
|
- Some DOM references will be writable, permitting a `_set` command to
|
||||||
|
complement the `_get` command.
|
||||||
|
- The `Config` object will recognize DOM references in values and perform
|
||||||
|
lookup at read time. This will require circularity detection.
|
||||||
|
- `src/DOM.cpp` will provide a memoized function to determine whether a DOM
|
||||||
|
reference is valid.
|
||||||
|
- `src/DOM.cpp` will provide a function to obtain a DOM reference value, with
|
||||||
|
supporting metadata (type, writable).
|
||||||
436
docs/rfcs/plans.md
Normal file
436
docs/rfcs/plans.md
Normal file
@@ -0,0 +1,436 @@
|
|||||||
|
---
|
||||||
|
title: "Plans"
|
||||||
|
---
|
||||||
|
|
||||||
|
There are many interconnected features and technologies in Taskwarrior,
|
||||||
|
Taskserver, Tasksh and Timewarrior, each piece having it's own goals.
|
||||||
|
|
||||||
|
This matrix allows a simple reading of where things are, and where they are
|
||||||
|
going. This is a low-resolution time line. It is subject to change. It does not
|
||||||
|
constitute a concrete plan. This is an all-volunteer effort, and scheduling is
|
||||||
|
difficult.
|
||||||
|
|
||||||
|
[Last updated 2016-08-08.]
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Taskwarrior<br />Technology/Feature</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-success">2.5.1</span><br />
|
||||||
|
Current<br /><br />
|
||||||
|
Released 2016-02-24
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-danger">2.6.0</span><br />
|
||||||
|
Next<br /><br />
|
||||||
|
2017
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-info">2.x</span><br />
|
||||||
|
Future
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Core</td>
|
||||||
|
<td>
|
||||||
|
<a href="/docs/dom.html">DOM</a><br />
|
||||||
|
Filters<br />
|
||||||
|
Expressions<br />
|
||||||
|
Color Rules<br />
|
||||||
|
Custom Reports<br />
|
||||||
|
Annotations<br />
|
||||||
|
Tags / Virtual Tags<br />
|
||||||
|
<a href="/docs/context.html">Context</a><br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/docs/design/recurrence.html">Recurrence</a><br />
|
||||||
|
Shared library<br />
|
||||||
|
<code>purge</code> command<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
True Color
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>API</td>
|
||||||
|
<td>
|
||||||
|
<a href="/docs/design/task.html">JSON</a><br />
|
||||||
|
Import<br />
|
||||||
|
Export<br />
|
||||||
|
<a href="/docs/hooks.html">Hooks</a><br />
|
||||||
|
<a href="/docs/hooks2.html">Hooks v2</a><br />
|
||||||
|
<a href="/docs/dom.html">DOM</a><br />
|
||||||
|
Helper commands<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>on-sync</code> hook<br />
|
||||||
|
Full DOM<br />
|
||||||
|
DOM access in rc<br />
|
||||||
|
<code>$ENV</code> access in rc<br />
|
||||||
|
Report columns as DOM refs<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Attributes<br />
|
||||||
|
<a href="/docs/udas.html">User Defined Attributes (UDA)</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>modified</code><br />
|
||||||
|
<code>priority</code> as a UDA<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>template</code><br />
|
||||||
|
<code>rtype</code><br />
|
||||||
|
Remove <code>mask</code><br />
|
||||||
|
Remove <code>imask</code><br />
|
||||||
|
Remove <code>parent</code><br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>org</code><br />
|
||||||
|
<code>group</code><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Reports</td>
|
||||||
|
<td>
|
||||||
|
Improved layouts<br />
|
||||||
|
Improved Themes
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Daily, Weekly reports (history, ghistory)<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Synchronization</td>
|
||||||
|
<td>
|
||||||
|
<code>task sync</code><br />
|
||||||
|
<code>task sync init</code> (all tasks)<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code>task sync reset</code><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>TDB (task database)</td>
|
||||||
|
<td>
|
||||||
|
Local file locking<br />
|
||||||
|
Single file set<br />
|
||||||
|
Single user
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Threaded file load<br />
|
||||||
|
Read-only mode
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>I18N / L10N</td>
|
||||||
|
<td>
|
||||||
|
UTF-8 support<br />
|
||||||
|
<code>deu-DEU</code><br />
|
||||||
|
<code>eng-USA</code><br />
|
||||||
|
<code>epo-RUS</code><br />
|
||||||
|
<code>esp-ESP</code><br />
|
||||||
|
<code>fra-FRA</code><br />
|
||||||
|
<code>ita-ITA</code><br />
|
||||||
|
<code>pol-POL</code><br />
|
||||||
|
<code>por-PRT</code><br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
No I18N / L10N
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Migrate to <a href="https://www.gnu.org/software/gettext/">gettext</a><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Documentation</td>
|
||||||
|
<td>
|
||||||
|
man: task<br />
|
||||||
|
man: taskrc<br />
|
||||||
|
man: task-color<br />
|
||||||
|
man: task-sync<br />
|
||||||
|
youtube: various<br />
|
||||||
|
<a href="https://taskwarrior.org">taskwarrior.org</a><br />
|
||||||
|
taskwarrior.com: Support Site<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
New video tutorials<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Testing</td>
|
||||||
|
<td>
|
||||||
|
C++ tests<br />
|
||||||
|
Python tests<br />
|
||||||
|
Sync tests<br />
|
||||||
|
Parallel tests<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Migration to Flod2<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Tool Chain</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.7 / Clang 3.3<br />
|
||||||
|
C++11 support<br />
|
||||||
|
CMake<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.9 / Clang 3.4<br />
|
||||||
|
Full C++11 support<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Full C++14 support<br />
|
||||||
|
Full C++17 support<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Tasksh<br />Technology/Feature</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-success">1.1.0</span><br />
|
||||||
|
Current<br /><br />
|
||||||
|
Released 2016-09-05
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-danger">1.2.0</span><br />
|
||||||
|
Next<br /><br />
|
||||||
|
2017
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-info">1.x</span><br />
|
||||||
|
Future
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Core</td>
|
||||||
|
<td>
|
||||||
|
<a href="/docs/review.html">Review</a><br />
|
||||||
|
libreadline<br />
|
||||||
|
Shared library<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Pomodoro timer<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Tool Chain</td>
|
||||||
|
<td>
|
||||||
|
CMake<br />
|
||||||
|
GCC 4.7 / Clang 3.3<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.9 / Clang 3.4<br />
|
||||||
|
Full C++11 support<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Full C++14 support<br />
|
||||||
|
Full C++17 support<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Taskserver<br />Technology/Feature</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-success">1.1.0</span><br />
|
||||||
|
Current<br /><br />
|
||||||
|
Released 2015-05-10
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-danger">1.2.0</span><br />
|
||||||
|
Next<br /><br />
|
||||||
|
2017
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-info">1.x</span><br />
|
||||||
|
Future
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Core</td>
|
||||||
|
<td>
|
||||||
|
Serial server
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Shared library<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Threaded server
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Protocol</td>
|
||||||
|
<td>
|
||||||
|
v1
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
v1.1 - client reset request<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
v1.2
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>DB (Data Storage)</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
GC
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Security</td>
|
||||||
|
<td>
|
||||||
|
Validation
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
UUID:Cert Verification<br />
|
||||||
|
Combined Certs
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Tool Chain</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.7 / Clang 3.3<br />
|
||||||
|
CMake<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.9 / Clang 3.4<br />
|
||||||
|
Full C++11 support<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Full C++14 support<br />
|
||||||
|
Full C++17 support<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>Timewarrior<br />Technology/Feature</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-success">1.0.0</span><br />
|
||||||
|
Current<br /><br />
|
||||||
|
Released 2016-08-20
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-danger">1.1.0</span><br />
|
||||||
|
Next<br /><br />
|
||||||
|
2017
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<span class="label label-info">1.x</span><br />
|
||||||
|
Future
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Core</td>
|
||||||
|
<td>
|
||||||
|
Shared library<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
True Color
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Reports</td>
|
||||||
|
<td>
|
||||||
|
<code>summary</code> report<br />
|
||||||
|
<code>gaps</code> report<br />
|
||||||
|
<code>day</code> chart<br />
|
||||||
|
<code>week</code> chart<br />
|
||||||
|
<code>month</code> chart<br />
|
||||||
|
<code>totals.py</code> extension<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Rules</td>
|
||||||
|
<td>
|
||||||
|
Simple configuration rules
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Rule System<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Integration</td>
|
||||||
|
<td>
|
||||||
|
Taskwarrior <code>on-modify</code> hook script
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Tool Chain</td>
|
||||||
|
<td>
|
||||||
|
CMake<br />
|
||||||
|
GCC 4.7 / Clang 3.3<br />
|
||||||
|
C++11 support<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
GCC 4.9 / Clang 3.4<br />
|
||||||
|
Full C++11 support<br />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Full C++14 support<br />
|
||||||
|
Full C++17 support<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
211
docs/rfcs/protocol.md
Normal file
211
docs/rfcs/protocol.md
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Sync Protocol"
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Sync Protocol
|
||||||
|
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Taskwarrior data has typically been shared in several ways. Those include SCM
|
||||||
|
(source code management) systems, directory synchronizing software (such as
|
||||||
|
DropBox), and by use of the \'push\', \'pull\' and \'merge\' commands introduced
|
||||||
|
in version 1.9.3.
|
||||||
|
|
||||||
|
While these methods work, they each have problems associated with the merging of
|
||||||
|
data. In the case of directory synchronizing software, there is no merging at
|
||||||
|
all - just simple file overwrite, despite many people believing that the data is
|
||||||
|
somehow combined and preserved.
|
||||||
|
|
||||||
|
The Taskserver is a solution. It is an online/cloud storage and sync service for
|
||||||
|
taskwarrior data. It performs conflict-free data merging, and minimizes
|
||||||
|
bandwidth use.
|
||||||
|
|
||||||
|
The Taskserver also provides multi-client access, so that a task added using a
|
||||||
|
web client could be immediately viewed using a mobile client, or modified using
|
||||||
|
taskwarrior. Choice of clients is important - people have widely varying
|
||||||
|
behaviors and tastes.
|
||||||
|
|
||||||
|
The Taskserver also provides multi-user access, which introduces new
|
||||||
|
capabilities, such as list sharing and delegation. These will require later
|
||||||
|
modification to this protocol.
|
||||||
|
|
||||||
|
The Taskserver protocol will be implemented by the taskd project and first used
|
||||||
|
in taskwarrior 2.3.0. Other clients will follow.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In this document, we adopt the convention discussed in Section 1.3.2 of
|
||||||
|
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized
|
||||||
|
words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the
|
||||||
|
significance of each particular requirement specified in this document.
|
||||||
|
|
||||||
|
In brief: \"MUST\" (or \"REQUIRED\") means that the item is an absolute
|
||||||
|
requirement of the specification; \"SHOULD\" (or \"RECOMMENDED\") means there
|
||||||
|
may exist valid reasons for ignoring this item, but the full implications should
|
||||||
|
be understood before doing so; and \"MAY\" (or \"OPTIONAL\") means that this
|
||||||
|
item is optional, and may be omitted without careful consideration.
|
||||||
|
|
||||||
|
|
||||||
|
## Link Level
|
||||||
|
|
||||||
|
The Taskserver protocol assumes a reliable data stream such as provided by TCP.
|
||||||
|
When TCP is used, a Taskserver listens on a single predetermined port *for the
|
||||||
|
given client* only. This means the server may be using multiple ports to serve
|
||||||
|
distinct sets of clients.
|
||||||
|
|
||||||
|
This server is only an interface between programs and the task data. It does not
|
||||||
|
perform any user interaction or presentation-level functions.
|
||||||
|
|
||||||
|
|
||||||
|
## Transactions
|
||||||
|
|
||||||
|
Each transaction is a single incoming message, with a single response message.
|
||||||
|
All communication therefore consists of a single \'send\', followed by a single
|
||||||
|
\'receive\', then termination. There are no sessions, and no continuously open
|
||||||
|
connections. The message format is described in the [Taskserver Message
|
||||||
|
Format](/docs/design/request) document.
|
||||||
|
|
||||||
|
|
||||||
|
## Responsibilities of the Server
|
||||||
|
|
||||||
|
The server will maintain a set of transactions, in the original sequence,
|
||||||
|
punctuated by sync keys which are UUIDs. Each sync key represents a non- trivial
|
||||||
|
sync operation by a client. Each transaction is a [JSON-formatted
|
||||||
|
task](/docs/design/task), followed by a newline (\\n) character. The result
|
||||||
|
is a single file that contains interleaved lines of two types: tasks and sync
|
||||||
|
keys.
|
||||||
|
|
||||||
|
This design allows the server to maintain a set of deltas such that multiple
|
||||||
|
clients may request a minimal set of changes since their last sync.
|
||||||
|
|
||||||
|
|
||||||
|
## Responsibilities of the Client
|
||||||
|
|
||||||
|
This describes how Taskwarrior implements sync.
|
||||||
|
|
||||||
|
All modifications to tasks (add, modify, done, delete \...) are recorded in the
|
||||||
|
form of a fully-composed [JSON-formatted task](/docs/design/task). The
|
||||||
|
formatted task is added to a local backlog.data file. If a task is modified a
|
||||||
|
second time, it is added again to the backlog.data file - the lines are not
|
||||||
|
combined. Each task SHALL have a \'modified\' date attribute that will help
|
||||||
|
resolve conflicts.
|
||||||
|
|
||||||
|
On sync:
|
||||||
|
|
||||||
|
- Send a \'sync\' type message with the entire contents of the backlog.data,
|
||||||
|
unmodified, as the message payload.
|
||||||
|
- Receive one of the following response codes:
|
||||||
|
- 201: This means \'no change\', and there is no further action to be
|
||||||
|
taken.
|
||||||
|
- 200: This means \'success\', and the message payload contains a set of
|
||||||
|
tasks and a sync key:
|
||||||
|
- The formatted tasks are to be stored as-is. These tasks will either
|
||||||
|
be appended to the client data or will overwrite existing client
|
||||||
|
data, based on the UUID of the task. No merge logic is necessary.
|
||||||
|
- The sync key will be written to the backlog.data file, overwriting
|
||||||
|
the previous contents, such that it will now contain only one line.
|
||||||
|
- 301: Redirect to : found in the \'info\' response header, will force the
|
||||||
|
client to resubmit the request to the new server.
|
||||||
|
- 3xx, 4xx, 5xx: The \'status\' field contains an error message.
|
||||||
|
- If the response contained any error or warning, the error should be shown to
|
||||||
|
the user. This provides an opportunity for the server to announce downtime,
|
||||||
|
or relocation.
|
||||||
|
|
||||||
|
If no sync key is sent, the server cannot provide an incremental delta, and so
|
||||||
|
will send all task data, which should be stored as above. This should be the
|
||||||
|
case for a client making its first sync call.
|
||||||
|
|
||||||
|
If an unrecognized attribute is present in the task data, the client MUST
|
||||||
|
preserve the attribute unmodified, and assume it is of type \'string\'. This
|
||||||
|
permits individual clients to augment the task data without other clients
|
||||||
|
stripping it meaningful data. This is how UDAs (user defined attributes) are
|
||||||
|
handled.
|
||||||
|
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
|
This protocol was designed so that extensions to the protocol will take the form
|
||||||
|
of additional message types and status codes.
|
||||||
|
|
||||||
|
|
||||||
|
## Summary of Response Codes
|
||||||
|
|
||||||
|
Status responses indicate the server\'s response to the last command received
|
||||||
|
from the client. The codes consist of a 3 digit numeric code.
|
||||||
|
|
||||||
|
The first digit of the response broadly indicates the success, failure, or
|
||||||
|
progress of the previous command (based generally on
|
||||||
|
[RFC640](https://tools.ietf.org/html/rfc640)
|
||||||
|
[RFC821](https://tools.ietf.org/html/rfc821)):
|
||||||
|
|
||||||
|
----- -------------------------------------
|
||||||
|
1yz Positive Preliminary reply
|
||||||
|
2yz Positive Completion reply
|
||||||
|
3yz Positive Intermediate reply
|
||||||
|
4yz Transient Negative Completion reply
|
||||||
|
5yz Permanent Negative Completion reply
|
||||||
|
----- -------------------------------------
|
||||||
|
|
||||||
|
The next digit in the code indicates the response category:
|
||||||
|
|
||||||
|
----- -------------------------------------------------
|
||||||
|
x0z Syntax
|
||||||
|
x1z Information (e.g., help)
|
||||||
|
x2z Connections
|
||||||
|
x3z Authentication
|
||||||
|
x4z Unspecified as yet
|
||||||
|
x5z Taskd System (\...)
|
||||||
|
x8z Nonstandard (private implementation) extensions
|
||||||
|
----- -------------------------------------------------
|
||||||
|
|
||||||
|
A summary of all status response are:
|
||||||
|
|
||||||
|
----- -----------
|
||||||
|
200 Success
|
||||||
|
201 No change
|
||||||
|
----- -----------
|
||||||
|
|
||||||
|
----- ----------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
300 Deprecated message type. This message will not be supported in future Taskserver releases.
|
||||||
|
301 Redirect. Further requests should be made to the specified server/port.
|
||||||
|
302 Retry. The client is requested to wait and retry the same request. The wait time is not specified, and further retry responses are possible.
|
||||||
|
----- ----------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
----- ------------------------------------------
|
||||||
|
400 Malformed data
|
||||||
|
401 Unsupported encoding
|
||||||
|
420 Server temporarily unavailable
|
||||||
|
421 Server shutting down at operator request
|
||||||
|
430 Access denied
|
||||||
|
431 Account suspended
|
||||||
|
432 Account terminated
|
||||||
|
----- ------------------------------------------
|
||||||
|
|
||||||
|
----- -----------------------------------
|
||||||
|
500 Syntax error in request
|
||||||
|
501 Syntax error, illegal parameters
|
||||||
|
502 Not implemented
|
||||||
|
503 Command parameter not implemented
|
||||||
|
504 Request too big
|
||||||
|
----- -----------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
All communication with the Taskserver uses SSL 3.0 or TLS 1.0, 1.1 or 1.2.
|
||||||
|
Encryption is mandatory. Data is never transmitted in plain text.
|
||||||
|
|
||||||
|
|
||||||
|
## Limitations and Guidelines
|
||||||
|
|
||||||
|
Some limitations exists to reduce bandwidth and load on the server. They are:
|
||||||
|
|
||||||
|
- A client may only connect to a single server. Synchronization among a set of
|
||||||
|
servers is not supported.
|
||||||
|
- A client should attempt to minimize data bandwidth usage by maintaining a
|
||||||
|
local data store, and properly using sync keys.
|
||||||
|
- A client should minimize data transfers by limiting the frequency of sync
|
||||||
|
requests.
|
||||||
203
docs/rfcs/recurrence.md
Normal file
203
docs/rfcs/recurrence.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Recurrence"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Draft
|
||||||
|
|
||||||
|
This is a draft design document. Your
|
||||||
|
[feedback](mailto:support@taskwarrior.org?Subject=Feedback) is welcomed.
|
||||||
|
|
||||||
|
Recurrence
|
||||||
|
----------
|
||||||
|
|
||||||
|
Recurrence needs an overhaul to improve weaknesses and add new features.
|
||||||
|
|
||||||
|
# Terminology
|
||||||
|
|
||||||
|
- The hidden 'parent' task is called the template.
|
||||||
|
- Synthesis is the name for the generation of new recurring task instances
|
||||||
|
when necessary.
|
||||||
|
- The synthesized tasks are called instances.
|
||||||
|
- The index is the zero-based monotonically increasing number of the instance.
|
||||||
|
- Drift is the accumulated errors in time that cause a due date to slowly
|
||||||
|
change for each recurring task.
|
||||||
|
|
||||||
|
# Criticism of Current Implementation
|
||||||
|
|
||||||
|
- The `mask` attribute grows unbounded.
|
||||||
|
- Only strict recurrence cycles are supported. The example of mowing the lawn
|
||||||
|
is that you want to mow the lawn every seven days, but when you are four
|
||||||
|
days late mowing the lawn, the next mowing should be in seven days, not in
|
||||||
|
three.
|
||||||
|
- Intances generated on one machine and then synced, may collide with
|
||||||
|
equivalent unsynced instances tasks on another device, because the UUIDs are
|
||||||
|
different.
|
||||||
|
- You cannot `wait` a recurring task and have that wait period propagate to
|
||||||
|
all other child tasks.
|
||||||
|
- Task instances cannot individually expire.
|
||||||
|
|
||||||
|
# Proposals
|
||||||
|
|
||||||
|
## Proposal: Eliminate `mask`, `imaѕk` Attributes
|
||||||
|
|
||||||
|
The `mask` attribute in the template is replaced by `last`, which indicates the
|
||||||
|
most recent instance index synthesized. Because instances are never synthesized
|
||||||
|
out of order, we only need to store the most recent index. The `imask` attribute
|
||||||
|
in the instance is no longer needed.
|
||||||
|
|
||||||
|
## Proposal: Rename `parent` to `template`
|
||||||
|
|
||||||
|
The name `parent` implies subtasks, and confuses those who inspect the
|
||||||
|
internals. The value remains the UUID of the template. This frees up the
|
||||||
|
namespace for future use with subtasks.
|
||||||
|
|
||||||
|
## Proposal: New 'rtype' attribute
|
||||||
|
|
||||||
|
To indicate the flavor of recurrence, support the following values:
|
||||||
|
|
||||||
|
* `periodic` - Instances are created on a regular schedule. Example: send birthday flowers. It must occur on a regular schedule, and doesn't matter if you were late last year. This is the default value.
|
||||||
|
* `chained` - Instances are created back to back, so when one instance ends, the next begins, with the same recurrence. Example: mow the lawn. If you mow two days late, the next instance is not two days early to compensate.
|
||||||
|
|
||||||
|
## Proposal: Use relative offsets
|
||||||
|
|
||||||
|
The delta between `wait` and `due` date in the template should be reflected in
|
||||||
|
the delta between `wait` and `due` date in the instance. Similarly,
|
||||||
|
'scheduled' must be handled the same way.
|
||||||
|
|
||||||
|
## Proposal: On load, auto-upgrade legacy tasks
|
||||||
|
|
||||||
|
Upgrade template:
|
||||||
|
|
||||||
|
- Add `rtype:periodic`
|
||||||
|
- Add `last:N` where `N` is the length of `mask`
|
||||||
|
- Delete `mask`
|
||||||
|
|
||||||
|
Upgrade instance:
|
||||||
|
|
||||||
|
- Rename `parent` to `template`
|
||||||
|
- Delete `imask`
|
||||||
|
- Update `wait` if not set to: `wait:due + (template.due - template.wait)`
|
||||||
|
- Update `scheduled` if not set to:
|
||||||
|
`scheduled:due + (template.due - template.scheduled)`
|
||||||
|
|
||||||
|
## Proposal: Deleting a chained instance
|
||||||
|
|
||||||
|
Deleting a `rtype:chained` instance causes the next chained instance to be
|
||||||
|
synthesized. This gives the illusion that the due date is simply pushed out to
|
||||||
|
`(now + template.recur)`.
|
||||||
|
|
||||||
|
## Proposal: Modification Propagation
|
||||||
|
|
||||||
|
TBD
|
||||||
|
|
||||||
|
## Proposal: Exotic Dates
|
||||||
|
|
||||||
|
Expand date specifications to use pattern phrases:
|
||||||
|
|
||||||
|
- `4th thursday in November`
|
||||||
|
- `4th thursday of November`
|
||||||
|
- `Friday before easter`
|
||||||
|
- `next Tuesday`
|
||||||
|
- `last Tuesday`
|
||||||
|
- `last July`
|
||||||
|
- `weekend`
|
||||||
|
- `3 days before eom`
|
||||||
|
- `in the morning`
|
||||||
|
- `4pm`
|
||||||
|
- `noon`
|
||||||
|
- `midnight`
|
||||||
|
|
||||||
|
Got suggestions?
|
||||||
|
|
||||||
|
## Proposal: User-Defined Week Start
|
||||||
|
|
||||||
|
TBD
|
||||||
|
|
||||||
|
# Implementation
|
||||||
|
|
||||||
|
## Implementation: Adding a new `periodic` template
|
||||||
|
|
||||||
|
When adding a new periodic template:
|
||||||
|
|
||||||
|
task add ... due:D recur:R wait:D-1wk scheduled:D-1wk until:U
|
||||||
|
|
||||||
|
Creates:
|
||||||
|
|
||||||
|
template.uuid: NEW_UUID
|
||||||
|
template.description: ...
|
||||||
|
template.entry: now
|
||||||
|
template.modified: now
|
||||||
|
template.due: D
|
||||||
|
template.recur: R (stored in raw form, ie 'P14D')
|
||||||
|
template.wait: D-1wk
|
||||||
|
template.scheduled: D-1wk
|
||||||
|
template.until: U
|
||||||
|
template.rtype: periodic
|
||||||
|
template.last:
|
||||||
|
|
||||||
|
Creating the Nth instance (index N):
|
||||||
|
|
||||||
|
Clone instance from template.
|
||||||
|
|
||||||
|
instance.uuid: NEW_UUID
|
||||||
|
instance.modified: now
|
||||||
|
instance.due: template.due + (N * template.recur)
|
||||||
|
instance.wait: instance.due + (template.due - template.wait)
|
||||||
|
instance.scheduled: instance.due + (template.due - template.scheduled)
|
||||||
|
instance.start:
|
||||||
|
|
||||||
|
template.last: N
|
||||||
|
|
||||||
|
## Implementation: Adding a new `chained` template
|
||||||
|
|
||||||
|
When adding a new chained template:
|
||||||
|
|
||||||
|
task add ... due:D recur:R wait:D-1wk scheduled:D-1wk until:U rtype:chained
|
||||||
|
|
||||||
|
Creates:
|
||||||
|
|
||||||
|
template.uuid: NEW_UUID
|
||||||
|
template.description: ...
|
||||||
|
template.entry: now
|
||||||
|
template.modified: now
|
||||||
|
template.due: D
|
||||||
|
template.recur: R (stored in raw form, ie 'P14D')
|
||||||
|
template.wait: D-1wk
|
||||||
|
template.scheduled: D-1wk
|
||||||
|
template.until: U
|
||||||
|
template.rtype: chained
|
||||||
|
|
||||||
|
Creating the Nth instance (index N):
|
||||||
|
|
||||||
|
Clone instance from template.
|
||||||
|
|
||||||
|
instance.uui d: NEW_UUID
|
||||||
|
instance.mod ified: now
|
||||||
|
instance.due : instance[N-1].end + template.recur
|
||||||
|
instance.wai t: instance.due + (template.due - template.wait)
|
||||||
|
instance.sch eduled: instance.due + (template.due - template.scheduled)
|
||||||
|
instance.sta rt:
|
||||||
|
|
||||||
|
Chained tasks do not obey `rc.recurrence.limit`, and show only one pending task
|
||||||
|
at a time.
|
||||||
|
|
||||||
|
## Implementation: Special handling for months
|
||||||
|
|
||||||
|
Certain recurrence periods are inexact:
|
||||||
|
|
||||||
|
- P1M
|
||||||
|
- P1Y
|
||||||
|
- P1D
|
||||||
|
|
||||||
|
When the recurrence period is `P1M` the number of days in a month varies and
|
||||||
|
causes drift.
|
||||||
|
|
||||||
|
When the recurrence period is `P1Y` the number of days in a year varies and
|
||||||
|
causes drift.
|
||||||
|
|
||||||
|
When the recurrence period is `P1D` the number of hours in a day varies due to
|
||||||
|
daylight savings, and causes drift.
|
||||||
|
|
||||||
|
Drift should be avoided by carefully implementing:
|
||||||
|
|
||||||
|
instance.due: template.due + (N * template.recur)
|
||||||
221
docs/rfcs/request.md
Normal file
221
docs/rfcs/request.md
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Request"
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Taskserver Message Format
|
||||||
|
|
||||||
|
The Taskserver accepts and emits only messages. These messages look somewhat
|
||||||
|
like email, as defined in [RFC821](https://tools.ietf.org/html/rfc821),
|
||||||
|
[RFC2822](https://tools.ietf.org/html/rfc2822).
|
||||||
|
|
||||||
|
The message format allows for data, metadata, and extensibility. This
|
||||||
|
combination allows the Taskserver to accommodate current and future needs. This
|
||||||
|
document describes the message format, and the supported message types.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In this document, we adopt the convention discussed in Section 1.3.2 of
|
||||||
|
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized
|
||||||
|
words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the
|
||||||
|
significance of each particular requirement specified in this document.
|
||||||
|
|
||||||
|
In brief: \"MUST\" (or \"REQUIRED\") means that the item is an absolute
|
||||||
|
requirement of the specification; \"SHOULD\" (or \"RECOMMENDED\") means there
|
||||||
|
may exist valid reasons for ignoring this item, but the full implications should
|
||||||
|
be understood before doing so; and \"MAY\" (or \"OPTIONAL\") means that this
|
||||||
|
item is optional, and may be omitted without careful consideration.
|
||||||
|
|
||||||
|
|
||||||
|
## Encoding
|
||||||
|
|
||||||
|
All messages are UTF8-encoded text.
|
||||||
|
|
||||||
|
|
||||||
|
## Message Format
|
||||||
|
|
||||||
|
This format is based on [RFC2822](https://tools.ietf.org/html/rfc2822),
|
||||||
|
\'Internet Message Format\'. Here is an example of the format:
|
||||||
|
|
||||||
|
<SIZE>
|
||||||
|
name: value
|
||||||
|
name2: value2
|
||||||
|
|
||||||
|
payload
|
||||||
|
|
||||||
|
There are three sections. The first is the size, which is a 4-byte, big- Endian,
|
||||||
|
binary byte count of the length of the message, including the 4 bytes for the
|
||||||
|
size.
|
||||||
|
|
||||||
|
The header section is a set of name/value pairs separated by newline characters
|
||||||
|
(U+000D). The name is separated from the value by \': \' (colon U+003A, space
|
||||||
|
U+0020) The header section is terminated by two consecutive newline (U+000D)
|
||||||
|
characters. All text is UTF8-encoded.
|
||||||
|
|
||||||
|
The payload section is arbitrary, and message type-specific. However, it is
|
||||||
|
still UTF8-encoded text.
|
||||||
|
|
||||||
|
|
||||||
|
## Message Requirements
|
||||||
|
|
||||||
|
Messages SHALL contain particular headers. Those are:
|
||||||
|
|
||||||
|
- type
|
||||||
|
- protocol
|
||||||
|
- client
|
||||||
|
|
||||||
|
The \'type\' value is what determines the interpretation of the payload.
|
||||||
|
|
||||||
|
The \'protocol\' value should be \'v1\', or any subsequently published protocol
|
||||||
|
version.
|
||||||
|
|
||||||
|
The \'client\' represent the client identifier, so that any special cases can be
|
||||||
|
handled. For example, an emergency fix that is client version-specific could be
|
||||||
|
released, to support users that have not updated their client, or perhaps the
|
||||||
|
client has not released a fix. The form of the \'version\' value is:
|
||||||
|
|
||||||
|
<product identifier> <version number>
|
||||||
|
|
||||||
|
As an example:
|
||||||
|
|
||||||
|
taskwarrior 2.3.0
|
||||||
|
|
||||||
|
DO NOT spoof any other software using this client value. If another client is
|
||||||
|
spoofed, then patches addressing protocol errors may break working software.
|
||||||
|
|
||||||
|
|
||||||
|
## Auth Data
|
||||||
|
|
||||||
|
Every request from the client SHALL contain \"auth\" information, which involves
|
||||||
|
these header entries:
|
||||||
|
|
||||||
|
org: <organization>
|
||||||
|
user: <user>
|
||||||
|
key: <key>
|
||||||
|
|
||||||
|
The user and org fields uniquely identify a user.
|
||||||
|
|
||||||
|
The key field is generated when a new server account is set up. It is a shared
|
||||||
|
secret, equivalent to a password, and should be protected.
|
||||||
|
|
||||||
|
Authentication failure can result in these errors:
|
||||||
|
|
||||||
|
- 430 Authentication failed
|
||||||
|
- 431 Account suspended
|
||||||
|
|
||||||
|
|
||||||
|
## Status Data
|
||||||
|
|
||||||
|
Every response from the Taskserver SHALL contain status data:
|
||||||
|
|
||||||
|
code: <code>
|
||||||
|
status: <status text>
|
||||||
|
|
||||||
|
The code is a numeric status indicator defined in the [Sync
|
||||||
|
Protocol](/docs/design/protocol).
|
||||||
|
|
||||||
|
|
||||||
|
## Payload Data
|
||||||
|
|
||||||
|
Payload data is optional, arbitrary and message type dependent. It is always
|
||||||
|
UTF8-encoded text.
|
||||||
|
|
||||||
|
|
||||||
|
## Message Types
|
||||||
|
|
||||||
|
The Taskserver supports several message types, thus providing a set of
|
||||||
|
primitives for use by clients.
|
||||||
|
|
||||||
|
It is expected that the number of supported ticket types will increase over
|
||||||
|
time.
|
||||||
|
|
||||||
|
|
||||||
|
## Sync Message
|
||||||
|
|
||||||
|
The \"sync\" message always originates from the client, but the response will
|
||||||
|
contain data from the server. A sync is therefore a single request with a single
|
||||||
|
response.
|
||||||
|
|
||||||
|
The \"sync\" message type MUST contain the following headers:
|
||||||
|
|
||||||
|
- type
|
||||||
|
- org
|
||||||
|
- user
|
||||||
|
- key
|
||||||
|
- client
|
||||||
|
- protocol
|
||||||
|
|
||||||
|
The \"sync\" message payload has this format:
|
||||||
|
|
||||||
|
<uuid>
|
||||||
|
<JSON task 1>
|
||||||
|
<JSON task 2>
|
||||||
|
...
|
||||||
|
<JSON task N>
|
||||||
|
|
||||||
|
Here is an example of a sync message:
|
||||||
|
|
||||||
|
<size>type: sync
|
||||||
|
org: <organization>
|
||||||
|
user: <user>
|
||||||
|
key: <key>
|
||||||
|
client: task 2.3.0
|
||||||
|
protocol: v1
|
||||||
|
|
||||||
|
2e4685f8-34bc-4f9b-b7ed-399388e182e1
|
||||||
|
{"description":"Test data","entry":"20130602T002341Z","status":"pending"}
|
||||||
|
|
||||||
|
The request contains the proper auth section, and the body contains the current
|
||||||
|
sync key followed by a newline characters (U+000D), then a list of
|
||||||
|
JSON-formatted tasks \[2\] each separated by a newline character (U+000D).
|
||||||
|
|
||||||
|
An example response message might be:
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 200
|
||||||
|
status: Ok
|
||||||
|
|
||||||
|
45da7110-1bcc-4318-d33e-12267a774e0f
|
||||||
|
|
||||||
|
The status indicates success, and the payload contains zero remote task
|
||||||
|
modifications, followed by a sync key.
|
||||||
|
|
||||||
|
|
||||||
|
## Statistics Message
|
||||||
|
|
||||||
|
The message format іs simply:
|
||||||
|
|
||||||
|
<size>type: statistics
|
||||||
|
org: <Organization>
|
||||||
|
user: <User>
|
||||||
|
key: <Key>
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
|
||||||
|
There is no payload. An example response message might be:
|
||||||
|
|
||||||
|
<size>type: response
|
||||||
|
client: taskd 1.0.0
|
||||||
|
protocol: v1
|
||||||
|
code: 200
|
||||||
|
status: Ok
|
||||||
|
average request bytes: 0
|
||||||
|
average response bytes: 0
|
||||||
|
average response time: 0.000000
|
||||||
|
errors: 0
|
||||||
|
idle: 1.000000
|
||||||
|
maximum response time: 0.000000
|
||||||
|
total bytes in: 0
|
||||||
|
total bytes out: 0
|
||||||
|
tps: 0.000000
|
||||||
|
transactions: 1
|
||||||
|
uptime: 28
|
||||||
|
|
||||||
|
There is no payload, and the results are in the header variables.
|
||||||
|
|
||||||
|
Note that the statistics gathered by the server are growing, which means new
|
||||||
|
values are occasionally added to the response message. Existing values will not
|
||||||
|
be removed.
|
||||||
231
docs/rfcs/rules.md
Normal file
231
docs/rfcs/rules.md
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Rule System"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work in Progress
|
||||||
|
|
||||||
|
This design document is a work in progress, and subject to change. Once
|
||||||
|
finalized, the feature will be scheduled for an upcoming release.
|
||||||
|
|
||||||
|
|
||||||
|
# Rule System
|
||||||
|
|
||||||
|
The rule system is a framework that supports highly configurable features, with
|
||||||
|
runtime evaluation, DOM access and an internal API. Implementing a rule system
|
||||||
|
meets the goal of shrinking and stabilizing the product core, while adding new
|
||||||
|
features, and enabling many more.
|
||||||
|
|
||||||
|
|
||||||
|
## Required Enhancements
|
||||||
|
|
||||||
|
To prepare for a Rules System, various subsystems must first be enhanced:
|
||||||
|
|
||||||
|
- DOM references need to be unambiguous, and will all have the `dom.` prefix.
|
||||||
|
|
||||||
|
- DOM references need to be able to access any Taskwarrior data, in any
|
||||||
|
|
||||||
|
- Custom reports will change from referencing `<column>[.<format>]` to simply
|
||||||
|
`<domref>`
|
||||||
|
|
||||||
|
- RC file syntax needs to be enhanced, so support rule definitions, which are
|
||||||
|
multi-line blocks that are indentation-sensitive
|
||||||
|
|
||||||
|
- RC file syntax will support two ways of specifying the same data:
|
||||||
|
|
||||||
|
a.b.c=...
|
||||||
|
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c=...
|
||||||
|
|
||||||
|
- RC file syntax will allow the use of environment variables inline:
|
||||||
|
|
||||||
|
name=${TERM}
|
||||||
|
include ${HOME}/.taskrc_local
|
||||||
|
|
||||||
|
- The `Variant` object will migrate to `libshared`
|
||||||
|
|
||||||
|
- The expression evaluator `Eval` object will migrate to `libshared`
|
||||||
|
|
||||||
|
- The column objects will gain a more structured base class, and will serve as
|
||||||
|
providers for DOM references
|
||||||
|
|
||||||
|
- The \'exec\' command will be able to run a rule, if the reference is correct
|
||||||
|
|
||||||
|
- Taskwarrior will store state data in a new `state.data` file
|
||||||
|
|
||||||
|
- `Config` object needs to use the `rat` parser, to tackle the more complex
|
||||||
|
syntax
|
||||||
|
|
||||||
|
- The RC file will support environment variable expansion, where `${NAME}`
|
||||||
|
will be replaced by its corresponding value at launch time
|
||||||
|
|
||||||
|
At that point, the rules system can be implemented in `libshared`, and will use
|
||||||
|
a pluggable architecture to allow its integration into several projects.
|
||||||
|
|
||||||
|
|
||||||
|
## DOM Enhancements
|
||||||
|
|
||||||
|
DOM references will be enhanced, with many more references supported. All DOM
|
||||||
|
references will begin with `dom.`, yielding unambiguous references. References
|
||||||
|
will have a type. Types will support sub-references (`<date>.<month>`,
|
||||||
|
`<tags>.<N>`, `<annotation>.<description>`), and display formats included.
|
||||||
|
|
||||||
|
dom . [<id> .] <attribute> [. <sub-reference>] . <format>
|
||||||
|
|
||||||
|
dom . 123 . entry . year . yyyy
|
||||||
|
dom . 123 . entry
|
||||||
|
dom . 123 . tags
|
||||||
|
dom . 123 . tags . count
|
||||||
|
dom . 123 . tags . 1
|
||||||
|
|
||||||
|
In addition to direct attribute access, DOM references will also support tw
|
||||||
|
references beyond the current set:
|
||||||
|
|
||||||
|
dom.rc.<name>
|
||||||
|
dom.cli.args
|
||||||
|
dom.terminal.width
|
||||||
|
dom.terminal.height
|
||||||
|
dom.system.version
|
||||||
|
dom.system.oѕ
|
||||||
|
|
||||||
|
And will also support higher-level constructs that do not directly correlate to
|
||||||
|
attributes, for example:
|
||||||
|
|
||||||
|
dom.active Boolean indicator of any active tasks
|
||||||
|
dom.synced Boolean indicator of the need to sync
|
||||||
|
dom.rc.path String path of .taskrc file (or override)
|
||||||
|
dom.data.path String path of data directory
|
||||||
|
dom.hooks.path String path of hooks directory
|
||||||
|
|
||||||
|
Finally, access to state:
|
||||||
|
|
||||||
|
dom.state.program
|
||||||
|
dom.state.sync.last
|
||||||
|
dom.state.sync.configured
|
||||||
|
dom.state.run.last
|
||||||
|
dom.state.context
|
||||||
|
|
||||||
|
|
||||||
|
## RC Syntax Changes
|
||||||
|
|
||||||
|
The current configuration system supports only two different forms of syntax:
|
||||||
|
|
||||||
|
<name> = [ <value> ]
|
||||||
|
|
||||||
|
include <file>
|
||||||
|
|
||||||
|
A rule is a new form of syntax that consists of the rule keyword, a name,
|
||||||
|
optional trigger, followed by indented actions in the form of API calls and flow
|
||||||
|
control. For example:
|
||||||
|
|
||||||
|
rule myRule() on_launch:
|
||||||
|
# Some code here
|
||||||
|
|
||||||
|
A rule definition will appear in the RC file, alongside all the existing
|
||||||
|
settings. The rule syntax will require a blank line to terminate the rule
|
||||||
|
definition, the result being that the RC file should be quite readable, although
|
||||||
|
it will look like Python.
|
||||||
|
|
||||||
|
|
||||||
|
## Hook Scripts
|
||||||
|
|
||||||
|
While this functionality can also be implemented using hook scripts, rules will
|
||||||
|
run in-process, and therefore do not require external interpreters to be
|
||||||
|
launched every time. This creates the potential to run faster than a hook
|
||||||
|
script.
|
||||||
|
|
||||||
|
For complex processing, hook scripts will be the preferred mechanism, but as the
|
||||||
|
rules system matures, rules will be made to run more quickly. With adequate
|
||||||
|
performance, a rule will be the preferred implementation over a hook script.
|
||||||
|
This is not expected to be the case at first.
|
||||||
|
|
||||||
|
Hook scripts are not likely to be extended beyond their current form, and with
|
||||||
|
greater DOM access and a growing API, rules should be able to supplant most hook
|
||||||
|
script use cases.
|
||||||
|
|
||||||
|
|
||||||
|
## Rule Triggers
|
||||||
|
|
||||||
|
The set of supported rule types will include:
|
||||||
|
|
||||||
|
* `on_launch` - Triggered on program launch.
|
||||||
|
* `on_add` - Triggered when a task is added. A context task will be provided. The rule can modify the task, and approve or reject it.
|
||||||
|
* `on_modify` - Triggered when a task is modified. A before and after context task will be provided. The rule can modify the task, and approve or reject it.
|
||||||
|
* `on_exit` - Triggered on program exit.
|
||||||
|
* `color` - Triggered when colors are being determined.
|
||||||
|
* `virtual tag` - Defines a new virtual tag.
|
||||||
|
* `format` - Triggered when an attribute needs formatting, defines are new format.
|
||||||
|
|
||||||
|
More rules types will be added for more capabilities in future releases.
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
The API is a simple set of actions that may be taken by a rule.
|
||||||
|
|
||||||
|
* `debug(<string>)` - Displays the string in debug mode only and continues processing.
|
||||||
|
* `warn(<string>)` - Displays the string as a warning continues processing.
|
||||||
|
* `error(<string>)` - Displays the string as an error and terminates processing.
|
||||||
|
* `exec(<binary> [ <args> ... ])` - Executes the external program and passes arguments to it. If the program exits with non-zero status, it is treated as an error.
|
||||||
|
* `return <value>` - Provides a result value for the rule, when necessary.
|
||||||
|
|
||||||
|
This is a very limited set at first, and more API calls will be added to support
|
||||||
|
capabilities in future releases.
|
||||||
|
|
||||||
|
|
||||||
|
## Grammar
|
||||||
|
|
||||||
|
The grammar closely tracks that of Python. Blocks are indented consistently.
|
||||||
|
|
||||||
|
* `if <condition>: ... else: ... ` - The condition is a full Algebraic expression, and supports none of the command line conveniences. Terms must be combined with logical operators. The condition is an expression that is evaluated and converted to a Boolean value.
|
||||||
|
* `for <name> in <collection>: ` - There is no native type for a collection, but there are DOM references (`tags` \...) that reference collections. This provides a way to iterate.
|
||||||
|
* `set <name> = <expression> ` - Writes to a named type. The name may be a writable DOM object (`dom...`) or temporary variable storage (`tmp...`). Writing to a read-only DOM reference is an error.
|
||||||
|
* `<function>([<args>]) ` - A function is either a rule or an API call. Calling an undefined function is an error.
|
||||||
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Here are some example rules which illustrate the syntax and API.
|
||||||
|
|
||||||
|
The replacement for the nag feature:
|
||||||
|
|
||||||
|
rule Nag(before, after) on-modify:
|
||||||
|
if before.urgency < tasks.max.urgency:
|
||||||
|
warn ‘You have more urgent tasks’
|
||||||
|
|
||||||
|
if after.status == 'completed' and before.urgency < (dom.urgency.max - 2.0):
|
||||||
|
warn 'You have more urgent tasks!'
|
||||||
|
|
||||||
|
Correct commonly misspelled word:
|
||||||
|
|
||||||
|
rule CorrectSpelling(task) on_add:
|
||||||
|
set task.description = substitute(task.description, 'teh', 'the')
|
||||||
|
|
||||||
|
Abbreviation expansion:
|
||||||
|
|
||||||
|
rule ExpandAbbreviation(task) on_modify:
|
||||||
|
set task.description = substitute(task.description, '/TW-\d+/', 'https:\/\/github.com\/GothenburgBitFactory\/taskwarrior\/issues\/\1')
|
||||||
|
|
||||||
|
Warn on missing project:
|
||||||
|
|
||||||
|
rule WarnOnMissingProject(task) on_add:
|
||||||
|
if task.project == ‘’:
|
||||||
|
warn(‘Project not specified’)
|
||||||
|
|
||||||
|
Color rule:
|
||||||
|
|
||||||
|
rule ColorizeDue(task) color:
|
||||||
|
if task.due > now:
|
||||||
|
if task.due < (now + 5d):
|
||||||
|
return dom.rc.color.due
|
||||||
|
else:
|
||||||
|
return dom.rc.color.due.later
|
||||||
|
|
||||||
|
Policy:
|
||||||
|
|
||||||
|
rule policyProject(task) on_add:
|
||||||
|
if task.project == '':
|
||||||
|
if rc.default.project == '':
|
||||||
|
error('You must specify a project')
|
||||||
|
set task.project = rc.default.project
|
||||||
253
docs/rfcs/sync.md
Normal file
253
docs/rfcs/sync.md
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Taskserver Sync Algorithm"
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Taskserver Sync Algorithm
|
||||||
|
|
||||||
|
This document describes how task changes are merged by the Taskserver. It does
|
||||||
|
not describe [the protocol](/docs/design/protocol) used by the Taskserver.
|
||||||
|
|
||||||
|
The Taskserver merges tasks from multiple sources, resulting in conflict- free
|
||||||
|
syncing of data. The algorithm used to achieve this is simple and effective,
|
||||||
|
paralleling what SCM systems do to perform a rebase.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In this document, we adopt the convention discussed in Section 1.3.2 of
|
||||||
|
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized
|
||||||
|
words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the
|
||||||
|
significance of each particular requirement specified in this document.
|
||||||
|
|
||||||
|
In brief: \"MUST\" (or \"REQUIRED\") means that the item is an absolute
|
||||||
|
requirement of the specification; \"SHOULD\" (or \"RECOMMENDED\") means there
|
||||||
|
may exist valid reasons for ignoring this item, but the full implications should
|
||||||
|
be understood before doing so; and \"MAY\" (or \"OPTIONAL\") means that this
|
||||||
|
item is optional, and may be omitted without careful consideration.
|
||||||
|
|
||||||
|
|
||||||
|
## Problem Definition
|
||||||
|
|
||||||
|
The sync algorithm considers a single task, with multiple changes occurring in
|
||||||
|
two separate locations that must be resolved. The two locations are the local
|
||||||
|
machine and the server. This results in two parallel change sequences.
|
||||||
|
|
||||||
|
Examples using multiple clients collapse down to the simple two-branch case
|
||||||
|
because the clients are merged serially.
|
||||||
|
|
||||||
|
|
||||||
|
## Change Sequence
|
||||||
|
|
||||||
|
A sequence of changes to the same task is represented as:
|
||||||
|
|
||||||
|
T0 --> T1 --> T2
|
||||||
|
|
||||||
|
Although all examples are of the two-branch variety, some involve trivial
|
||||||
|
branches. Going through these examples will illustrate the algorithm. First the
|
||||||
|
legend:
|
||||||
|
|
||||||
|
T0 Represents the original task, the base.
|
||||||
|
T1 Represents the task with a non-trivial set of changes.
|
||||||
|
T2 Represents the task with further changes.
|
||||||
|
|
||||||
|
|
||||||
|
## Deltas
|
||||||
|
|
||||||
|
The transition from T0 \--\> T1 can be seen as a transform applied to T0,
|
||||||
|
resulting in T1. That transform is the delta (d1) between T0 and T1, which is a
|
||||||
|
subtractive term:
|
||||||
|
|
||||||
|
d1 = (T1 - T0)
|
||||||
|
|
||||||
|
Therefore:
|
||||||
|
|
||||||
|
T0 --> T1 = T0 + d1
|
||||||
|
= T0 + (T1 - T0)
|
||||||
|
|
||||||
|
This states that the transition from T0 to T1 is the application of a delta to
|
||||||
|
the original, T0, which results in T1. Applying this to the whole change
|
||||||
|
sequence yields:
|
||||||
|
|
||||||
|
T0 --> T1 --> T2 = T0 + d1 + d2
|
||||||
|
= T0 + (T1 - T0) + (T2 - T1)
|
||||||
|
|
||||||
|
|
||||||
|
## Use Case Classification
|
||||||
|
|
||||||
|
Because clients sync requests are processed serially, there is no need to
|
||||||
|
consider the multiple client cases. This means there is only ever the case with
|
||||||
|
two parallel change sequences = the two branch case.
|
||||||
|
|
||||||
|
|
||||||
|
## Two Branch Case
|
||||||
|
|
||||||
|
The two branch case represents changes made to the same task in two locations,
|
||||||
|
resulting in two deltas that must be applied to the same base.
|
||||||
|
|
||||||
|
T0 --> T1
|
||||||
|
T0 --> T2
|
||||||
|
|
||||||
|
This reduces to a base with two deltas, but the order in which the deltas are
|
||||||
|
applied is important. For example:
|
||||||
|
|
||||||
|
T0 + d1 + d2 =/= T0 + d2 + d1
|
||||||
|
|
||||||
|
The application of deltas is not commutative, except in the trivial case where
|
||||||
|
the two deltas are identical, or the deltas do not overlap. The deltas therefore
|
||||||
|
need to be applied in the correct sequence. Tasks have metadata that indicates
|
||||||
|
the last modified time, which dictates the sequence. Assuming d1 occurred before
|
||||||
|
d2, this neatly collapses down to a single branch sequence:
|
||||||
|
|
||||||
|
T0 + d1 + d2 = T3
|
||||||
|
|
||||||
|
Note that the result in this case is T3, because it will be neither T1 nor T2,
|
||||||
|
unless the deltas are identical.
|
||||||
|
|
||||||
|
|
||||||
|
## Two Branch, Multiple Changes Case
|
||||||
|
|
||||||
|
The two branch case can be complicated by multiple changes per branch:
|
||||||
|
|
||||||
|
T0 --> T1 --> T3 --> T5
|
||||||
|
T0 --> T2 --> T4
|
||||||
|
|
||||||
|
Note that the numbers were chosen to represent the order in which the changes
|
||||||
|
were made. First a list of deltas is generated:
|
||||||
|
|
||||||
|
T0 --> T1 = d1
|
||||||
|
T1 --> T3 = d3
|
||||||
|
T3 --> T5 = d5
|
||||||
|
T0 --> T2 = d2
|
||||||
|
T0 --> T4 = d4
|
||||||
|
|
||||||
|
d1, d3, d5, d2, d4
|
||||||
|
|
||||||
|
Then the deltas are sorted by modified time:
|
||||||
|
|
||||||
|
d1, d2, d3, d4, d5
|
||||||
|
|
||||||
|
Then epplied to the base, yielding T6:
|
||||||
|
|
||||||
|
T0 + d1 + d2 + d3 + d4 +d5 = T6
|
||||||
|
|
||||||
|
|
||||||
|
## Two Branch Case Example
|
||||||
|
|
||||||
|
Suppose the base task looks like this:
|
||||||
|
|
||||||
|
T0 project:ONE due:tomorrow priority:H +tag1 Original description
|
||||||
|
|
||||||
|
The first branch looks like this:
|
||||||
|
|
||||||
|
T1 project:TWO due:23rd priority:H +tag1 Original description
|
||||||
|
|
||||||
|
The second branch looks like this:
|
||||||
|
|
||||||
|
T2 project:ONE due:tomorrow priority:H +tag1 Modified description
|
||||||
|
|
||||||
|
Delta d1 is:
|
||||||
|
|
||||||
|
T0 project:ONE due:tomorrow priority:H +tag1 Original description
|
||||||
|
T1 project:TWO due:23rd priority:H +tag1 Original description
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
d1 project:TWO due:23rd
|
||||||
|
|
||||||
|
Delta d2 is:
|
||||||
|
|
||||||
|
T0 project:ONE due:tomorrow priority:H +tag1 Original description
|
||||||
|
T2 project:ONE due:tomorrow priority:H +tag1 Modified description
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
d2 Modified description
|
||||||
|
|
||||||
|
If d1 occurred before d2, the result is:
|
||||||
|
|
||||||
|
T3 = T0 + d1 + d2
|
||||||
|
= T0 + (project:TWO due:23rd) + (Modified description)
|
||||||
|
|
||||||
|
T3 = project:TWO due:23rd priority:H +tag1 Modified description
|
||||||
|
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
A range of illustrated use cases, from the trivial to the complex will show the
|
||||||
|
algorithm in use.
|
||||||
|
|
||||||
|
|
||||||
|
## Use Case 1: New Local Task
|
||||||
|
|
||||||
|
Initial state:
|
||||||
|
|
||||||
|
Server: -
|
||||||
|
Client: T0
|
||||||
|
|
||||||
|
The server has no data, and so T0 is stored. The result is now:
|
||||||
|
|
||||||
|
Server: T0
|
||||||
|
Client: T0
|
||||||
|
|
||||||
|
|
||||||
|
## Use Case 2: Local Change
|
||||||
|
|
||||||
|
Initial state:
|
||||||
|
|
||||||
|
Server: T0
|
||||||
|
Client: T0 --> T1
|
||||||
|
|
||||||
|
The server resolves the change:
|
||||||
|
|
||||||
|
T0 --> T1 = T0 + d1
|
||||||
|
= T1
|
||||||
|
|
||||||
|
T1 is stored. The result is now:
|
||||||
|
|
||||||
|
Server: T0 --> T1
|
||||||
|
Client: T1
|
||||||
|
|
||||||
|
|
||||||
|
## Use Case 3: Local and Remote Change
|
||||||
|
|
||||||
|
Initial state:
|
||||||
|
|
||||||
|
Server: T0 --> T1
|
||||||
|
Client: T0 --> T2
|
||||||
|
|
||||||
|
This is the two branch case, and the deltas are generated:
|
||||||
|
|
||||||
|
T0 --> T1 = T0 + d1
|
||||||
|
T0 --> T2 = T0 + d2
|
||||||
|
|
||||||
|
The order of change is determine to be d1, d2, yielding T3:
|
||||||
|
|
||||||
|
T3 = T0 + d1 + d2
|
||||||
|
|
||||||
|
T3 is stored on the server, and returned to the client. The result is now:
|
||||||
|
|
||||||
|
Server: T0 --> T1 --> T2 --> T3
|
||||||
|
Client: T3
|
||||||
|
|
||||||
|
|
||||||
|
## Use Case 4: Multiple Local and Remote Changes
|
||||||
|
|
||||||
|
Initial state:
|
||||||
|
|
||||||
|
Server: T0 --> T1 --> T3
|
||||||
|
Client: T0 --> T2 --> T4
|
||||||
|
|
||||||
|
This is the two branch case, and the deltas are generated:
|
||||||
|
|
||||||
|
T0 --> T1 = T0 + d1
|
||||||
|
T1 --> T3 = T0 + d3
|
||||||
|
T0 --> T2 = T0 + d2
|
||||||
|
T2 --> T4 = T0 + d4
|
||||||
|
|
||||||
|
d1, d3, d2, d4
|
||||||
|
|
||||||
|
The order of change is determine to be d1, d2, d3, d4, yielding T5:
|
||||||
|
|
||||||
|
T5 = T0 + d1 + d2 + d3 + d4
|
||||||
|
|
||||||
|
T5 is stored on the server, and returned to the client. The result is now:
|
||||||
|
|
||||||
|
Server: T0 --> T1 --> T2 --> T3 --> T4 --> T5
|
||||||
|
Client: T5
|
||||||
761
docs/rfcs/task.md
Normal file
761
docs/rfcs/task.md
Normal file
@@ -0,0 +1,761 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Taskwarrior JSON Format"
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
# Taskwarrior JSON Format
|
||||||
|
|
||||||
|
When Taskwarrior exchanges data, it uses [JSON](https://www.json.org/). This
|
||||||
|
document describes the structure and semantics for tasks exported from
|
||||||
|
Taskwarrior, imported to Taskwarrior, or synced with the Taskserver.
|
||||||
|
|
||||||
|
Any client of the Taskserver will need to communicate task information. This
|
||||||
|
document describes the format of a single task. It does not describe the
|
||||||
|
communication and sync protocol between client and server.
|
||||||
|
|
||||||
|
This document is subject to change. The data attributes are also subject to
|
||||||
|
change.
|
||||||
|
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
In this document, we adopt the convention discussed in Section 1.3.2 of
|
||||||
|
[RFC1122](https://tools.ietf.org/html/rfc1122#page-16) of using the capitalized
|
||||||
|
words MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, and OPTIONAL to define the
|
||||||
|
significance of each particular requirement specified in this document.
|
||||||
|
|
||||||
|
In brief: \"MUST\" (or \"REQUIRED\") means that the item is an absolute
|
||||||
|
requirement of the specification; \"SHOULD\" (or \"RECOMMENDED\") means there
|
||||||
|
may exist valid reasons for ignoring this item, but the full implications should
|
||||||
|
be understood before doing so; and \"MAY\" (or \"OPTIONAL\") means that this
|
||||||
|
item is optional, and may be omitted without careful consideration.
|
||||||
|
|
||||||
|
|
||||||
|
## General Format
|
||||||
|
|
||||||
|
The format is JSON, specifically a JSON object as a single line of text,
|
||||||
|
terminated by a newline (U+000D).
|
||||||
|
|
||||||
|
The JSON looks like this:
|
||||||
|
|
||||||
|
{"description":"One two three","status":"pending", ... }
|
||||||
|
|
||||||
|
While this is not a valid task (there are missing fields), the format is
|
||||||
|
illustrated.
|
||||||
|
|
||||||
|
All attribute names are quoted with \" (U+0022). A name will always have a
|
||||||
|
corresponding value, and if a value is blank, then the name/value pair is
|
||||||
|
omitted from the line. Newline characters are not permitted within the value,
|
||||||
|
meaning that a task consists of a single line of text.
|
||||||
|
|
||||||
|
All data is UTF8.
|
||||||
|
|
||||||
|
|
||||||
|
## Data Types
|
||||||
|
|
||||||
|
There are five data types used in the task format.
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: String
|
||||||
|
|
||||||
|
Strings may consist of any UTF8 encoded characters.
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: Fixed String
|
||||||
|
|
||||||
|
A fixed string is one value from a set of acceptable values, such as a priority
|
||||||
|
level, where the values may only be \"\", \"L\", \"M\" or \"H\".
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: UUID
|
||||||
|
|
||||||
|
A UUID is a 32-hex-character lower case string, formatted in this way:
|
||||||
|
|
||||||
|
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
|
||||||
|
An example:
|
||||||
|
|
||||||
|
296d835e-8f85-4224-8f36-c612cad1b9f8
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: Integer
|
||||||
|
|
||||||
|
Integers are rendered in a simple fashion:
|
||||||
|
|
||||||
|
123
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: Date
|
||||||
|
|
||||||
|
Dates are rendered in ISO 8601 combined date and time in UTC format using the
|
||||||
|
template:
|
||||||
|
|
||||||
|
YYYYMMDDTHHMMSSZ
|
||||||
|
|
||||||
|
An example:
|
||||||
|
|
||||||
|
20120110T231200Z
|
||||||
|
|
||||||
|
No other formats are supported.
|
||||||
|
|
||||||
|
|
||||||
|
## Data Type: Duration
|
||||||
|
|
||||||
|
Duration values represent a time period. They take the form:
|
||||||
|
|
||||||
|
[[<sign>] <number>] <unit>
|
||||||
|
|
||||||
|
Some examples include:
|
||||||
|
|
||||||
|
- -3days
|
||||||
|
- annual
|
||||||
|
- 4hrs
|
||||||
|
|
||||||
|
The supported units are:
|
||||||
|
|
||||||
|
- annual
|
||||||
|
- biannual
|
||||||
|
- bimonthly
|
||||||
|
- biweekly
|
||||||
|
- biyearly
|
||||||
|
- daily
|
||||||
|
- days
|
||||||
|
- day
|
||||||
|
- d
|
||||||
|
- fortnight
|
||||||
|
- hours
|
||||||
|
- hour
|
||||||
|
- hrs
|
||||||
|
- hr
|
||||||
|
- h
|
||||||
|
- minutes
|
||||||
|
- mins
|
||||||
|
- min
|
||||||
|
- monthly
|
||||||
|
- months
|
||||||
|
- month
|
||||||
|
- mnths
|
||||||
|
- mths
|
||||||
|
- mth
|
||||||
|
- mos
|
||||||
|
- mo
|
||||||
|
- quarterly
|
||||||
|
- quarters
|
||||||
|
- qrtrs
|
||||||
|
- qtrs
|
||||||
|
- qtr
|
||||||
|
- q
|
||||||
|
- seconds
|
||||||
|
- secs
|
||||||
|
- sec
|
||||||
|
- s
|
||||||
|
- semiannual
|
||||||
|
- sennight
|
||||||
|
- weekdays
|
||||||
|
- weekly
|
||||||
|
- weeks
|
||||||
|
- week
|
||||||
|
- wks
|
||||||
|
- wk
|
||||||
|
- w
|
||||||
|
- yearly
|
||||||
|
- years
|
||||||
|
- year
|
||||||
|
- yrs
|
||||||
|
- yr
|
||||||
|
- y
|
||||||
|
|
||||||
|
Note that some values lack precision, for example \"2q\" means two quarters, or
|
||||||
|
half a year.
|
||||||
|
|
||||||
|
Note that not all combinations of and make sense, for example \"3annual\" makes
|
||||||
|
no sense, but evaluates to \"3years\".
|
||||||
|
|
||||||
|
|
||||||
|
## The Attributes
|
||||||
|
|
||||||
|
Here are the standard attributes that may comprise a task:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>status</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>uuid</td>
|
||||||
|
<td>UUID</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>entry</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>description</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>start</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>end</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>due</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>until</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>wait</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>modified</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>scheduled</td>
|
||||||
|
<td>Date</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>recur</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mask</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>imask</td>
|
||||||
|
<td>Integer</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>parent</td>
|
||||||
|
<td>UUID</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>project</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>priority</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>depends</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>tags *</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>annotation *</td>
|
||||||
|
<td>String</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>(UDA)</td>
|
||||||
|
<td>?</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
\* Both tags and annotations are lists of strings and objects.
|
||||||
|
|
||||||
|
Any UDA fields are assumed to be of type string.
|
||||||
|
|
||||||
|
There are other forms, which are conditional upon the state of a task:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Status Value</th>
|
||||||
|
<th>Pending</th>
|
||||||
|
<th>Deleted</th>
|
||||||
|
<th>Completed</th>
|
||||||
|
<th>Waiting</th>
|
||||||
|
<th>Recurring Parent</th>
|
||||||
|
<th>Recurring Child</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>status</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>uuid</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>entry</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>description</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>start</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>end</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>due</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>until</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>scheduled</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>wait</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>recur</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>mask</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>imask</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>parent</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td class="danger">Reqd</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>annotation</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>project</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>tags</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>priority</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>depends</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>modified</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
<td class="info">Intrn</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>UDA</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
<td>Opt</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
(Legend: Reqd = required, Opt = optional, Intrn = Internally generated)
|
||||||
|
|
||||||
|
All tasks have four required fields. There are other states in which a task may
|
||||||
|
exist, and the requirements change. At a minimum, a valid task contains:
|
||||||
|
|
||||||
|
- uuid
|
||||||
|
- status
|
||||||
|
- entry
|
||||||
|
- description
|
||||||
|
|
||||||
|
*Deleted*\
|
||||||
|
A deleted task MUST also have \"status\":\"deleted\", an \"end\" date and a
|
||||||
|
\"modified\" date.
|
||||||
|
|
||||||
|
*Completed*\
|
||||||
|
A completed task MUST also have \"status\":\"completed\", an \"end\" date and a
|
||||||
|
\"modified\" date.
|
||||||
|
|
||||||
|
*Waiting*\
|
||||||
|
A waiting task MUST also have \"status\":\"waiting\" and a \"wait\" date. The
|
||||||
|
task is hidden from the user, until that \"wait\" date has passed, whereupon the
|
||||||
|
status reverts to \"pending\", and the \"wait\" date is removed.
|
||||||
|
|
||||||
|
*Recurring Parent*\
|
||||||
|
When a recurring task is entered, it MUST have \"status\":\"recurring\", a
|
||||||
|
\"recur\" period and a \"due\" date. It MAY also have an \"until\" date.
|
||||||
|
Recurring parent tasks are hidden from the user.
|
||||||
|
|
||||||
|
*Recurring Child*\
|
||||||
|
A recurring child task is not created by the user, but is cloned from the
|
||||||
|
recurring parent task by the Taskserver. It may be modified by the user. On
|
||||||
|
completion, there is special handling to be done. See section 3.11.
|
||||||
|
|
||||||
|
|
||||||
|
## Additional Attributes
|
||||||
|
|
||||||
|
There MAY be other fields than those listed above in a task definition. Such
|
||||||
|
fields MUST be preserved intact by any client, which means that if a task is
|
||||||
|
downloaded that contains an unrecognized field, that field MUST not be modified,
|
||||||
|
and MUST continue to exist in the task..
|
||||||
|
|
||||||
|
User Defined Attributes (UDAs) are additional fields.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute Details
|
||||||
|
|
||||||
|
The individual fields convey important information about a task, and in some
|
||||||
|
cases work only in collusion with other fields. All such details are listed
|
||||||
|
here.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: status
|
||||||
|
|
||||||
|
The status field describes the state of the task, which may ONLY be one of these
|
||||||
|
literal strings:
|
||||||
|
|
||||||
|
"status":"pending"
|
||||||
|
"status":"deleted"
|
||||||
|
"status":"completed"
|
||||||
|
"status":"waiting"
|
||||||
|
"status":"recurring"
|
||||||
|
|
||||||
|
A pending task is a task that has not yet been completed or deleted. This is the
|
||||||
|
typical state for a task.
|
||||||
|
|
||||||
|
A deleted task is one that has been removed from the pending state, and MUST
|
||||||
|
have an \"end\" field specified. Given the required \"entry\" and \"end\" field,
|
||||||
|
it can be determined how long the task was pending.
|
||||||
|
|
||||||
|
A completed task is one that has been removed from the pending state by
|
||||||
|
completion, and MUST have an \"end\" field specified. Given the required
|
||||||
|
\"entry\" and \"end\" fields, it can be determine how long the task was pending.
|
||||||
|
|
||||||
|
A waiting task is ostensibly a pending task that has been hidden from typical
|
||||||
|
view, and MUST have a \"wait\" field containing the date when the task is
|
||||||
|
automatically returned to the pending state. If a client sees a task that is in
|
||||||
|
the waiting state, and the \"wait\" field is earlier than the current date and
|
||||||
|
time, the client MUST remove the \"wait\" field and set the \"status\" field to
|
||||||
|
\"pending\".
|
||||||
|
|
||||||
|
A recurring task is essentially a parent template task from which child tasks
|
||||||
|
are cloned. The parent remains hidden from view, and contains a \"mask\" field
|
||||||
|
that represents the recurrences. Each cloned child task has an \"imask\" field
|
||||||
|
that indexes into the parent \"mask\" field, as well as a \"parent\" field that
|
||||||
|
lists the UUID of the parent.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: uuid
|
||||||
|
|
||||||
|
When a task is created, it MUST be assigned a new UUID by the client. Once
|
||||||
|
assigned, a UUID field MUST NOT be modified. UUID fields are permanent.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: entry
|
||||||
|
|
||||||
|
When a task is created, it MUST be assigned an \"entry\" date by the client.
|
||||||
|
This is the creation date of the task.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: description
|
||||||
|
|
||||||
|
When a task is created, it MUST have a \"description\" field value, which
|
||||||
|
contains UTF8 characters. A \"description\" field may not contain newline
|
||||||
|
characters, but may contain other characters, properly escaped. See
|
||||||
|
<https://json.org> for details.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: start
|
||||||
|
|
||||||
|
To indicate that a task is being worked on, it MAY be assigned a \"start\"
|
||||||
|
field. Such a task is then considered Active.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: end
|
||||||
|
|
||||||
|
When a task is deleted or completed, is MUST be assigned an \"end\" field. It is
|
||||||
|
not valid for a task to have an \"end\" field unless the status is also
|
||||||
|
\"completed\" or \"deleted\". If a completed task is restored to the \"pending\"
|
||||||
|
state, the \"end\" field is removed.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: due
|
||||||
|
|
||||||
|
A task MAY have a \"due\" field, which indicates when the task should be
|
||||||
|
completed.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: until
|
||||||
|
|
||||||
|
A recurring task MAY have an \"until\" field, which is the date after which no
|
||||||
|
more recurring tasks should be generated. At that time, the parent recurring
|
||||||
|
task is set to \"completed\".
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: wait
|
||||||
|
|
||||||
|
A task MAY have a \"wait\" field date, in conjunction with a \"status\" of
|
||||||
|
\"waiting\". A waiting task is one that is not typically shown on reports until
|
||||||
|
it is past the wait date.
|
||||||
|
|
||||||
|
An example of this is a birthday reminder. A task may be entered for a birthday
|
||||||
|
reminder in 10 months time, but can have a \"wait\" date 9 months from now,
|
||||||
|
which means the task remains hidden until 1 month before the due date. This
|
||||||
|
prevents long-term tasks from cluttering reports until they become relevant.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: recur
|
||||||
|
|
||||||
|
The \"recur\" field is for recurring tasks, and specifies the period between
|
||||||
|
child tasks, in the form of a duration value. The value is kept in the raw state
|
||||||
|
(such as \"3wks\") as a string, so that it may be evaluated each time it is
|
||||||
|
needed.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: mask
|
||||||
|
|
||||||
|
A parent recurring task has a \"mask\" field that is an array of child status
|
||||||
|
indicators. Suppose a task is created that is due every week for a month. The
|
||||||
|
\"mask\" field will look like:
|
||||||
|
|
||||||
|
"----"
|
||||||
|
|
||||||
|
This mask has four slots, indicating that there are four child tasks, and each
|
||||||
|
slot indicates, in this case, that the child tasks are pending (\"-\"). The
|
||||||
|
possible slot indicators are:
|
||||||
|
|
||||||
|
* `-` - Pending
|
||||||
|
* `+` - Completed
|
||||||
|
* `X` - Deleted
|
||||||
|
* `W` - Waiting
|
||||||
|
|
||||||
|
Suppose the first three tasks has been completed, the mask would look like this:
|
||||||
|
|
||||||
|
"+++-"
|
||||||
|
|
||||||
|
If there were only three indicators in the mask:
|
||||||
|
|
||||||
|
"+-+"
|
||||||
|
|
||||||
|
This would indicate that the second task is pending, the first and third are
|
||||||
|
complete, and the fourth has not yet been generated.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: imask
|
||||||
|
|
||||||
|
Child recurring tasks have an \"imask\" field instead of a \"mask\" field like
|
||||||
|
their parent. The \"imask\" field is a zero-based integer offset into the
|
||||||
|
\"mask\" field of the parent.
|
||||||
|
|
||||||
|
If a child task is completed, one of the changes that MUST occur is to look up
|
||||||
|
the parent task, and using \"imask\" set the \"mask\" of the parent to the
|
||||||
|
correct indicator. This prevents recurring tasks from being generated twice.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: parent
|
||||||
|
|
||||||
|
A recurring task instance MUST have a \"parent\" field, which is the UUID of the
|
||||||
|
task that has \"status\" of \"recurring\". This linkage between tasks,
|
||||||
|
established using \"parent\", \"mask\" and \"imask\" is used to track the need
|
||||||
|
to generate more recurring tasks.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: annotation\_\...
|
||||||
|
|
||||||
|
Annotations are strings with timestamps. Each annotation itself has an \"entry\"
|
||||||
|
field and a \"description\" field, similar to the task itself. Annotations form
|
||||||
|
an array named \"annotations\". For example (lines broken for clarity):
|
||||||
|
|
||||||
|
"annotations":[
|
||||||
|
{"entry":"20120110T234212Z","description":"Remember to get the mail"},
|
||||||
|
{"entry":"20120110T234559Z","description":"Pay the bills"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: project
|
||||||
|
|
||||||
|
A project is a single string. For example:
|
||||||
|
|
||||||
|
"project":"Personal Taxes"
|
||||||
|
|
||||||
|
Note that projects receive special handling, so that when a \".\" (U+002E) is
|
||||||
|
used, it implies a hierarchy, which means the following two projects:
|
||||||
|
|
||||||
|
"Home.Kitchen"
|
||||||
|
"Home.Garden"
|
||||||
|
|
||||||
|
are both considered part of the \"Home\" project.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: tags
|
||||||
|
|
||||||
|
The \"tags\" field is an array of string, where each string is a single word
|
||||||
|
containing no spaces. For example:
|
||||||
|
|
||||||
|
"tags":["home","garden"]
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: priority
|
||||||
|
|
||||||
|
The \"priority\" field, if present, MAY contain one of the following strings:
|
||||||
|
|
||||||
|
"priority":"H"
|
||||||
|
"priority":"M"
|
||||||
|
"priority":"L"
|
||||||
|
|
||||||
|
These represent High, Medium and Low priorities. An absent priority field
|
||||||
|
indicates no priority.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: depends
|
||||||
|
|
||||||
|
The \"depends\" field is a string containing a comma-separated unique set of
|
||||||
|
UUIDs. If task 2 depends on task 1, then it is task 1 that must be completed
|
||||||
|
first. Task 1 is considered a \"blocking\" tasks, and task 2 is considered a
|
||||||
|
\"blocked\" task. For example:
|
||||||
|
|
||||||
|
"depends":",, ..."
|
||||||
|
|
||||||
|
Note that in a future version of this specification, this will be changed to a
|
||||||
|
JSON array of strings, like the \"tags\" field.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: modified
|
||||||
|
|
||||||
|
A task MUST have a \"modified\" field set if it is modified. This field is of
|
||||||
|
type \"date\", and is used as a reference when merging tasks.
|
||||||
|
|
||||||
|
|
||||||
|
## Attribute: scheduled
|
||||||
|
|
||||||
|
A task MAY have a \"scheduled\" field, which indicates when the task should be
|
||||||
|
available to start. A task that has passed its \"scheduled\" data is said to be
|
||||||
|
\"ready\".
|
||||||
|
|
||||||
|
|
||||||
|
## User Defined Attributes
|
||||||
|
|
||||||
|
A User Defined Attribute (UDA) is a field that is defined via configuration.
|
||||||
|
Given that the configuration is not present in the JSON format of a task, any
|
||||||
|
fields that are not recognized are to be treated as UDAs. This means that if a
|
||||||
|
task contains a UDA, unless the meaning of it is understood, it MUST be
|
||||||
|
preserved.
|
||||||
|
|
||||||
|
UDAs may have one of four types: string, numeric, date and duration.
|
||||||
|
|
||||||
BIN
docs/rfcs/week.png
Normal file
BIN
docs/rfcs/week.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
35
docs/rfcs/workweek.md
Normal file
35
docs/rfcs/workweek.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
title: "Taskwarrior - Work Week Support"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Work in Progress
|
||||||
|
|
||||||
|
This design document is a work in progress, and subject to change. Once
|
||||||
|
finalized, the feature will be scheduled for an upcoming release.
|
||||||
|
|
||||||
|
|
||||||
|
# Work Week Support
|
||||||
|
|
||||||
|
Taskwarrior supports the idea that a week starts on either a Sunday or a Monday,
|
||||||
|
as determined by configuration. This was added eight years ago, simply for
|
||||||
|
display purposes in the `calendar` report. Since then its use has propagated and
|
||||||
|
it influences the `sow` date reference.0
|
||||||
|
|
||||||
|
Further requests have been made to make this more flexible, so that the notion
|
||||||
|
of \'weekend\' can be defined. Furthermore, the idea that every week has a
|
||||||
|
weekend has also been questioned.
|
||||||
|
|
||||||
|
It has become clear that a `weekstart` setting, and the notion of a weekend are
|
||||||
|
no longer useful.
|
||||||
|
|
||||||
|
|
||||||
|
## Proposed Support
|
||||||
|
|
||||||
|
One option is to allow the user to completely define a work week in the
|
||||||
|
following way:
|
||||||
|
|
||||||
|
workweek=1,2,3,4,5
|
||||||
|
|
||||||
|
With Sunday as day zero, this states that the work week is the typical Monday -
|
||||||
|
Friday. From this setting, the meaning of `soww` and `eoww` can be determined,
|
||||||
|
as well as `recur:weekday`.
|
||||||
BIN
docs/rfcs/year.png
Normal file
BIN
docs/rfcs/year.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user