icalPal 3.2.0 → 3.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cc2cfd940c507b46cafd9c893beb25c47c82850ba7c1e02aaffcb6bc76eda208
4
- data.tar.gz: e28610d838feaf2c05b41badd96bad57185501529cd73c7f0b7f5889290a59ef
3
+ metadata.gz: fd12b179a212d0582bd2740c8697f994f75d71fab58ab9ca28c8330e59e33b08
4
+ data.tar.gz: ab00df9c7f7b5fce00f8a247f346f5049f019d5336973eaec5e17d1970e773da
5
5
  SHA512:
6
- metadata.gz: 2cdd430f7a66418a87cccf5c037f24d0e4fe39e594db5b951ea004c13eadafd15f398bfc0beac8b5fe4c987664a1ee56d9e113354a438e06cf2fe9c3d88c3304
7
- data.tar.gz: ee2276cb96b75d93727bc9dcf4595cd8bef64ccd0893e4e3647f0c5a74d559cddf86434bf0a392176e3a05f7339d8b9651347e5c6098c45467aaf8c163349b62
6
+ metadata.gz: 5b2a5690bcf64c79fff82138dfeb27063dcc79d65ca29082e387cc396c7787d8beeec4beaf5ab56492bfb1739e1dcabfb2012ebceb34b899b90a118a8cf522b5
7
+ data.tar.gz: d65423b35e47f5287cb44406f618d8cb90825163d1d416e3dc2b1921483fa67ad6e62873c692fd25173a1485d8507a4f70c276a66e2a626cf0d4573e1e5571c8
data/bin/icalPal CHANGED
@@ -11,6 +11,7 @@ begin
11
11
 
12
12
  require_relative '../lib/icalpal'
13
13
  require_relative '../lib/options'
14
+ require_relative '../lib/utils'
14
15
  rescue LoadError => e
15
16
  dep = e.message[/-- (.*)/, 1]
16
17
 
@@ -101,7 +102,27 @@ end
101
102
  # Make sure we opened at least one database
102
103
  unless success
103
104
  $log.fatal('Could not open database')
104
- $opts[:db].each { |db| $log.fatal("Tried #{db}") }
105
+
106
+ # SQLite3 does not return useful error messages. If any databases
107
+ # failed because of EPERM (operation not permitted), our parent
108
+ # process might need Full Disk Access, and we should suggest that.
109
+ eperm = 0
110
+
111
+ $opts[:db].each do |db|
112
+ # Use a real open to get a useful error
113
+ File.open(db).close
114
+ rescue Exception => e
115
+ $log.fatal("#{e.class}: #{db}")
116
+
117
+ eperm = 1 if e.instance_of?(Errno::EPERM)
118
+ end
119
+
120
+ if eperm.positive?
121
+ $stderr.puts
122
+ $stderr.puts "Does #{ancestor} have Full Disk Access in System Settings?"
123
+ $stderr.puts
124
+ $stderr.puts "Try running: open 'x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles'"
125
+ end
105
126
 
106
127
  abort
107
128
  end
data/bin/icalpal ADDED
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'logger'
5
+
6
+ require 'csv'
7
+ require 'json'
8
+ require 'rdoc'
9
+ require 'sqlite3'
10
+ require 'yaml'
11
+
12
+ require_relative '../lib/icalpal'
13
+ require_relative '../lib/options'
14
+ require_relative '../lib/utils'
15
+ rescue LoadError => e
16
+ dep = e.message[/-- (.*)/, 1]
17
+
18
+ $stderr.puts "FATAL: icalpal is missing a dependency: #{dep}"
19
+ $stderr.puts
20
+ $stderr.puts "Install with 'gem install --user-install #{dep}'"
21
+
22
+ exit
23
+ end
24
+
25
+
26
+ ##################################################
27
+ # Load options
28
+
29
+ # All kids love log!
30
+ $log = Logger.new(STDERR, { level: $defaults[:common][:debug] })
31
+ $log.formatter = proc do |s, t, _p, m| # Severity, time, progname, msg
32
+ ($log.level.positive?)? "#{s}: #{m}\n" :
33
+ format("[%-5<sev>s] %<time>s [%<caller>s] - %<message>s\n",
34
+ {
35
+ sev: s,
36
+ time: t.strftime('%H:%M:%S.%L'),
37
+ caller: caller(4, 1)[0].split('/')[-1],
38
+ message: m
39
+ })
40
+ end
41
+
42
+ $opts = ICalPal::Options.new.parse_options
43
+
44
+ $rows = [] # Rows from the database
45
+ $items = [] # Items to be printed
46
+
47
+
48
+ ##################################################
49
+ # All kids love log!
50
+
51
+ $log.info("Options: #{$opts}")
52
+
53
+
54
+ ##################################################
55
+ # Add an item to the list
56
+ #
57
+ # @param item[Object]
58
+
59
+ def add(item)
60
+ $log.info("Adding #{item.inspect} #{item['UUID']} (#{item['title']})") if item['UUID']
61
+
62
+ item['sday'] = ICalPal::RDT.new(*item['sdate'].to_a[0..2]) if ICalPal::Event === item && item['sdate']
63
+ $items.push(item)
64
+ end
65
+
66
+
67
+ ##################################################
68
+ # Load the data
69
+
70
+ # What are we getting?
71
+ klass = ICalPal.call($opts[:cmd])
72
+ success = false
73
+
74
+ # Get it
75
+ $opts[:db].each do |db|
76
+ $log.debug("Trying #{db}")
77
+
78
+ if klass == ICalPal::Reminder
79
+ begin
80
+ # Load all .sqlite files
81
+ $log.debug("Loading *.sqlite in #{db}")
82
+ Dir.glob("#{db}/*.sqlite").each do |d|
83
+ $rows += ICalPal.load_data(d, klass::QUERY)
84
+ success = true
85
+
86
+ rescue SQLite3::CantOpenException
87
+ # Non-fatal exception, try the next one
88
+ end
89
+ end
90
+ else
91
+ # Load database
92
+ begin
93
+ $rows += ICalPal.load_data(db, klass::QUERY)
94
+ success = true
95
+
96
+ rescue SQLite3::CantOpenException
97
+ # Non-fatal exception, try the next one
98
+ end
99
+ end
100
+ end
101
+
102
+ # Make sure we opened at least one database
103
+ unless success
104
+ $log.fatal('Could not open database')
105
+
106
+ # SQLite3 does not return useful error messages. If any databases
107
+ # failed because of EPERM (operation not permitted), our parent
108
+ # process might need Full Disk Access, and we should suggest that.
109
+ eperm = 0
110
+
111
+ $opts[:db].each do |db|
112
+ # Use a real open to get a useful error
113
+ File.open(db).close
114
+ rescue Exception => e
115
+ $log.fatal("#{e.class}: #{db}")
116
+
117
+ eperm = 1 if e.instance_of?(Errno::EPERM)
118
+ end
119
+
120
+ if eperm.positive?
121
+ $stderr.puts
122
+ $stderr.puts "Does #{ancestor} have Full Disk Access in System Settings?"
123
+ $stderr.puts
124
+ $stderr.puts "Try running: open 'x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles'"
125
+ end
126
+
127
+ abort
128
+ end
129
+
130
+ $log.info("Loaded #{$rows.count} #{klass} rows")
131
+
132
+
133
+ ##################################################
134
+ # Process the data
135
+
136
+ # Add rows
137
+ $rows.each_with_index do |row, i|
138
+ $log.debug("Row #{i}: #{row['ROWID']}:#{row['UUID']} - #{row['account']}/#{row['calendar']}/#{row['title']}")
139
+
140
+ # --es/--is
141
+ if $opts[:es].any? row['account']
142
+ $log.debug(':es')
143
+ next
144
+ end
145
+
146
+ unless $opts[:is].empty? || ($opts[:is].any? row['account'])
147
+ $log.debug(':is')
148
+ next
149
+ end
150
+
151
+ # --ec/--ic
152
+ unless klass == ICalPal::Store || !row['calendar']
153
+ if $opts[:ec].any? row['calendar']
154
+ $log.debug(':ec')
155
+ next
156
+ end
157
+
158
+ unless $opts[:ic].empty? || ($opts[:ic].any? row['calendar'])
159
+ $log.debug(':ic')
160
+ next
161
+ end
162
+ end
163
+
164
+ # Instantiate an item
165
+ item = klass.new(row)
166
+
167
+ # --et/--it
168
+ if $opts[:et].any? item['type']
169
+ $log.debug(':et')
170
+ next
171
+ end
172
+
173
+ unless $opts[:it].empty? || ($opts[:it].any? item['type'])
174
+ $log.debug(':it')
175
+ next
176
+ end
177
+
178
+ # --el/--il
179
+ if $opts[:el].any? item['list_name']
180
+ $log.debug(':el')
181
+ next
182
+ end
183
+
184
+ unless $opts[:il].empty? || ($opts[:il].any? item['list_name'])
185
+ $log.debug(':il')
186
+ next
187
+ end
188
+
189
+ # --match
190
+ if $opts[:match]
191
+ r = $opts[:match].split('=')
192
+
193
+ if item[r[0]].to_s.respond_to?(:match)
194
+ unless item[r[0]].to_s.match(Regexp.new(r[1].to_s, Regexp::IGNORECASE))
195
+ $log.debug(':match')
196
+ next
197
+ end
198
+ end
199
+ end
200
+
201
+ if ICalPal::Event === item
202
+ # Check for all-day and cancelled events
203
+ if $opts[:ea] && item['all_day'].positive?
204
+ $log.debug(':ea')
205
+ next
206
+ end
207
+
208
+ if $opts[:ia] && !item['all_day'].positive?
209
+ $log.debug(':ia')
210
+ next
211
+ end
212
+
213
+ if item['status'] == :canceled
214
+ $log.debug(':canceled')
215
+ next
216
+ end
217
+
218
+ (item['has_recurrences'].positive?)?
219
+ item.recurring.each { |i| add(i) } :
220
+ item.non_recurring.each { |i| add(i) }
221
+ else
222
+ # Check for dated reminders
223
+ if ICalPal::Reminder === item
224
+ if $opts[:dated] == 1 && item['due_date'].positive?
225
+ $log.debug(':undated')
226
+ next
227
+ end
228
+
229
+ if $opts[:dated] == 2 && item['due_date'].zero?
230
+ $log.debug(':dated')
231
+ next
232
+ end
233
+ end
234
+
235
+ add(item)
236
+ end
237
+ end
238
+
239
+ # Add placeholders for empty days
240
+ if $opts[:sed] && $opts[:sd] && klass == ICalPal::Event
241
+ days = $items.collect { |i| i['sday'] }.uniq.sort
242
+
243
+ $opts[:days].times do |n|
244
+ day = $opts[:from] + n
245
+ $items.push(klass.new(day)) unless days.any? { |i| i.to_s == day.to_s }
246
+ end
247
+ end
248
+
249
+ # Sort the rows
250
+ begin
251
+ $log.info("Sorting/uniqing #{$items.count} items by #{[ $opts[:sep], $opts[:sort], 'sdate' ]}, reverse #{$opts[:reverse].inspect}")
252
+
253
+ $items.sort_by! { |i| [ i[$opts[:sep]], i[$opts[:sort]], i['sdate'] ] }
254
+ $items.reverse! if $opts[:reverse]
255
+ $items.uniq!
256
+ rescue Exception => e
257
+ $log.info("Sorting failed: #{e}\n")
258
+ end
259
+
260
+ $log.debug("#{$items.count} items remain")
261
+
262
+ # Configure formatting
263
+ mu = case $opts[:output]
264
+ when 'ansi' then RDoc::Markup::ToAnsi.new
265
+ when 'default' then RDoc::Markup::ToICalPal.new($opts)
266
+ when 'html'
267
+ rdoc = RDoc::Options.new
268
+ rdoc.pipe = true
269
+ rdoc.output_decoration = false
270
+ RDoc::Markup::ToHtml.new(rdoc)
271
+ when 'md' then RDoc::Markup::ToMarkdown.new
272
+ when 'rdoc' then RDoc::Markup::ToRdoc.new
273
+ when 'toc' then RDoc::Markup::ToTableOfContents.new
274
+ end
275
+
276
+
277
+ ##################################################
278
+ # Print the data
279
+
280
+ items = $items[0..$opts[:li] - 1]
281
+
282
+ unless mu
283
+ $log.debug("Output in #{$opts[:output]} format")
284
+
285
+ puts case $opts[:output]
286
+ when 'csv'
287
+ # Get all headers
288
+ headers = []
289
+ items.each { |i| headers += i.keys }
290
+ headers.uniq!
291
+
292
+ # Populate a CSV::Table
293
+ table = CSV::Table.new([], headers: headers)
294
+ items.each { |i| table << i.to_csv(headers) }
295
+
296
+ table
297
+ when 'hash' then items.map { |i| i.self }
298
+ when 'json' then items.map { |i| i.self }.to_json
299
+ when 'xml'
300
+ xml = items.map { |i| "<#{$opts[:cmd].chomp('s')}>#{i.to_xml}</#{$opts[:cmd].chomp('s')}>" }
301
+ "<#{$opts[:cmd]}>\n#{xml.join('')}</#{$opts[:cmd]}>"
302
+ when 'yaml' then items.map { |i| i.self }.to_yaml
303
+ when 'remind' then items.map { |i|
304
+ "REM #{i['sdate'].strftime('%F AT %R')} " +
305
+ "DURATION #{((i['edate'] - i['sdate']).to_f * 1440).to_i} " +
306
+ "MSG #{i['title']}"
307
+ }.join("\n")
308
+ else abort "No formatter for #{$opts[:output]}"
309
+ end
310
+
311
+ exit
312
+ end
313
+
314
+ $log.debug("Formatting with #{mu.inspect}")
315
+
316
+ doc = RDoc::Markup::Document.new
317
+ section = nil
318
+
319
+ items.each_with_index do |i, j|
320
+ $log.debug("Print #{j}: #{i.inspect}")
321
+
322
+ # --li
323
+ break if $opts[:li].positive? && j >= $opts[:li]
324
+
325
+ # Use RDoc::Markup::Verbatim to save the item
326
+ v = RDoc::Markup::Verbatim.new
327
+ v.format = i
328
+ doc << v
329
+
330
+ # Sections
331
+ if $opts[:sep] && section != i[$opts[:sep]]
332
+ $log.debug("New section '#{$opts[:sep]}': #{i[$opts[:sep]]}")
333
+
334
+ doc << RDoc::Markup::Raw.new($opts[:sep])
335
+
336
+ doc << RDoc::Markup::BlankLine.new if j.positive?
337
+ doc << RDoc::Markup::Heading.new(1, i[$opts[:sep]].to_s)
338
+ doc << RDoc::Markup::Rule.new(0)
339
+
340
+ section = i[$opts[:sep]]
341
+ end
342
+
343
+ # Item
344
+ props = RDoc::Markup::List.new(:BULLET)
345
+
346
+ # Properties
347
+ $opts[:props].each_with_index do |prop, k|
348
+ value = i[prop]
349
+
350
+ next unless value
351
+ next if Array === value && !value[0]
352
+ next if String === value && value.empty?
353
+
354
+ $log.debug("#{prop}: #{value}")
355
+
356
+ # Use Raw to save the property
357
+ props << RDoc::Markup::Raw.new(prop)
358
+
359
+ if k.positive?
360
+ props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
361
+ props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(value)) unless (i['placeholder'])
362
+ else
363
+ # First property, value only
364
+ props << RDoc::Markup::Heading.new(2, value.to_s)
365
+ end
366
+
367
+ # unless k.positive?
368
+ # # First property, value only
369
+ # props << RDoc::Markup::Heading.new(2, value.to_s)
370
+ # else
371
+ # props << RDoc::Markup::BlankLine.new unless (i['placeholder'] || $opts[:ps])
372
+ # props << RDoc::Markup::ListItem.new(prop, RDoc::Markup::Paragraph.new(value)) unless (i['placeholder'])
373
+ # end
374
+ end
375
+
376
+ # Print it
377
+ props << RDoc::Markup::BlankLine.new unless props.empty?
378
+
379
+ doc << props
380
+ end
381
+
382
+ print doc.accept(mu)
data/icalPal.gemspec CHANGED
@@ -15,13 +15,41 @@ EOF
15
15
  s.homepage = "https://github.com/ajrosen/#{s.name}"
16
16
  s.licenses = [ 'GPL-3.0-or-later' ]
17
17
 
18
+ s.metadata = {
19
+ 'bug_tracker_uri' => "https://github.com/ajrosen/#{s.name}/issues"
20
+ }
21
+
18
22
  s.files = Dir["#{s.name}.gemspec", 'bin/*', 'lib/*.rb']
19
23
  s.executables = [ "#{s.name}" ]
20
24
  s.extra_rdoc_files = [ 'README.md' ]
21
25
 
22
- s.add_runtime_dependency 'nokogiri-plist', '~> 0.5.0'
23
- s.add_runtime_dependency 'sqlite3', '~> 2'
26
+ s.add_dependency 'nokogiri-plist', '~> 0.5.0'
27
+ s.add_dependency 'sqlite3', '~> 2.6.0' unless s.rubygems_version == `/usr/bin/gem --version`.strip
28
+
29
+ # The macOS and Homebrew versions of rubygems have incompatible
30
+ # requirements for sqlite3.
31
+ #
32
+ # macOS comes with version 1.3.13, so it does not need to be added
33
+ # as a dependency, but it cannot install anything newer:
34
+ #
35
+ # requires Ruby version >= 3.0, < 3.4.dev. The current ruby version is 2.6.10.
36
+ #
37
+ # Homebrew's Ruby formula does not come with sqlite3, so it does
38
+ # need to be added as a dependency, but it cannot install version
39
+ # 1.3.13:
40
+ #
41
+ # error: call to undeclared function
42
+ #
43
+ # So we must call add_dependency, but iff we are not building with
44
+ # macOS' Ruby installation.
24
45
 
25
46
  s.bindir = 'bin'
26
47
  s.required_ruby_version = '>= 2.6.0'
48
+
49
+ s.post_install_message = <<-EOF
50
+
51
+ Note: #{ICalPal::NAME} requires "Full Disk Access" in System Settings to access your calendar.
52
+ Make sure the program that runs #{ICalPal::NAME}, not #{ICalPal::NAME} itself, has these permissions.
53
+
54
+ EOF
27
55
  end
data/lib/defaults.rb CHANGED
@@ -73,6 +73,7 @@ $defaults = {
73
73
  n: false,
74
74
  nnr: "\n ",
75
75
  nrd: false,
76
+ now: false,
76
77
  ps: [ "\n " ],
77
78
  sa: false,
78
79
  sed: false,
data/lib/event.rb CHANGED
@@ -130,7 +130,7 @@ module ICalPal
130
130
  $log.debug("multi-day event #{i + 1}") if (i.positive?)
131
131
 
132
132
  self['daynum'] = i + 1
133
- events.push(clone) if in_window?(self['sdate'])
133
+ events.push(clone) if in_window?(self['sdate'], self['edate'])
134
134
 
135
135
  self['sdate'] += 1
136
136
  self['edate'] += 1
@@ -287,8 +287,8 @@ module ICalPal
287
287
  # @param s [RDT] Event start
288
288
  # @param e [RDT] Event end
289
289
  # @return [Boolean]
290
- def in_window?(s, e = s)
291
- if $opts[:n]
290
+ def in_window?(s, e)
291
+ if $opts[:now]
292
292
  if ($now >= s && $now < e)
293
293
  $log.debug("now: #{s} to #{e} vs. #{$now}")
294
294
  true
data/lib/icalPal.rb CHANGED
@@ -110,38 +110,6 @@ module ICalPal
110
110
  retval
111
111
  end
112
112
 
113
- # Convert a key/value pair to XML. The value should be +nil+, +String+,
114
- # +Integer+, +Array+, or +ICalPal::RDT+
115
- #
116
- # @param key The key
117
- # @param value The value
118
- # @return [String] The key/value pair in a simple XML format
119
- def xmlify(key, value)
120
- case value
121
- # Nil
122
- when NilClass then "<#{key}/>"
123
-
124
- # String, Integer
125
- when String then "<#{key}>#{value}</#{key}>"
126
- when Integer then "<#{key}>#{value}</#{key}>"
127
-
128
- # Array
129
- when Array
130
- # Treat empty arrays as nil values
131
- xmlify(key, nil) if value[0].nil?
132
-
133
- retval = ''
134
- value.each { |x| retval += xmlify("#{key}0", x) }
135
- "<#{key}>#{retval}</#{key}>"
136
-
137
- # RDT
138
- when ICalPal::RDT then "<#{key}>#{value}</#{key}>"
139
-
140
- # Unknown
141
- else "<#{key}>#{value}</#{key}>"
142
- end
143
- end
144
-
145
113
  # Get the +n+'th +dow+ in month +m+
146
114
  #
147
115
  # @param n [Integer] Integer between -4 and +4
data/lib/options.rb CHANGED
@@ -197,7 +197,7 @@ module ICalPal
197
197
 
198
198
  # Parse eventsNow and eventsToday commands
199
199
  cli[:cmd].match('events(Now|Today)(\+[0-9]+)?') do |m|
200
- cli[:n] = true if m[1] == 'Now'
200
+ cli[:now] = true if m[1] == 'Now'
201
201
  cli[:days] = (m[1] == 'Today')? m[2].to_i + 1 : 1
202
202
 
203
203
  cli[:from] = $today
data/lib/utils.rb ADDED
@@ -0,0 +1,45 @@
1
+ # Convert a key/value pair to XML. The value should be +nil+, +String+,
2
+ # +Integer+, +Array+, or +ICalPal::RDT+
3
+ #
4
+ # @param key The key
5
+ # @param value The value
6
+ # @return [String] The key/value pair in a simple XML format
7
+ def xmlify(key, value)
8
+ case value
9
+ # Nil
10
+ when NilClass then "<#{key}/>"
11
+
12
+ # String, Integer
13
+ when String then "<#{key}>#{value}</#{key}>"
14
+ when Integer then "<#{key}>#{value}</#{key}>"
15
+
16
+ # Array
17
+ when Array
18
+ # Treat empty arrays as nil values
19
+ xmlify(key, nil) if value[0].nil?
20
+
21
+ retval = ''
22
+ value.each { |x| retval += xmlify("#{key}0", x) }
23
+ "<#{key}>#{retval}</#{key}>"
24
+
25
+ # RDT
26
+ when ICalPal::RDT then "<#{key}>#{value}</#{key}>"
27
+
28
+ # Unknown
29
+ else "<#{key}>#{value}</#{key}>"
30
+ end
31
+ end
32
+
33
+ # Get the application icalPal is most likely running in
34
+ #
35
+ # @return [Integer] The basename of the program whose parent process id is 1 (launchd)
36
+ def ancestor
37
+ ppid = Process.ppid
38
+
39
+ while (ppid != 1)
40
+ ps = `ps -p #{ppid} -o ppid,command | tail -1`
41
+ ppid = ps[/^[0-9 ]+ /].to_i
42
+ end
43
+
44
+ ps[ps.rindex('/') + 1..].chop
45
+ end
data/lib/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module ICalPal
2
2
  NAME = 'icalPal'.freeze
3
- VERSION = '3.2.0'.freeze
3
+ VERSION = '3.3.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icalPal
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Rosen
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-19 00:00:00.000000000 Z
10
+ date: 2025-03-24 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: nokogiri-plist
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '2'
32
+ version: 2.6.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '2'
39
+ version: 2.6.0
40
40
  description: |
41
41
  Inspired by icalBuddy and maintains close compatability. Includes
42
42
  many additional features for querying, filtering, and formatting.
@@ -49,6 +49,7 @@ extra_rdoc_files:
49
49
  files:
50
50
  - README.md
51
51
  - bin/icalPal
52
+ - bin/icalpal
52
53
  - icalPal.gemspec
53
54
  - lib/EventKit.rb
54
55
  - lib/ToICalPal.rb
@@ -60,11 +61,18 @@ files:
60
61
  - lib/rdt.rb
61
62
  - lib/reminder.rb
62
63
  - lib/store.rb
64
+ - lib/utils.rb
63
65
  - lib/version.rb
64
66
  homepage: https://github.com/ajrosen/icalPal
65
67
  licenses:
66
68
  - GPL-3.0-or-later
67
- metadata: {}
69
+ metadata:
70
+ bug_tracker_uri: https://github.com/ajrosen/icalPal/issues
71
+ post_install_message: |2+
72
+
73
+ Note: icalPal requires "Full Disk Access" in System Settings to access your calendar.
74
+ Make sure the program that runs icalPal, not icalPal itself, has these permissions.
75
+
68
76
  rdoc_options: []
69
77
  require_paths:
70
78
  - lib
@@ -79,7 +87,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
87
  - !ruby/object:Gem::Version
80
88
  version: '0'
81
89
  requirements: []
82
- rubygems_version: 3.6.3
90
+ rubygems_version: 3.6.6
83
91
  specification_version: 4
84
92
  summary: Command-line tool to query the macOS Calendar
85
93
  test_files: []
94
+ ...