mhc 1.0.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.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/COPYRIGHT +28 -0
  6. data/Gemfile +8 -0
  7. data/README.org +209 -0
  8. data/Rakefile +13 -0
  9. data/bin/mhc +312 -0
  10. data/emacs/Cask +25 -0
  11. data/emacs/Makefile +58 -0
  12. data/emacs/mhc-calendar.el +1723 -0
  13. data/emacs/mhc-calfw.el +135 -0
  14. data/emacs/mhc-compat.el +90 -0
  15. data/emacs/mhc-date.el +642 -0
  16. data/emacs/mhc-day.el +149 -0
  17. data/emacs/mhc-db.el +158 -0
  18. data/emacs/mhc-draft.el +211 -0
  19. data/emacs/mhc-e21.el +167 -0
  20. data/emacs/mhc-face.el +236 -0
  21. data/emacs/mhc-file.el +224 -0
  22. data/emacs/mhc-guess.el +648 -0
  23. data/emacs/mhc-header.el +176 -0
  24. data/emacs/mhc-logic.el +563 -0
  25. data/emacs/mhc-message.el +130 -0
  26. data/emacs/mhc-minibuf.el +466 -0
  27. data/emacs/mhc-misc.el +248 -0
  28. data/emacs/mhc-mua.el +260 -0
  29. data/emacs/mhc-parse.el +286 -0
  30. data/emacs/mhc-process.el +35 -0
  31. data/emacs/mhc-ps.el +1174 -0
  32. data/emacs/mhc-record.el +201 -0
  33. data/emacs/mhc-schedule.el +202 -0
  34. data/emacs/mhc-summary.el +763 -0
  35. data/emacs/mhc-sync.el +158 -0
  36. data/emacs/mhc-vars.el +149 -0
  37. data/emacs/mhc.el +1114 -0
  38. data/icons/Anniversary.xbm +6 -0
  39. data/icons/Anniversary.xpm +27 -0
  40. data/icons/Birthday.xbm +6 -0
  41. data/icons/Birthday.xpm +25 -0
  42. data/icons/Business.xbm +6 -0
  43. data/icons/Business.xpm +24 -0
  44. data/icons/CheckBox.xbm +6 -0
  45. data/icons/CheckBox.xpm +24 -0
  46. data/icons/CheckedBox.xbm +6 -0
  47. data/icons/CheckedBox.xpm +25 -0
  48. data/icons/Conflict.xbm +6 -0
  49. data/icons/Conflict.xpm +22 -0
  50. data/icons/Date.xbm +6 -0
  51. data/icons/Date.xpm +29 -0
  52. data/icons/Holiday.xbm +6 -0
  53. data/icons/Holiday.xpm +25 -0
  54. data/icons/Link.xbm +6 -0
  55. data/icons/Link.xpm +25 -0
  56. data/icons/Other.xbm +6 -0
  57. data/icons/Other.xpm +28 -0
  58. data/icons/Party.xbm +6 -0
  59. data/icons/Party.xpm +23 -0
  60. data/icons/Private.xbm +6 -0
  61. data/icons/Private.xpm +26 -0
  62. data/icons/Recurrence.xbm +6 -0
  63. data/icons/Recurrence.xpm +98 -0
  64. data/icons/Vacation.xbm +6 -0
  65. data/icons/Vacation.xpm +26 -0
  66. data/lib/mhc.rb +45 -0
  67. data/lib/mhc/builder.rb +64 -0
  68. data/lib/mhc/caldav.rb +304 -0
  69. data/lib/mhc/calendar.rb +106 -0
  70. data/lib/mhc/command.rb +13 -0
  71. data/lib/mhc/command/cache.rb +14 -0
  72. data/lib/mhc/command/completions.rb +108 -0
  73. data/lib/mhc/command/init.rb +133 -0
  74. data/lib/mhc/command/scan.rb +33 -0
  75. data/lib/mhc/command/sync.rb +22 -0
  76. data/lib/mhc/config.rb +229 -0
  77. data/lib/mhc/converter.rb +330 -0
  78. data/lib/mhc/datastore.rb +164 -0
  79. data/lib/mhc/date_enumerator.rb +274 -0
  80. data/lib/mhc/date_frame.rb +124 -0
  81. data/lib/mhc/date_helper.rb +49 -0
  82. data/lib/mhc/etag.rb +68 -0
  83. data/lib/mhc/event.rb +396 -0
  84. data/lib/mhc/formatter.rb +312 -0
  85. data/lib/mhc/logger.rb +94 -0
  86. data/lib/mhc/modifier.rb +149 -0
  87. data/lib/mhc/occurrence.rb +94 -0
  88. data/lib/mhc/occurrence_enumerator.rb +113 -0
  89. data/lib/mhc/property_value.rb +33 -0
  90. data/lib/mhc/property_value/date.rb +190 -0
  91. data/lib/mhc/property_value/integer.rb +15 -0
  92. data/lib/mhc/property_value/list.rb +41 -0
  93. data/lib/mhc/property_value/period.rb +49 -0
  94. data/lib/mhc/property_value/range.rb +100 -0
  95. data/lib/mhc/property_value/recurrence_condition.rb +272 -0
  96. data/lib/mhc/property_value/text.rb +11 -0
  97. data/lib/mhc/property_value/time.rb +45 -0
  98. data/lib/mhc/query.rb +210 -0
  99. data/lib/mhc/sync.rb +46 -0
  100. data/lib/mhc/sync/driver.rb +108 -0
  101. data/lib/mhc/sync/status.rb +70 -0
  102. data/lib/mhc/sync/status_manager.rb +142 -0
  103. data/lib/mhc/sync/strategy.rb +233 -0
  104. data/lib/mhc/sync/syncinfo.rb +98 -0
  105. data/lib/mhc/templates/config.yml.erb +142 -0
  106. data/lib/mhc/version.rb +4 -0
  107. data/lib/mhc/webdav.rb +319 -0
  108. data/mhc.gemspec +24 -0
  109. data/samples/DOT.mhc-config.yml +116 -0
  110. data/samples/japanese-holidays.mhcc +153 -0
  111. data/samples/mhc-completions.zsh +11 -0
  112. data/spec/mhc_spec.rb +682 -0
  113. data/spec/spec_helper.rb +9 -0
  114. data/xpm/close.xpm +18 -0
  115. data/xpm/delete.xpm +19 -0
  116. data/xpm/exit.xpm +18 -0
  117. data/xpm/month.xpm +18 -0
  118. data/xpm/next.xpm +18 -0
  119. data/xpm/next2.xpm +18 -0
  120. data/xpm/next_year.xpm +18 -0
  121. data/xpm/open.xpm +19 -0
  122. data/xpm/prev.xpm +18 -0
  123. data/xpm/prev2.xpm +18 -0
  124. data/xpm/prev_year.xpm +18 -0
  125. data/xpm/save.xpm +19 -0
  126. data/xpm/today.xpm +18 -0
  127. metadata +214 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e9eb513930c0f5d993e1755bed627593443df3e2
4
+ data.tar.gz: d4a6c467fe781e96c68c0ebad0a96f743e8d6a8b
5
+ SHA512:
6
+ metadata.gz: 0027ebd2eaab008113d12e02062011bf403ce7f3611f8d41cd874ee0c16434ed3e9c576abb10199426f2d374c6ea8c397209ee35ec453b86c42713c56c7c39b1
7
+ data.tar.gz: 4b3ba18ed523c7105e9109f573b10f74bf1c4cfefbc99dea2e5d2dc4a09b03f6a17bd349097efae502b650323a6b64456dd3e0193fbc5f41516029519d1438e8
data/.gitignore ADDED
@@ -0,0 +1,27 @@
1
+ *.elc
2
+ *.gem
3
+ *.rbc
4
+ .DS_Store
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ attic/
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ rdocs/
18
+ spec/reports
19
+ test/tmp
20
+ test/version_tmp
21
+ tmp
22
+ vendor/bundle
23
+ .ruby-version
24
+ .ruby-gemset
25
+ .rvmrc
26
+ dist
27
+ .cask
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
data/COPYRIGHT ADDED
@@ -0,0 +1,28 @@
1
+ Copyright (C) 1999, 2000 Yoshinari Nomura. All rights reserved.
2
+ Copyright (C) 2000-2015 MHC developing team. All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. Neither the name of the team nor the names of its contributors
14
+ may be used to endorse or promote products derived from this software
15
+ without specific prior written permission.
16
+
17
+ THIS SOFTWARE IS PROVIDED BY THE TEAM AND CONTRIBUTORS ``AS IS''
18
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ THE TEAM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28
+ OF THE POSSIBILITY OF SUCH DAMAGE.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mhc.gemspec
4
+ gemspec
5
+ gem "thor"
6
+ gem "ri_cal", :git => 'https://github.com/yoshinari-nomura/ri_cal.git'
7
+ gem "tzinfo"
8
+ gem "tzinfo-data"
data/README.org ADDED
@@ -0,0 +1,209 @@
1
+ #+TITLE: MHC -- Message Harmonized Calendaring system.
2
+ #+AUTHOR: Yoshinari Nomura
3
+ #+EMAIL:
4
+ #+DATE: 2015-03-16
5
+ #+OPTIONS: H:3 num:2 toc:nil
6
+ #+OPTIONS: ^:nil @:t \n:nil ::t |:t f:t TeX:t
7
+ #+OPTIONS: skip:nil
8
+ #+OPTIONS: author:t
9
+ #+OPTIONS: email:nil
10
+ #+OPTIONS: creator:nil
11
+ #+OPTIONS: timestamp:nil
12
+ #+OPTIONS: timestamps:nil
13
+ #+OPTIONS: d:nil
14
+ #+OPTIONS: tags:t
15
+ #+TEXT:
16
+ #+DESCRIPTION:
17
+ #+KEYWORDS:
18
+ #+LANGUAGE: ja
19
+ #+LATEX_CLASS: jsarticle
20
+ #+LATEX_CLASS_OPTIONS: [a4j]
21
+ # #+LATEX_HEADER: \usepackage{plain-article}
22
+ # #+LATEX_HEADER: \renewcommand\maketitle{}
23
+ # #+LATEX_HEADER: \pagestyle{empty}
24
+ # #+LaTeX: \thispagestyle{empty}
25
+
26
+ * DESCRIPTION
27
+ MHC is designed to help those who receive most appointments via email.
28
+ Using MHC, you can easily import schedule articles from emails.
29
+
30
+ You can get the latest version from:
31
+ + https://github.com/yoshinari-nomura/mhc
32
+ + http://www.quickhack.net/mhc
33
+
34
+ MHC has following features:
35
+
36
+ + Easy import your schedule from existing buffers.
37
+ For example, using with Mew/Gnus/Wanderlust (MUAs on Emacs),
38
+ you can easily compose your schedule items from
39
+ appoint-emails. MHC will guess the title,
40
+ date, time and description by scanning the email.
41
+ + Simple data structure allows you to manipulate stored data in many ways.
42
+ + Appointments can be made to repeat in flexible ways.
43
+ + powerful but simple expression of appointments.
44
+
45
+ MHC stores schedule articles in the same form of MH; you can manipulate
46
+ these messages not only by above tools but also by many other MUAs,
47
+ editors, UNIX commandline tools or your own scripts.
48
+
49
+ * SYSTEM REQUIREMENTS
50
+ + Ruby 2.1 or newer
51
+ + Emacs 24 or newer
52
+
53
+ * Information for Developers
54
+ ** INSTALL for developers:
55
+ 1) Install rbenv + ruby-build
56
+ (see https://github.com/sstephenson/rbenv#basic-github-checkout for details)
57
+ #+BEGIN_SRC shell-script
58
+ $ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
59
+ $ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
60
+ # Edit your shell dot files to add some path and environment variables.
61
+ #+END_SRC
62
+
63
+ 2) Install Latest Ruby and bundler
64
+ #+BEGIN_SRC shell-script
65
+ # Install ruby 2.1.2
66
+ $ rbenv install 2.1.2
67
+
68
+ # Installation check
69
+ $ rbenv global 2.1.2
70
+ $ ruby -v # -> You will see: ruby 2.1.2...
71
+
72
+ # Install bundler for your new Ruby
73
+ $ gem install bundler
74
+
75
+ # If you want to use Ruby in your sytem, say /usr/bin/ruby
76
+ $ rbenv global system
77
+ $ ruby -v
78
+ #+END_SRC
79
+
80
+ 3) Clone MHC from github
81
+ #+BEGIN_SRC shell-script
82
+ $ git clone git@github.com:yoshinari-nomura/mhc.git ~/src/mhc
83
+ #+END_SRC
84
+
85
+ 4) Set default ruby version in MHC project
86
+ #+BEGIN_SRC shell-script
87
+ $ cd ~/src/mhc
88
+ $ echo '2.1.2' > .ruby-version
89
+ $ ruby -v # -> You will see: ruby 2.1.2...
90
+ #+END_SRC
91
+
92
+ 5) Install requied gem packages in sandbox ~/src/mhc/vendor/bundle
93
+ #+BEGIN_SRC shell-script
94
+ $ cd ~/src/mhc
95
+ $ bundle install --path vendor/bundle
96
+ #+END_SRC
97
+
98
+ 6) Initialize config file and spool directory
99
+ #+BEGIN_SRC shell-script
100
+ $ bin/mhc init ~/mhc
101
+
102
+ Guessing current local timezone ...
103
+ ok guess timezone ... Asia/Tokyo
104
+ Making directries under ~/mhc ...
105
+ create ~/mhc/draft
106
+ create ~/mhc/inbox
107
+ create ~/mhc/presets
108
+ create ~/mhc/spool
109
+ create ~/mhc/trash
110
+ create ~/mhc/status/cache
111
+ create ~/mhc/status/log
112
+ create ~/mhc/status/sync_channels
113
+ Copying config file(s) into ~/.config/mhc/config.yml ...
114
+ ok copy ~/.config/mhc/config.yml
115
+ Done.
116
+
117
+ # Read comments in config.yml carefully
118
+ $ vi ~/.config/mhc/config.yml
119
+
120
+ # Add Japanese Holidays if needed.
121
+ $ cp samples/japanese-holidays.mhcc ~/mhc/presets/
122
+
123
+ # Add ~/src/mhc/bin directory to your $PATH for dogfooding
124
+ $ export PATH=$HOME/src/mhc/bin:$PATH
125
+ #+END_SRC
126
+
127
+ 7) Byte-compile Emacs client
128
+ #+BEGIN_SRC shell-script
129
+ $ cd emacs
130
+ $ make
131
+ #+END_SRC
132
+
133
+ 8) Add setup in your =.emacs.d/init.el=
134
+ #+BEGIN_SRC emacs-lisp
135
+ (setq load-path
136
+ (cons "~/src/mhc/emacs" load-path))
137
+ (autoload 'mhc-mua-setup "mhc-mua")
138
+ (mhc-mua-setup)
139
+
140
+ ;; M-x mhc-goto-this-month
141
+ #+END_SRC
142
+
143
+ 9) Check if TODAY is good.
144
+ #+BEGIN_SRC shell-script
145
+ $ mhc scan today
146
+ #+END_SRC
147
+
148
+ You may add ~/src/mhc/bin directory to your $PATH for dogfooding
149
+
150
+ ** DIRECTORY STRUCTURE
151
+ *** Configuration Directory
152
+ Default configuration directory is =~/.config/mhc=.
153
+ If environment variable =MHC_CONFIG_HOME= or =XDG_CONFIG_HOME= is set,
154
+ it is taken as =$MHC_CONFIG_HOME/mhc= or =$XDG_CONFIG_HOME/mhc=.
155
+
156
+ Configuration directory =~/.config/mhc= has these stuffs:
157
+ + config.yml :: Configuration file (mandatory).
158
+ + plugins :: Your home-made Ruby functions.
159
+ See [[file:samples][samples]] for details.
160
+
161
+ *** Spool Directory
162
+ Location of the spool directory should be set
163
+ by =TOPDIR:= element in =config.yml=.
164
+
165
+ For example, if you have =TOPDIR: ~/MHC= entry
166
+ in your =config.yml=, you will have these directory structure
167
+ under =~/MHC=:
168
+
169
+ + spool/*.mhc :: MHC event database. All events are flatly located
170
+ in this directory in the form of ={x-sc-message-id}.mhc=
171
+ + draft/*.mhc :: Draft files of events.
172
+ Opening a file in directory by Emacs,
173
+ and Typing =C-cC-c= will move the file into =spool= directory.
174
+ (Not implemented yet. Should be empty for now.)
175
+ + inbox/*.mhc :: Mainly same as =spool=. You will have a chance to
176
+ review these events in this directory afterwards.
177
+ (Not implemented yet. Should be empty for now.)
178
+ + presets/*.mhcc :: Database for fixed anniversary events
179
+ such as birthdays or national holidays.
180
+ + trash/*.mhc :: Removed events from =spool= directory.
181
+ + status/ ::
182
+ + cache/* :: Cache files for speed-up.
183
+ You can remove these files without any damage to MHC Database.
184
+ + log/* :: log files for debug.
185
+ You can remove these files without any damage to MHC DB.
186
+
187
+ + sync_channels/* :: Sync records of MHC DB.
188
+ If you remove any files under this directory,
189
+ MHC Sync will be DAMAGED.
190
+ * How to convert from the old MHC spool
191
+ [[https://gist.github.com/yoshinari-nomura/bb9a197e0e01ad81c883][update-uuid.sh]] would help you.
192
+
193
+ New format is:
194
+ + =X-SC-Record-Id= is now in UUID style.
195
+ + Each filename is in the form of ={UUID}.mhc=, not =[0-9]+=.
196
+ + UUID in =X-SC-Record-Id= is same as its file's base name.
197
+ + All articles are flatly placed in TOP/spool/ directory.
198
+
199
+ #+BEGIN_SRC shell-script
200
+ $ ./update-uuid.sh ~/Mail/schedule ~/mhc
201
+
202
+ Converting... logfile will be in /Users/nom/mhc/update-uuid.sh34485.log
203
+ #+END_SRC
204
+
205
+ For Japanese people, character-code conversion might be needed.
206
+ #+BEGIN_SRC shell-script
207
+ $ cd ~/mhc/spool
208
+ $ find . -name '*.mhc' | xargs -n 10 nkf --overwrite
209
+ #+END_SRC
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ require 'rdoc/task'
9
+ Rake::RDocTask.new do |rd|
10
+ rd.rdoc_dir = 'rdocs'
11
+ rd.rdoc_files = FileList["lib/**/*.rb"]
12
+ rd.options << '-charset=UTF-8'
13
+ end
data/bin/mhc ADDED
@@ -0,0 +1,312 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ################################################################
4
+ # rbenv support:
5
+ # If this file is a symlink, and bound to a specific ruby
6
+ # version via rbenv (indicated by RBENV_VERSION),
7
+ # I want to resolve the symlink and re-exec
8
+ # the original executable respecting the .ruby_version
9
+ # which should indicate the right version.
10
+ #
11
+ if File.symlink?(__FILE__) and ENV["RBENV_VERSION"]
12
+ ENV["RBENV_VERSION"] = nil
13
+ shims_path = File.expand_path("shims", ENV["RBENV_ROOT"])
14
+ ENV["PATH"] = shims_path + ":" + ENV["PATH"]
15
+ exec(File.readlink(__FILE__), *ARGV)
16
+ end
17
+
18
+ ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
19
+
20
+ require "rubygems"
21
+ require "bundler/setup"
22
+
23
+ require "thor"
24
+ require "mhc"
25
+
26
+ Encoding.default_external="UTF-8"
27
+
28
+ class MhcCLI < Thor
29
+ ################################################################
30
+ # constants
31
+
32
+ DEFAULT_CONFIG_HOME = File.join((ENV["XDG_CONFIG_HOME"] || "~/.config"), "mhc")
33
+ DEFAULT_CONFIG_FILE = "config.yml"
34
+ DEFAULT_CONFIG_PATH = File.join(DEFAULT_CONFIG_HOME, DEFAULT_CONFIG_FILE)
35
+
36
+ package_name 'MHC'
37
+
38
+ ################################################################
39
+ # class methods
40
+
41
+ class << self
42
+ attr_accessor :calendar
43
+ attr_accessor :popular_options
44
+ end
45
+
46
+ def self.register_option(name, options)
47
+ @popular_options ||= {}
48
+ @popular_options[name] = options
49
+ end
50
+
51
+ def self.named_option(*names)
52
+ names.each do |name|
53
+ method_option name, @popular_options[name]
54
+ end
55
+ end
56
+
57
+ ################################################################
58
+ # global options
59
+
60
+ class_option :debug, :desc => "Set debug flag", :type => :boolean
61
+ class_option :profile, :desc => "Set profiler flag", :type => :boolean
62
+ class_option :config, :desc => "Set config path (default: #{DEFAULT_CONFIG_PATH})", :banner => "FILE"
63
+
64
+ check_unknown_options! :except => :completions
65
+
66
+ ################################################################
67
+ # frequently used options
68
+
69
+ register_option :repository, :desc => "Set MHC top directory", :banner => "DIRECTORY"
70
+ register_option :calendar, :desc => "Set source CALENDAR"
71
+ register_option :category, :desc => "Pick items only in CATEGORY"
72
+ register_option :format, :desc => "Set printing format", :enum => %w(text mail orgtable emacs icalendar calfw howm)
73
+ register_option :search, :desc => "Search items by complex expression"
74
+ register_option :dry_run, :desc => "Perform a trial run with no changes made", :type => :boolean
75
+
76
+ ################################################################
77
+ # command name mappings
78
+
79
+ map ["--version", "-v"] => :version
80
+
81
+ map ["--help", "-h"] => :help
82
+ default_command :help
83
+
84
+ ################################################################
85
+ # Command: help
86
+ ################################################################
87
+
88
+ desc "help [COMMAND]", "Describe available commands or one specific command"
89
+ def help(command = nil)
90
+ super(command)
91
+ end
92
+
93
+ ################################################################
94
+ # Command: version
95
+ ################################################################
96
+ desc "version", "Show version"
97
+
98
+ def version
99
+ puts Mhc::VERSION
100
+ end
101
+
102
+ ################################################################
103
+ # Command: cache
104
+ ################################################################
105
+ desc "cache", "Dump cache file"
106
+
107
+ named_option :repository
108
+
109
+ def cache
110
+ Mhc::Command::Cache.new(calendar)
111
+ end
112
+
113
+ ################################################################
114
+ # Command: completions
115
+ ################################################################
116
+ desc "completions [COMMAND]", "List available commands or options for COMMAND", :hide => true
117
+
118
+ long_desc <<-LONGDESC
119
+ List available commands or options for COMMAND
120
+ This is supposed to be a zsh compsys helper"
121
+ LONGDESC
122
+
123
+ def completions(*command)
124
+ help = self.class.commands
125
+ global_options = self.class.class_options
126
+ Mhc::Command::Completions.new(help, global_options, command, config)
127
+ end
128
+
129
+ ################################################################
130
+ # Command: config
131
+ ################################################################
132
+ desc "configuration", "Show current configuration in various formats."
133
+
134
+ named_option :format
135
+
136
+ def configuration(name = nil)
137
+ puts Mhc::Converter::Emacs.new.to_emacs(config.get_value(name))
138
+ end
139
+
140
+ ################################################################
141
+ # Command: init
142
+ ################################################################
143
+ desc "init DIRECTORY", "Initialize MHC repository and configuration template"
144
+
145
+ def init(top_dir)
146
+ Mhc::Command::Init.new(top_dir, options[:config] || DEFAULT_CONFIG_PATH, ENV["MHC_TZID"])
147
+ end
148
+
149
+ ################################################################
150
+ # Command: scan
151
+ ################################################################
152
+ desc "scan RANGE", "Scan events in date RANGE"
153
+
154
+ long_desc <<-LONGDESC
155
+ scan events in date RANGE.
156
+
157
+ RANGE is one of:
158
+ \x5 + START-YYYYMMDD
159
+ \x5 + START[+LENGTH]
160
+
161
+ START is one of:
162
+ \x5 + today, tomorrow, sun ... sat, yyyymmdd
163
+ \x5 + thismonth, nextmonth, yyyymm
164
+
165
+ LENGTH is a number followed by a SUFFIX. SUFFIX is one of:
166
+ \x5 + d (days)
167
+ \x5 + w (weeks)
168
+ \x5 + m (months)
169
+
170
+ If LENGTH is omitted, it is treated as '1d' or '1m' depending on
171
+ which type of START is set.
172
+
173
+ Examples:
174
+ \x5 mhc scan 20140101-20141231
175
+ \x5 mhc scan 2140101+3d
176
+ \x5 mhc scan today --category 'Business'
177
+ \x5 mhc scan thismonth --search 'category:Business & !subject:"Trip"'
178
+ LONGDESC
179
+
180
+ named_option :calendar, :category, :format, :repository, :search
181
+
182
+ def scan(range)
183
+ begin
184
+ Mhc::Command::Scan.new(calendar, range, **symbolize_keys(options))
185
+ rescue Mhc::PropertyValue::ParseError, Mhc::FormatterNameError, Mhc::Query::ParseError => e
186
+ STDERR.print "Error: " + e.message + "\n"
187
+ end
188
+ return self
189
+ end
190
+
191
+ ################################################################
192
+ # Command: server
193
+ ################################################################
194
+ desc "server", "Invoked as server (backend of emacs)"
195
+
196
+ named_option :repository
197
+
198
+ def server
199
+ require "shellwords"
200
+ while line = STDIN.gets # STDIN.noecho(&:gets)
201
+ argv = line.chomp.shellsplit
202
+ self.class.start(argv)
203
+ STDOUT.flush
204
+ end
205
+ end
206
+
207
+ ################################################################
208
+ # Command: show
209
+ ################################################################
210
+ desc "show MESSAGE_ID", "Show article found by MESSAGE_ID"
211
+
212
+ named_option :calendar, :repository
213
+
214
+ def show(message_id)
215
+ event = exit_on_error do
216
+ calendar.find(uid: message_id)
217
+ end
218
+ print event.dump if event
219
+ end
220
+
221
+ ################################################################
222
+ # Command: sync
223
+ ################################################################
224
+ desc "sync SYNC_CHANNEL", "Synchronize DBs via SYNC_CHANNEL"
225
+
226
+ named_option :dry_run
227
+
228
+ def sync(channel_name)
229
+ driver = exit_on_error do
230
+ builder.sync_driver(channel_name)
231
+ end
232
+ driver.sync_all(options[:dry_run])
233
+ return self
234
+ end
235
+
236
+ ################################################################
237
+ # add some hooks to Thor
238
+
239
+ no_commands do
240
+ def invoke_command(command, *args)
241
+ setup_global_options unless command.name == "init"
242
+ result = super
243
+ teardown
244
+ result
245
+ end
246
+ end
247
+
248
+ ################################################################
249
+ # private
250
+
251
+ private
252
+
253
+ def exit_on_error(&block)
254
+ begin
255
+ yield if block_given?
256
+ rescue Mhc::ConfigurationError => e
257
+ STDERR.print "ERROR: #{e.message}.\n"
258
+ exit 1
259
+ end
260
+ end
261
+
262
+ attr_reader :builder, :config, :calendar
263
+
264
+ def setup_global_options
265
+ exit_on_error do
266
+ @config = Mhc::Config.create_from_file(options[:config] || DEFAULT_CONFIG_PATH)
267
+ @builder ||= Mhc::Builder.new(@config)
268
+ if @config.general.tzid
269
+ Mhc.default_tzid = @config.general.tzid
270
+ end
271
+
272
+ calname = options[:calendar] || @config.calendars.first.name
273
+ @config.general.repository = options[:repository] if options[:repository]
274
+
275
+ self.class.calendar ||= builder.calendar(calname)
276
+ @calendar = self.class.calendar
277
+ end
278
+
279
+ load_plugins
280
+
281
+ if options[:profile]
282
+ require 'profiler'
283
+ Profiler__.start_profile
284
+ end
285
+ if options[:debug]
286
+ require "pp"
287
+ $MHC_DEBUG = true
288
+ $MHC_DEBUG_FOR_DEVELOPER = true if ENV["MHC_DEBUG_FOR_DEVELOPER"]
289
+ end
290
+ end
291
+
292
+ def load_plugins
293
+ config_path = options[:config] || DEFAULT_CONFIG_PATH
294
+ plugin_dir = File.dirname(config_path)
295
+
296
+ Dir.glob(File.expand_path("plugins/*.rb", plugin_dir)) do |rb|
297
+ require rb
298
+ end
299
+ end
300
+
301
+ def teardown
302
+ if options[:profile]
303
+ Profiler__.print_profile($stdout)
304
+ end
305
+ end
306
+
307
+ def symbolize_keys(hash)
308
+ Hash[hash.map {|k,v| [k.to_sym, v]}]
309
+ end
310
+ end
311
+
312
+ command = MhcCLI.start(ARGV)