time_tap 0.2.0 → 0.4.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -37
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -21
- data/README.md +104 -41
- data/Rakefile +1 -30
- data/bin/timetap +25 -26
- data/lib/time_tap.rb +126 -52
- data/lib/time_tap/backend.rb +9 -0
- data/lib/time_tap/backend/file_system.rb +36 -0
- data/lib/time_tap/config.yml.example +32 -0
- data/lib/time_tap/editor.rb +9 -0
- data/lib/time_tap/editor/sublime_text2.rb +15 -0
- data/lib/time_tap/editor/text_mate.rb +22 -0
- data/lib/time_tap/editor/text_mate2.rb +15 -0
- data/lib/time_tap/editor/xcode.rb +24 -0
- data/lib/time_tap/project.rb +136 -116
- data/lib/time_tap/server.rb +20 -20
- data/lib/time_tap/version.rb +3 -0
- data/lib/time_tap/views/project.haml +5 -3
- data/lib/time_tap/views/project_day.haml +1 -0
- data/lib/time_tap/watcher.rb +46 -43
- data/log/.git-keep +1 -0
- data/spec/lib/time_tap/project_spec.rb +12 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/time_tap/backend_spec.rb +12 -0
- data/spec/time_tap/project_spec.rb +13 -0
- data/spec/time_tap/watcher_spec.rb +14 -0
- data/spec/time_tap_spec.rb +6 -4
- data/time_tap.gemspec +26 -108
- data/vendor/SublimeText2/.gitignore +1 -0
- data/vendor/SublimeText2/README.md +27 -0
- data/vendor/SublimeText2/TimeTap.py +10 -0
- data/vendor/TextMate2/TimeTap.tmbundle/Commands/Record current file.tmCommand +33 -0
- data/vendor/TextMate2/TimeTap.tmbundle/info.plist +16 -0
- data/vendor/TimeTap.tmbundle/Commands/Record current file.tmCommand +36 -0
- data/vendor/TimeTap.tmbundle/info.plist +18 -0
- metadata +161 -260
- data/Gemfile.lock +0 -48
- data/VERSION +0 -1
- data/config.yaml +0 -8
- data/lib/time_tap/editors.rb +0 -23
data/.gitignore
CHANGED
@@ -1,42 +1,10 @@
|
|
1
|
-
# rcov generated
|
2
1
|
coverage
|
3
|
-
|
4
|
-
# rdoc generated
|
5
2
|
rdoc
|
6
|
-
|
7
|
-
# yard generated
|
8
3
|
doc
|
9
4
|
.yardoc
|
10
|
-
|
11
|
-
|
5
|
+
pkg/*
|
6
|
+
*.gem
|
12
7
|
.bundle
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
18
|
-
#
|
19
|
-
# * Create a file at ~/.gitignore
|
20
|
-
# * Include files you want ignored
|
21
|
-
# * Run: git config --global core.excludesfile ~/.gitignore
|
22
|
-
#
|
23
|
-
# After doing this, these files will be ignored in all your git projects,
|
24
|
-
# saving you from having to 'pollute' every project you touch with them
|
25
|
-
#
|
26
|
-
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
27
|
-
#
|
28
|
-
# For MacOS:
|
29
|
-
#
|
30
|
-
#.DS_Store
|
31
|
-
#
|
32
|
-
# For TextMate
|
33
|
-
#*.tmproj
|
34
|
-
#tmtags
|
35
|
-
#
|
36
|
-
# For emacs:
|
37
|
-
#*~
|
38
|
-
#\#*
|
39
|
-
#.\#*
|
40
|
-
#
|
41
|
-
# For vim:
|
42
|
-
#*.swp
|
8
|
+
.sass*
|
9
|
+
/Gemfile.lock
|
10
|
+
/log/*.log
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3
|
data/Gemfile
CHANGED
@@ -1,22 +1,4 @@
|
|
1
|
-
source
|
1
|
+
source 'http://rubygems.org'
|
2
2
|
|
3
|
-
gem
|
4
|
-
|
5
|
-
gem 'i18n', '~> 0.3.5'
|
6
|
-
gem 'haml'
|
7
|
-
gem 'rb-appscript'
|
8
|
-
gem 'sinatra'
|
9
|
-
|
10
|
-
# Add dependencies required to use your gem here.
|
11
|
-
# Example:
|
12
|
-
# gem "activesupport", ">= 2.3.5"
|
13
|
-
|
14
|
-
# Add dependencies to develop your gem here.
|
15
|
-
# Include everything needed to run rake, tests, features, etc.
|
16
|
-
group :development do
|
17
|
-
gem "rspec", ">= 2.0.0.beta.19"
|
18
|
-
gem "yard", "~> 0.6.0"
|
19
|
-
gem "bundler", "~> 1.0.0"
|
20
|
-
gem "jeweler", "~> 1.5.0.pre3"
|
21
|
-
gem "rcov", ">= 0"
|
22
|
-
end
|
3
|
+
# Specify your gem's dependencies in time_tap.gemspec
|
4
|
+
gemspec
|
data/README.md
CHANGED
@@ -2,80 +2,122 @@
|
|
2
2
|
|
3
3
|
TimeTap helps you track the time you spend coding on each project while in TextMate.
|
4
4
|
|
5
|
-
Once it's launched you don't have to bother anymore starting/stopping timers or
|
5
|
+
Once it's launched you don't have to bother anymore starting/stopping timers or
|
6
6
|
inventing some arbitrary amount of time to fill your fancy time tracker.
|
7
7
|
|
8
8
|
<img src="http://f.cl.ly/items/17025fecf7189518cf07/timetap-project-list.png"/>
|
9
9
|
<img src="http://f.cl.ly/items/7b96ad2f7b49a95fdfd0/timetap-project-page.png"/>
|
10
10
|
|
11
11
|
|
12
|
-
## How does it work
|
13
12
|
|
14
|
-
|
15
|
-
and tells you how much time you spent on each project.
|
13
|
+
## Installing
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
gem install time_tap
|
16
|
+
|
17
|
+
timetap --install
|
18
|
+
|
19
|
+
… and visit [localhost:1111](http://localhost:1111/)
|
20
|
+
|
21
|
+
### Installing from source
|
22
|
+
|
23
|
+
- Get the codez: `git clone git://github.com/elia/timetap.git`
|
24
|
+
- Run `bundle exec bin/timetap --install`
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
## How it works
|
30
|
+
|
31
|
+
TimeTap keeps an eye on the modification time of the frontmost file in TextMate
|
32
|
+
and tells you how much time you spent on each project.
|
33
|
+
|
34
|
+
If you stop coding for a while while squeezing your brains TimeTap understands.
|
35
|
+
TimeTap will consider "coding time" pauses to up to 30 minutes between to saves
|
19
36
|
in the same project.
|
20
37
|
|
21
|
-
Technically it saves a timestamp+path of the frontmost file in TextMate every
|
38
|
+
Technically it saves a timestamp+path of the frontmost file in TextMate every
|
22
39
|
30 seconds, then it digests all this information in a nice Sinatra webapp.
|
23
40
|
|
24
41
|
The server will respond on http://0.0.0.0:1111/.
|
25
42
|
|
26
43
|
|
27
|
-
|
44
|
+
### Assumptions
|
45
|
+
|
46
|
+
* You code on TextMate.
|
47
|
+
* You save often (like me), at least every 30 minutes.
|
48
|
+
* You keep your code organized (I use ~/Code as main code folder).
|
49
|
+
|
50
|
+
|
51
|
+
## Editors
|
52
|
+
|
53
|
+
TimeTap works with TextMate, TextMate2 and SublimeText2.
|
54
|
+
For TM2 and ST2 you need to install specific bundles (in the `vendor/` folder).
|
55
|
+
|
56
|
+
### TextMate
|
57
|
+
|
58
|
+
Need to do nothing, thanks to `rb-appscript` :)
|
59
|
+
|
60
|
+
|
61
|
+
### TextMate 2
|
62
|
+
|
63
|
+
You need to install the bundle in [`vendor/SublimeText2`](https://github.com/elia/timetap/tree/master/vendor/TextMate2)
|
64
|
+
|
65
|
+
|
66
|
+
### SublimeText
|
67
|
+
|
68
|
+
You need to install the package in [`vendor/SublimeText2`](https://github.com/elia/timetap/tree/master/vendor/SublimeText2)
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
## Configuring
|
28
73
|
|
29
|
-
|
30
|
-
`rake launcher && launchctl load ~/Library/LaunchAgents`
|
31
|
-
to add a plist for OSX's launchd and have it launched automatically at login.
|
74
|
+
TimeTap uses a config file to control where projects are kept, etc. the path is:
|
32
75
|
|
33
|
-
|
76
|
+
~/.timetap.config
|
34
77
|
|
35
|
-
|
78
|
+
Which can look like this:
|
36
79
|
|
37
|
-
|
80
|
+
```yaml
|
81
|
+
port: 1111
|
82
|
+
# the port on localhost for the web interface
|
38
83
|
|
39
|
-
|
84
|
+
# These are used to identify project root folders
|
85
|
+
code_folders:
|
86
|
+
- ~/Code/MyCompany
|
87
|
+
- ~/Code
|
40
88
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
89
|
+
# It's highly recomended to use 1.9.3
|
90
|
+
ruby: /Users/elia/.rvm/bin/ruby-1.9.3-p286
|
91
|
+
```
|
45
92
|
|
46
|
-
Nested Projects allows you to keep your projects inside a hierarchy, instead of the original assumption of timetap (which is that all projects are flat).
|
47
93
|
|
48
|
-
|
94
|
+
|
95
|
+
### About "nested project layers"
|
96
|
+
|
97
|
+
TimeTap assumes you keep your projects inside a specific folder, like this:
|
98
|
+
|
99
|
+
~/Code/
|
100
|
+
tap/
|
101
|
+
tik_tak/
|
102
|
+
tk-win/
|
103
|
+
AcmeCorp/
|
104
|
+
website/
|
105
|
+
intranet/
|
106
|
+
|
107
|
+
But if you keep your projects grouped in subfolders like this:
|
49
108
|
|
50
109
|
~/Code/
|
51
110
|
Clients/
|
52
111
|
AcmeCorp/
|
53
112
|
website/
|
54
|
-
|
113
|
+
intranet/
|
55
114
|
BetaCorp/
|
56
115
|
skunkworks/
|
57
116
|
OpenSource/
|
58
117
|
project_one/
|
59
118
|
timetap/
|
60
119
|
|
61
|
-
|
62
|
-
|
63
|
-
## Assumptions
|
64
|
-
|
65
|
-
* You code on TextMate.
|
66
|
-
* You save often (like me), at least every 30 minutes.
|
67
|
-
* You keep your code organized (I use ~/Code as main code folder).
|
68
|
-
|
69
|
-
|
70
|
-
## TODO
|
71
|
-
|
72
|
-
- support other text editors, or at least make it easy to do so
|
73
|
-
- (r)spec it!
|
74
|
-
- make it more configurable
|
75
|
-
- gemify (with jeweler)
|
76
|
-
- flatten encoding quick-fixes with proper solutions (eat and spit only utf8)
|
77
|
-
- integration with external (online) time tracking tools
|
78
|
-
- export to csv (?)
|
120
|
+
then, the `nested_project_layers` key tells TimeTap how deep to look for project names inside a hierarchy (in the example a value of 2 will catch `AcmeCorp`, `BetaCorp`, `project_one` and `timetap`).
|
79
121
|
|
80
122
|
|
81
123
|
## How to Contribute
|
@@ -91,6 +133,27 @@ Use it, love it, then...
|
|
91
133
|
* Send me a pull request. Bonus points for topic branches.
|
92
134
|
|
93
135
|
|
136
|
+
### TODO
|
137
|
+
|
138
|
+
- <strike>make it more configurable</strike>
|
139
|
+
- <strike>gemify (with jeweler)</strike>
|
140
|
+
- <strike>support other text editors, or at least make it easy to do so</strike>
|
141
|
+
- (r)spec it!
|
142
|
+
- flatten encoding quick-fixes with proper solutions (eat and spit only utf8)
|
143
|
+
- integration with external (online) time tracking tools
|
144
|
+
|
145
|
+
|
146
|
+
## Credits
|
147
|
+
|
148
|
+
- Ryan Wilcox [@rwilcox](https://github.com/rwilcox)
|
149
|
+
|
150
|
+
|
151
|
+
## Related Projects
|
152
|
+
|
153
|
+
- [Watch Tower](https://github.com/TechnoGate/watch_tower)
|
154
|
+
- [Vim TimeTap](https://github.com/rainerborene/vim-timetap)
|
155
|
+
|
156
|
+
|
94
157
|
## Copyright
|
95
158
|
|
96
|
-
Copyright
|
159
|
+
Copyright © 2009-2012 Elia Schito. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,34 +1,5 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'bundler'
|
3
|
-
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'rake'
|
11
|
-
|
12
|
-
require 'jeweler'
|
13
|
-
Jeweler::Tasks.new do |gem|
|
14
|
-
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
-
gem.name = "time_tap"
|
16
|
-
gem.summary = %Q{Unobtrusive time tracking for TextMate}
|
17
|
-
gem.description = %Q{TimeTap helps you track the time you spend coding on each project while in TextMate.}
|
18
|
-
gem.email = "perlelia@gmail.com"
|
19
|
-
gem.homepage = "http://github.com/elia/timetap"
|
20
|
-
gem.authors = ["Elia Schito"]
|
21
|
-
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
22
|
-
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
23
|
-
# spec.add_runtime_dependency 'jabber4r', '> 0.1'
|
24
|
-
# spec.add_development_dependency 'rspec', '> 1.2.3'
|
25
|
-
gem.add_development_dependency "rspec", ">= 2.0.0.beta.19"
|
26
|
-
gem.add_development_dependency "yard", "~> 0.6.0"
|
27
|
-
gem.add_development_dependency "bundler", "~> 1.0.0"
|
28
|
-
gem.add_development_dependency "jeweler", "~> 1.5.0.pre3"
|
29
|
-
gem.add_development_dependency "rcov", ">= 0"
|
30
|
-
end
|
31
|
-
Jeweler::RubygemsDotOrgTasks.new
|
2
|
+
Bundler::GemHelper.install_tasks
|
32
3
|
|
33
4
|
require 'rspec/core'
|
34
5
|
require 'rspec/core/rake_task'
|
data/bin/timetap
CHANGED
@@ -4,52 +4,51 @@
|
|
4
4
|
require 'time_tap'
|
5
5
|
|
6
6
|
|
7
|
-
|
8
|
-
user_config = File.expand_path("~/.tap_config")
|
9
|
-
config_file = File.expand_path('../../config.yaml', __FILE__)
|
10
|
-
|
11
|
-
options = YAML.load_file(config_file)
|
12
|
-
options.merge! YAML.load_file(user_config) if File.exist?(user_config)
|
13
|
-
TimeTap.config = options
|
14
|
-
|
7
|
+
TimeTap.load_user_config!
|
15
8
|
|
16
9
|
require 'optparse'
|
17
10
|
OptionParser.new do |opts|
|
18
11
|
opts.banner = "Usage: #{$0} [options]"
|
19
12
|
|
20
|
-
opts.on("-f", "--foreground", "Run in foreground.") do
|
21
|
-
TimeTap.config[:
|
13
|
+
opts.on("-f", "--foreground", "Run in foreground (default).") do
|
14
|
+
TimeTap.config[:background] = false
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on("-b", "--background", "Run in background.") do
|
18
|
+
TimeTap.config[:background] = true
|
22
19
|
end
|
23
|
-
|
24
|
-
opts.on("-p", "--port PORT", "Use specified port for server. (default #{
|
20
|
+
|
21
|
+
opts.on("-p", "--port PORT", "Use specified port for server. (default #{TimeTap.config['port']})") do |value|
|
25
22
|
TimeTap.config[:port] = value
|
26
23
|
end
|
27
|
-
|
28
|
-
opts.on("--
|
29
|
-
TimeTap.
|
30
|
-
puts "\nInstalled. Now run:\n launchctl load ~/Library/LaunchAgents\n\n"
|
31
|
-
exit
|
24
|
+
|
25
|
+
opts.on("-l", "--log-level LEVEL", "Use specified port for server. (default #{TimeTap.config['port']})") do |value|
|
26
|
+
TimeTap.config[:log_level] = value
|
32
27
|
end
|
33
|
-
|
34
|
-
opts.on("--
|
35
|
-
|
36
|
-
TimeTap.
|
28
|
+
|
29
|
+
opts.on("-i", "--install", "Sets TimeTap to be launched automatically at login, and boots it.") do
|
30
|
+
TimeTap.install_launcher!
|
31
|
+
TimeTap.install_config!
|
32
|
+
TimeTap.reload_launcher!
|
33
|
+
# TimeTap::reload_launcher! uses `exec` so it never gets here
|
37
34
|
exit
|
38
35
|
end
|
39
36
|
end.parse!
|
40
37
|
|
41
|
-
|
42
|
-
|
38
|
+
TimeTap.config[:foreground] = !TimeTap.config[:background]
|
39
|
+
if TimeTap.config[:background]
|
43
40
|
require 'time_tap/daemon'
|
44
|
-
|
41
|
+
|
45
42
|
pid = fork {
|
46
43
|
# Try to replace "ruby" with "TimeTap" in the command string (for "ps -A" & co.)
|
47
44
|
$0 = 'TimeTap'
|
48
|
-
|
45
|
+
|
49
46
|
Process.daemon(true)
|
50
47
|
TimeTap.start
|
51
48
|
}
|
52
49
|
else
|
53
|
-
|
50
|
+
TimeTap.logger = Logger.new($stdout)
|
51
|
+
TimeTap.logger.level = Logger.const_get(TimeTap.config[:log_level].upcase) if TimeTap.config[:log_level]
|
52
|
+
TimeTap.logger.info '[TimeTap] Going foreground...'
|
54
53
|
TimeTap.start
|
55
54
|
end
|
data/lib/time_tap.rb
CHANGED
@@ -1,81 +1,123 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'logger'
|
3
3
|
|
4
|
+
module TimeTap
|
5
|
+
@config = {
|
6
|
+
:root => "~",
|
7
|
+
# root is where the logs will be saved
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
# code is where all your projects live
|
10
|
+
:code_folders => %w[
|
11
|
+
~/Code
|
12
|
+
~/Developer
|
13
|
+
~/Development
|
14
|
+
~/src
|
15
|
+
~/code
|
16
|
+
~/rails
|
17
|
+
~/Desktop
|
18
|
+
~
|
19
|
+
],
|
12
20
|
|
21
|
+
:nested_project_layers => 1,
|
22
|
+
# see below about nested projects
|
13
23
|
|
14
|
-
|
24
|
+
:port => 1111,
|
25
|
+
# the port on localhost for the web interface
|
26
|
+
|
27
|
+
:ruby => '/usr/bin/ruby',
|
28
|
+
# the ruby you want to use
|
29
|
+
|
30
|
+
:backend => :file_system,
|
31
|
+
:backend_options => { :file_name => '~/.timetap.history' },
|
32
|
+
:editor => :text_mate,
|
33
|
+
:log_file => '~/.timetap.log'
|
34
|
+
}.with_indifferent_access
|
15
35
|
attr_accessor :config
|
16
|
-
|
36
|
+
|
37
|
+
|
38
|
+
@logger = Logger.new($stdout)
|
39
|
+
attr_accessor :logger
|
40
|
+
|
41
|
+
|
17
42
|
extend self
|
18
|
-
|
19
|
-
|
43
|
+
|
44
|
+
|
20
45
|
# CONFIGURATION
|
21
46
|
|
22
47
|
# Are we on 1.9?
|
23
48
|
# FIXME: this is wrong! :)
|
24
49
|
RUBY19 = RUBY_VERSION.to_f >= 1.9
|
25
|
-
|
50
|
+
|
26
51
|
def config= options = {}
|
27
52
|
require 'active_support'
|
28
|
-
|
53
|
+
|
29
54
|
# CONFIG
|
30
55
|
@config = HashWithIndifferentAccess.new(options)
|
31
56
|
@config[:root] = File.expand_path(config[:root])
|
32
57
|
@config[:port] = config[:port].to_i
|
33
58
|
end
|
34
|
-
|
35
|
-
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
# BACKEND
|
63
|
+
|
64
|
+
def backend
|
65
|
+
require 'time_tap/backend'
|
66
|
+
@backend = Backend.load config[:backend], config[:backend_options]
|
67
|
+
end
|
68
|
+
|
69
|
+
def editor
|
70
|
+
require 'time_tap/editor'
|
71
|
+
@backend = Editor.load config[:editor], config[:editor_options]
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# START
|
76
|
+
|
36
77
|
def start options = {}
|
37
78
|
# REQUIREMENTS
|
38
|
-
|
79
|
+
|
39
80
|
require 'yaml'
|
40
|
-
require 'active_support'
|
41
81
|
require 'time_tap/project'
|
42
|
-
require 'time_tap/editors'
|
43
82
|
require 'time_tap/watcher'
|
44
83
|
require 'time_tap/server'
|
45
|
-
|
46
|
-
|
47
|
-
|
84
|
+
|
85
|
+
logger.info "[TimeTap] config: #{config.to_yaml}"
|
48
86
|
# SIGNAL HANDLING
|
49
|
-
|
50
|
-
Signal.trap(
|
51
|
-
Signal.trap(
|
52
|
-
|
53
|
-
|
87
|
+
|
88
|
+
Signal.trap('INT') {exit}
|
89
|
+
Signal.trap('TERM') {exit}
|
90
|
+
|
91
|
+
|
54
92
|
# WEB SERVER
|
55
|
-
|
93
|
+
|
56
94
|
Thread.abort_on_exception = true
|
57
|
-
|
95
|
+
|
58
96
|
@server = Thread.new {
|
59
97
|
Signal.trap("INT") {exit}
|
60
98
|
Signal.trap("TERM") {exit}
|
61
|
-
|
99
|
+
|
62
100
|
Server.run! :host => 'localhost', :port => TimeTap.config[:port]
|
63
101
|
exit
|
64
102
|
}
|
65
|
-
|
66
|
-
|
103
|
+
|
104
|
+
|
67
105
|
# WATCHER
|
68
|
-
|
69
|
-
|
70
|
-
|
106
|
+
|
107
|
+
watcher = Watcher.new(editor, backend)
|
108
|
+
watcher.keep_watching
|
71
109
|
end
|
72
|
-
|
110
|
+
|
111
|
+
|
73
112
|
# Add a plist for OSX's launchd and have *TimeTap* launched automatically at login.
|
74
|
-
def
|
113
|
+
def install_launcher!
|
114
|
+
puts 'Installing launcher...'
|
115
|
+
|
75
116
|
load_plist_info!
|
76
117
|
ruby = config[:ruby] || "/usr/bin/ruby"
|
77
118
|
include_dir = '-I'+File.expand_path('../../lib', __FILE__)
|
78
119
|
launcher = File.expand_path('../../bin/timetap', __FILE__)
|
120
|
+
working_directory = File.expand_path('../../', __FILE__)
|
79
121
|
|
80
122
|
puts "\nCreating launchd plist in\n #{plist_path}"
|
81
123
|
|
@@ -88,17 +130,25 @@ module TimeTap
|
|
88
130
|
<key>Label</key>
|
89
131
|
<string>com.eliaesocietas.TimeTap</string>
|
90
132
|
|
91
|
-
<key>Program</key>
|
92
|
-
<string>#{ruby}</string>
|
93
|
-
|
94
133
|
<key>ProgramArguments</key>
|
95
134
|
<array>
|
96
135
|
<string>#{ruby}</string>
|
97
136
|
<string>#{include_dir}</string>
|
137
|
+
<string>-S</string>
|
138
|
+
<string>bundle</string>
|
139
|
+
<string>exec</string>
|
98
140
|
<string>#{launcher}</string>
|
99
141
|
<string>-f</string>
|
100
142
|
</array>
|
101
143
|
|
144
|
+
|
145
|
+
<key>WorkingDirectory</key>
|
146
|
+
<string>#{working_directory}</string>
|
147
|
+
<key>StandardErrorPath</key>
|
148
|
+
<string>/usr/local/var/log/timetap.log</string>
|
149
|
+
<key>StandardOutPath</key>
|
150
|
+
<string>/usr/local/var/log/timetap.log</string>
|
151
|
+
|
102
152
|
<key>OnDemand</key>
|
103
153
|
<false/>
|
104
154
|
|
@@ -109,20 +159,44 @@ module TimeTap
|
|
109
159
|
PLIST
|
110
160
|
end
|
111
161
|
end
|
112
|
-
|
113
|
-
def
|
162
|
+
|
163
|
+
def reload_launcher!
|
164
|
+
puts 'Reloading system launcher...'
|
165
|
+
|
114
166
|
load_plist_info!
|
115
167
|
command = "launchctl unload #{plist_path}; launchctl load #{plist_path}"
|
116
168
|
exec command
|
117
169
|
end
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
170
|
+
|
171
|
+
def load_user_config!
|
172
|
+
require 'yaml'
|
173
|
+
TimeTap.config.merge! YAML.load_file(user_config) if File.exist?(user_config)
|
174
|
+
end
|
175
|
+
|
176
|
+
def user_config
|
177
|
+
@user_config ||= File.expand_path('~/.timetap.config')
|
178
|
+
end
|
179
|
+
|
180
|
+
def install_config!
|
181
|
+
puts 'Checking config...'
|
182
|
+
unless File.exist? user_config
|
183
|
+
require 'fileutils'
|
184
|
+
example_config = File.expand_path('../time_tap/config.yml.example', __FILE__)
|
185
|
+
FileUtils.copy example_config, user_config
|
186
|
+
puts "Added default config to #{user_config}"
|
126
187
|
end
|
127
|
-
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
attr_reader :plist_path, :plist_name
|
196
|
+
|
197
|
+
def load_plist_info!
|
198
|
+
@plist_name ||= "com.eliaesocietas.TimeTap.plist"
|
199
|
+
@plist_path ||= File.expand_path("~/Library/LaunchAgents/#{plist_name}")
|
200
|
+
end
|
201
|
+
|
128
202
|
end
|