taskwarrior-calendar 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/task-ical +6 -0
- data/lib/taskwarrior/calendar/app/base.rb +50 -0
- data/lib/taskwarrior/calendar/app/convert.rb +24 -0
- data/lib/taskwarrior/calendar/app.rb +16 -0
- data/lib/taskwarrior/calendar/event.rb +33 -0
- data/lib/taskwarrior/calendar/timezone.rb +21 -0
- data/lib/taskwarrior/calendar/version.rb +7 -0
- data/lib/taskwarrior/calendar.rb +87 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4381f3210f9a478f0b1ad0453d7e84c42f3dd8b2b55a5afc17d0ce8c21fdf938
|
4
|
+
data.tar.gz: 6609c61b9c93d0a0fd8d2fdffcc11d3334ec55297c0ee5004d9e18e64a0e0a1e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 80f387b7fae053e80079eee0e7d36f17bb6260f9de2d55dde84cd010a9e72aacd8c2193cf67a0e4c46a6063b836c75c7f91fa54238826f37d194eb28bcf2b7bc
|
7
|
+
data.tar.gz: 785ff03b8ce423694a906964a07a97d0dac57f79961cd9ee4cdc48021d5a5a4780383911d9d1b2e89d65d5e6368a7855d9d7608ed5f730e93dba85352f263e33
|
data/bin/task-ical
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'clamp'
|
4
|
+
require 'pastel'
|
5
|
+
require 'tty-pager'
|
6
|
+
|
7
|
+
require_relative '../version'
|
8
|
+
require_relative '../../calendar'
|
9
|
+
|
10
|
+
class Taskwarrior
|
11
|
+
class Calendar
|
12
|
+
module App
|
13
|
+
class BaseCommand < Clamp::Command
|
14
|
+
option ['-m', '--man'], :flag, 'show manpage' do
|
15
|
+
manpage = <<~MANPAGE
|
16
|
+
Name:
|
17
|
+
task-ical - Taskwarrior tasks to ical converter
|
18
|
+
|
19
|
+
#{help}
|
20
|
+
Description:
|
21
|
+
The due timestamp, optionally scheduled timestamp and
|
22
|
+
description of a task are used to create a calendar event.
|
23
|
+
|
24
|
+
Authors:
|
25
|
+
Tobias Schäfer <github@blackox.org>
|
26
|
+
|
27
|
+
Copyright and License
|
28
|
+
This software is copyright (c) 2022 by Tobias Schäfer.
|
29
|
+
|
30
|
+
This package is free software; you can redistribute it and/or
|
31
|
+
modify it under the terms of the "MIT License".
|
32
|
+
MANPAGE
|
33
|
+
TTY::Pager.page(manpage)
|
34
|
+
|
35
|
+
exit 0
|
36
|
+
end
|
37
|
+
|
38
|
+
option ['-v', '--version'], :flag, 'show version' do
|
39
|
+
puts "task-ical #{Taskwarrior::Calendar::VERSION}"
|
40
|
+
exit 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def bailout(message)
|
44
|
+
puts Pastel.new.red.bold(message)
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base'
|
4
|
+
|
5
|
+
class Taskwarrior
|
6
|
+
class Calendar
|
7
|
+
module App
|
8
|
+
class ConvertCommand < Taskwarrior::Calendar::App::BaseCommand
|
9
|
+
option '--[no-]alarm', :flag, 'add alarm to event', default: true
|
10
|
+
option '--filter', 'FILTER', 'tasks filter', default: 'status:pending'
|
11
|
+
option '--filename', 'FILE', 'ics output file'
|
12
|
+
|
13
|
+
def execute
|
14
|
+
calendar = Taskwarrior::Calendar.new(filter:, alarm: alarm?)
|
15
|
+
return calendar.publish(filename:) if !filename.nil?
|
16
|
+
|
17
|
+
puts calendar.to_ical
|
18
|
+
rescue StandardError => e
|
19
|
+
bailout(e.cause || e.message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'app/base'
|
4
|
+
require_relative 'app/convert'
|
5
|
+
|
6
|
+
class Taskwarrior
|
7
|
+
class Calendar
|
8
|
+
module App
|
9
|
+
class Command < Taskwarrior::Calendar::App::BaseCommand
|
10
|
+
self.default_subcommand = 'convert'
|
11
|
+
|
12
|
+
subcommand 'convert', 'Convert tasks to events', Taskwarrior::Calendar::App::ConvertCommand
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'icalendar'
|
4
|
+
require 'icalendar/tzinfo'
|
5
|
+
|
6
|
+
class Taskwarrior
|
7
|
+
class Calendar
|
8
|
+
module Event
|
9
|
+
def add_event(event, task, type, alarm)
|
10
|
+
date = Icalendar::Values::DateTime.new(
|
11
|
+
tz_info.utc_to_local(DateTime.parse(task[type])),
|
12
|
+
'tzid' => tz_name
|
13
|
+
)
|
14
|
+
event.dtstart = event.dtend = date
|
15
|
+
|
16
|
+
event.summary = "#{type.capitalize}: #{task['description']}"
|
17
|
+
event.ip_class = 'PRIVATE'
|
18
|
+
|
19
|
+
add_event_alarm(event, task, type) if alarm
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def add_event_alarm(event, task, type)
|
25
|
+
event.alarm do |a|
|
26
|
+
a.action = 'DISPLAY'
|
27
|
+
a.summary = "#{type.capitalize}: #{task['description']}"
|
28
|
+
a.trigger = '-PT15M'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tzinfo'
|
4
|
+
|
5
|
+
class Taskwarrior
|
6
|
+
class Calendar
|
7
|
+
module Timezone
|
8
|
+
def tz_name
|
9
|
+
@tz_name ||= ENV['TZ'] || begin
|
10
|
+
File.read('/etc/timezone').strip
|
11
|
+
rescue Errno::ENOENT
|
12
|
+
'UTC'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def tz_info
|
17
|
+
@tz_info ||= TZInfo::Timezone.get(tz_name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'icalendar'
|
5
|
+
require 'icalendar/tzinfo'
|
6
|
+
require 'json'
|
7
|
+
require 'open3'
|
8
|
+
|
9
|
+
require_relative 'calendar/timezone'
|
10
|
+
require_relative 'calendar/event'
|
11
|
+
|
12
|
+
class Taskwarrior
|
13
|
+
##
|
14
|
+
# Convert taskwarrior tasks to calendar events.
|
15
|
+
#
|
16
|
+
# calendar = Taskwarrior::Calendar.new(filter: 'status:pending', alarm: false)
|
17
|
+
# calendar.publish(filename: '~/tasks.ics')
|
18
|
+
#
|
19
|
+
# Task *due* and optional *scheduled* dates if available are exported as
|
20
|
+
# calendar events.
|
21
|
+
#
|
22
|
+
# By default tasks are filtered by +status:pending+ and all events are
|
23
|
+
# appointed with an alarm *15* *minutes* *before* the event date. This can be
|
24
|
+
# configured with the filter and alarm options. For further filter details see
|
25
|
+
# https://taskwarrior.org/docs/filter. All events are exported in the
|
26
|
+
# timezone of the system. This can be configured with the +TZ+ environment
|
27
|
+
# variable.
|
28
|
+
class Calendar
|
29
|
+
include Timezone
|
30
|
+
include Event
|
31
|
+
|
32
|
+
##
|
33
|
+
# Initialize a new taskwarrior calendar object. Tasks are filtered by
|
34
|
+
# +status:pending+ and all calendar events are appointed with an alarm.
|
35
|
+
# This can be configured with the +filter+ and +alarm+ options.
|
36
|
+
#
|
37
|
+
# On failure an error is raised.
|
38
|
+
def initialize(filter: 'status:pending', alarm: true)
|
39
|
+
tasks(filter:)
|
40
|
+
calendar(alarm:)
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Return the Icalendar::Calendar object.
|
45
|
+
def to_object
|
46
|
+
@calendar
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Return the calendar as ICS string.
|
51
|
+
def to_ical
|
52
|
+
@calendar.to_ical
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Publish calendar ICS to a file, default +taskwarrior.ics+. This can be
|
57
|
+
# configured with the +filename+ option.
|
58
|
+
def publish(filename: 'taskwarrior.ics')
|
59
|
+
File.write(filename, to_ical)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def tasks(filter:)
|
65
|
+
@tasks = Open3.popen3("task #{filter} export") do |_, stdout, stderr, process|
|
66
|
+
raise IOError, "taskwarrior: #{stderr.read}" if process.value.exitstatus != 0
|
67
|
+
|
68
|
+
JSON.parse(stdout.read)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def calendar(alarm:)
|
73
|
+
@calendar = Icalendar::Calendar.new
|
74
|
+
@calendar.add_timezone(tz_info.ical_timezone(DateTime.now))
|
75
|
+
|
76
|
+
@tasks.each do |task|
|
77
|
+
%w[due scheduled].each do |type|
|
78
|
+
next if !task.key?(type) || task[type].empty?
|
79
|
+
|
80
|
+
@calendar.event do |event|
|
81
|
+
add_event(event, task, type, alarm)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: taskwarrior-calendar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Schäfer
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-16 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: base64
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: clamp
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.3.2
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.3.2
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: icalendar
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.9.0
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.9.0
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: logger
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :runtime
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: ostruct
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :runtime
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: pastel
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.8.0
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 0.8.0
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: tty-pager
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.14.0
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.14.0
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: tzinfo
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 2.0.6
|
117
|
+
type: :runtime
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 2.0.6
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: tzinfo-data
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 1.2023.3
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 1.2023.3
|
138
|
+
description: |
|
139
|
+
Convert taskwarrior tasks to calendar events.
|
140
|
+
|
141
|
+
The due timestamp, optionally scheduled timestamp and description of a
|
142
|
+
task are used to create a calendar event.
|
143
|
+
email:
|
144
|
+
- github@blackox.org
|
145
|
+
executables:
|
146
|
+
- task-ical
|
147
|
+
extensions: []
|
148
|
+
extra_rdoc_files: []
|
149
|
+
files:
|
150
|
+
- bin/task-ical
|
151
|
+
- lib/taskwarrior/calendar.rb
|
152
|
+
- lib/taskwarrior/calendar/app.rb
|
153
|
+
- lib/taskwarrior/calendar/app/base.rb
|
154
|
+
- lib/taskwarrior/calendar/app/convert.rb
|
155
|
+
- lib/taskwarrior/calendar/event.rb
|
156
|
+
- lib/taskwarrior/calendar/timezone.rb
|
157
|
+
- lib/taskwarrior/calendar/version.rb
|
158
|
+
homepage: https://github.com/tschaefer/taskwarrior-calendar
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
metadata:
|
162
|
+
rubygems_mfa_required: 'true'
|
163
|
+
source_code_uri: https://github.com/tschaefer/taskwarrior-calendar
|
164
|
+
bug_tracker_uri: https://github.com/tschaefer/taskwarrior-calendar/issues
|
165
|
+
post_install_message: All your tasks are belong to us!
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 3.1.1
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubygems_version: 3.6.6
|
181
|
+
specification_version: 4
|
182
|
+
summary: Convert taskwarrior tasks to calendar events.
|
183
|
+
test_files: []
|