mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Import design docs (RFCs)
This commit is contained in:
parent
07493d5fa6
commit
8747cc9f94
15 changed files with 3259 additions and 0 deletions
|
@ -13,3 +13,22 @@ For all other documenation, see https://taskwarrior.org.
|
|||
* [Building Taskwarrior](./contrib/build)
|
||||
* [Coding Style](./contrib/coding_style)
|
||||
* [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 |
Loading…
Add table
Add a link
Reference in a new issue