watch_tower 0.0.0.1 → 0.0.1.beta1
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.
- data/.todo +3 -0
- data/.travis.yml +4 -0
- data/Gemfile +0 -4
- data/README.md +48 -2
- data/TODO +3 -0
- data/ci/travis.rb +4 -1
- data/lib/watch_tower/appscript.rb +65 -7
- data/lib/watch_tower/cli/install.rb +27 -3
- data/lib/watch_tower/cli/open.rb +2 -0
- data/lib/watch_tower/cli/start.rb +3 -1
- data/lib/watch_tower/cli.rb +2 -0
- data/lib/watch_tower/config.rb +2 -0
- data/lib/watch_tower/core_ext.rb +2 -0
- data/lib/watch_tower/editor/base_appscript.rb +28 -1
- data/lib/watch_tower/editor/base_ps.rb +25 -0
- data/lib/watch_tower/editor/textmate.rb +2 -0
- data/lib/watch_tower/editor/xcode.rb +2 -0
- data/lib/watch_tower/editor.rb +2 -0
- data/lib/watch_tower/errors.rb +2 -0
- data/lib/watch_tower/eye.rb +13 -2
- data/lib/watch_tower/file_tree.rb +78 -0
- data/lib/watch_tower/project/any_based.rb +2 -0
- data/lib/watch_tower/project/git_based.rb +2 -0
- data/lib/watch_tower/project/init.rb +2 -0
- data/lib/watch_tower/project/path_based.rb +2 -0
- data/lib/watch_tower/project.rb +2 -0
- data/lib/watch_tower/server/app.rb +37 -7
- data/lib/watch_tower/server/assets/javascripts/application.js +4 -0
- data/lib/watch_tower/server/assets/javascripts/datepicker.coffee +21 -0
- data/lib/watch_tower/server/assets/javascripts/file_tree.coffee +30 -0
- data/lib/watch_tower/server/assets/javascripts/percentage.coffee +15 -5
- data/lib/watch_tower/server/assets/stylesheets/application.css +1 -0
- data/lib/watch_tower/server/assets/stylesheets/date.sass +17 -0
- data/lib/watch_tower/server/assets/stylesheets/file_tree.sass +42 -0
- data/lib/watch_tower/server/assets/stylesheets/global.sass +7 -4
- data/lib/watch_tower/server/configurations/asset.rb +2 -0
- data/lib/watch_tower/server/configurations.rb +2 -0
- data/lib/watch_tower/server/database.rb +2 -0
- data/lib/watch_tower/server/db/migrate/001_create_projects.rb +2 -0
- data/lib/watch_tower/server/db/migrate/002_create_files.rb +2 -0
- data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +2 -0
- data/lib/watch_tower/server/db/migrate/004_create_durations.rb +2 -0
- data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +2 -0
- data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +2 -0
- data/lib/watch_tower/server/db/migrate/007_add_editor_to_times_entries.rb +8 -0
- data/lib/watch_tower/server/db/migrate/008_rename_editor_to_editor_name_in_times_entries.rb +5 -0
- data/lib/watch_tower/server/db/migrate/009_remove_editor_index_from_time_entries.rb +7 -0
- data/lib/watch_tower/server/db/migrate/010_add_editor_version_to_times_entries.rb +7 -0
- data/lib/watch_tower/server/helpers/asset.rb +2 -0
- data/lib/watch_tower/server/helpers/improved_partials.rb +2 -0
- data/lib/watch_tower/server/helpers/presenters.rb +33 -0
- data/lib/watch_tower/server/helpers.rb +3 -0
- data/lib/watch_tower/server/models/duration.rb +9 -0
- data/lib/watch_tower/server/models/file.rb +17 -0
- data/lib/watch_tower/server/models/project.rb +30 -0
- data/lib/watch_tower/server/models/time_entry.rb +5 -0
- data/lib/watch_tower/server/presenters/application_presenter.rb +165 -0
- data/lib/watch_tower/server/presenters/file_presenter.rb +10 -0
- data/lib/watch_tower/server/presenters/project_presenter.rb +20 -0
- data/lib/watch_tower/server/presenters.rb +13 -0
- data/lib/watch_tower/server/public/assets/{WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg → WatchTower-58eff0713efffbc6054defddc879e0b1.jpg} +0 -0
- data/lib/watch_tower/server/public/assets/application-4e6971066e06aa53b0c8e52c764044d1.css +389 -0
- data/lib/watch_tower/server/public/assets/application-6a1be75d4fd6a545faceb638e47a2486.js +23778 -0
- data/lib/watch_tower/server/public/assets/calendar-379834cd6e6321a940b662ace47f3032.gif +0 -0
- data/lib/watch_tower/server/public/assets/calendar-blue-d6aa74feef7ee4287532761db99a6c0a.gif +0 -0
- data/lib/watch_tower/server/public/assets/calendar-green-3752fe2996091379c8d321f759039385.gif +0 -0
- data/lib/watch_tower/server/public/assets/jquery.datepick-9c8dfe3a4d40bcafc7b182e194c13836.css +227 -0
- data/lib/watch_tower/server/public/assets/{percentage-d8589e21a5fc85d32a445f531ff8ab95.png → percentage-d0176e99520c95e93eee63738ef5d487.png} +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar-blue.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar-green.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/images/calendar.gif +0 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-ext.js +266 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-validation.js +232 -0
- data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick.js +2092 -0
- data/lib/watch_tower/server/vendor/assets/stylesheets/jquery.datepick.css +226 -0
- data/lib/watch_tower/server/views/_project.haml +10 -13
- data/lib/watch_tower/server/views/index.haml +9 -6
- data/lib/watch_tower/server/views/layout.haml +7 -4
- data/lib/watch_tower/server/views/project.haml +9 -11
- data/lib/watch_tower/server.rb +8 -1
- data/lib/watch_tower/templates/{watchtower.plist → watchtower.plist.erb} +5 -6
- data/lib/watch_tower/version.rb +12 -3
- data/lib/watch_tower.rb +20 -1
- data/spec/factories.rb +2 -0
- data/spec/watch_tower/appscript_spec.rb +36 -2
- data/spec/watch_tower/editor/base_appscript_spec.rb +83 -0
- data/spec/watch_tower/editor/textmate_spec.rb +37 -0
- data/spec/watch_tower/editor/xcode_spec.rb +6 -0
- data/spec/watch_tower/eye_spec.rb +21 -0
- data/spec/watch_tower/file_tree_spec.rb +156 -0
- data/spec/watch_tower/server/app_spec.rb +64 -20
- data/spec/watch_tower/server/models/file_spec.rb +93 -31
- data/spec/watch_tower/server/models/project_spec.rb +147 -18
- data/spec/watch_tower/server/models/time_entry_spec.rb +10 -0
- data/spec/watch_tower/server/{decorator/project_decorator_spec.rb → presenters/application_presenter_spec.rb} +24 -13
- data/spec/watch_tower/server/presenters/file_presenter_spec.rb +8 -0
- data/spec/watch_tower/server/presenters/project_presenter_spec.rb +130 -0
- data/watch_tower.gemspec +10 -4
- metadata +114 -74
- data/lib/watch_tower/server/decorator/application_decorator.rb +0 -91
- data/lib/watch_tower/server/decorator/file_decorator.rb +0 -38
- data/lib/watch_tower/server/decorator/project_decorator.rb +0 -51
- data/lib/watch_tower/server/decorator.rb +0 -21
- data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +0 -107
- data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +0 -9359
- data/lib/watch_tower/server/views/_file.haml +0 -9
@@ -0,0 +1,226 @@
|
|
1
|
+
/* Default styling for jQuery Datepicker v4.0.6. */
|
2
|
+
.datepick {
|
3
|
+
background-color: #fff;
|
4
|
+
color: #000;
|
5
|
+
border: 1px solid #444;
|
6
|
+
border-radius: 0.25em;
|
7
|
+
-moz-border-radius: 0.25em;
|
8
|
+
-webkit-border-radius: 0.25em;
|
9
|
+
font-family: Arial,Helvetica,Sans-serif;
|
10
|
+
font-size: 90%;
|
11
|
+
}
|
12
|
+
.datepick-rtl {
|
13
|
+
direction: rtl;
|
14
|
+
}
|
15
|
+
.datepick-popup {
|
16
|
+
z-index: 1000;
|
17
|
+
}
|
18
|
+
.datepick-disable {
|
19
|
+
position: absolute;
|
20
|
+
z-index: 100;
|
21
|
+
background-color: white;
|
22
|
+
opacity: 0.5;
|
23
|
+
filter: alpha(opacity=50);
|
24
|
+
}
|
25
|
+
.datepick a {
|
26
|
+
color: #fff;
|
27
|
+
text-decoration: none;
|
28
|
+
}
|
29
|
+
.datepick a.datepick-disabled {
|
30
|
+
color: #888;
|
31
|
+
cursor: auto;
|
32
|
+
}
|
33
|
+
.datepick button {
|
34
|
+
margin: 0.25em;
|
35
|
+
padding: 0.125em 0em;
|
36
|
+
background-color: #fcc;
|
37
|
+
border: none;
|
38
|
+
border-radius: 0.25em;
|
39
|
+
-moz-border-radius: 0.25em;
|
40
|
+
-webkit-border-radius: 0.25em;
|
41
|
+
font-weight: bold;
|
42
|
+
}
|
43
|
+
.datepick-nav, .datepick-ctrl {
|
44
|
+
float: left;
|
45
|
+
width: 100%;
|
46
|
+
background-color: #000;
|
47
|
+
color: #fff;
|
48
|
+
font-size: 90%;
|
49
|
+
font-weight: bold;
|
50
|
+
}
|
51
|
+
.datepick-ctrl {
|
52
|
+
background-color: #600;
|
53
|
+
}
|
54
|
+
.datepick-cmd {
|
55
|
+
width: 30%;
|
56
|
+
}
|
57
|
+
.datepick-cmd:hover {
|
58
|
+
background-color: #777;
|
59
|
+
}
|
60
|
+
.datepick-ctrl .datepick-cmd:hover {
|
61
|
+
background-color: #f08080;
|
62
|
+
}
|
63
|
+
.datepick-cmd-prevJump, .datepick-cmd-nextJump {
|
64
|
+
width: 8%;
|
65
|
+
}
|
66
|
+
a.datepick-cmd {
|
67
|
+
height: 1.5em;
|
68
|
+
}
|
69
|
+
button.datepick-cmd {
|
70
|
+
text-align: center;
|
71
|
+
}
|
72
|
+
.datepick-cmd-prev, .datepick-cmd-prevJump, .datepick-cmd-clear {
|
73
|
+
float: left;
|
74
|
+
padding-left: 2%;
|
75
|
+
}
|
76
|
+
.datepick-cmd-current, .datepick-cmd-today {
|
77
|
+
float: left;
|
78
|
+
width: 35%;
|
79
|
+
text-align: center;
|
80
|
+
}
|
81
|
+
.datepick-cmd-next, .datepick-cmd-nextJump, .datepick-cmd-close {
|
82
|
+
float: right;
|
83
|
+
padding-right: 2%;
|
84
|
+
text-align: right;
|
85
|
+
}
|
86
|
+
.datepick-rtl .datepick-cmd-prev, .datepick-rtl .datepick-cmd-prevJump,
|
87
|
+
.datepick-rtl .datepick-cmd-clear {
|
88
|
+
float: right;
|
89
|
+
padding-left: 0%;
|
90
|
+
padding-right: 2%;
|
91
|
+
text-align: right;
|
92
|
+
}
|
93
|
+
.datepick-rtl .datepick-cmd-current, .datepick-rtl .datepick-cmd-today {
|
94
|
+
float: right;
|
95
|
+
}
|
96
|
+
.datepick-rtl .datepick-cmd-next, .datepick-rtl .datepick-cmd-nextJump,
|
97
|
+
.datepick-rtl .datepick-cmd-close {
|
98
|
+
float: left;
|
99
|
+
padding-left: 2%;
|
100
|
+
padding-right: 0%;
|
101
|
+
text-align: left;
|
102
|
+
}
|
103
|
+
.datepick-month-nav {
|
104
|
+
float: left;
|
105
|
+
background-color: #777;
|
106
|
+
text-align: center;
|
107
|
+
}
|
108
|
+
.datepick-month-nav div {
|
109
|
+
float: left;
|
110
|
+
width: 12.5%;
|
111
|
+
margin: 1%;
|
112
|
+
padding: 1%;
|
113
|
+
}
|
114
|
+
.datepick-month-nav span {
|
115
|
+
color: #888;
|
116
|
+
}
|
117
|
+
.datepick-month-row {
|
118
|
+
clear: left;
|
119
|
+
}
|
120
|
+
.datepick-month {
|
121
|
+
float: left;
|
122
|
+
width: 15em;
|
123
|
+
border: 1px solid #444;
|
124
|
+
text-align: center;
|
125
|
+
}
|
126
|
+
.datepick-month-header, .datepick-month-header select, .datepick-month-header input {
|
127
|
+
height: 1.5em;
|
128
|
+
background-color: #444;
|
129
|
+
color: #fff;
|
130
|
+
font-weight: bold;
|
131
|
+
}
|
132
|
+
.datepick-month-header select, .datepick-month-header input {
|
133
|
+
height: 1.4em;
|
134
|
+
border: none;
|
135
|
+
}
|
136
|
+
.datepick-month-header input {
|
137
|
+
position: absolute;
|
138
|
+
display: none;
|
139
|
+
}
|
140
|
+
.datepick-month table {
|
141
|
+
width: 100%;
|
142
|
+
border-collapse: collapse;
|
143
|
+
}
|
144
|
+
.datepick-month thead {
|
145
|
+
border-bottom: 1px solid #aaa;
|
146
|
+
}
|
147
|
+
.datepick-month th, .datepick-month td {
|
148
|
+
margin: 0em;
|
149
|
+
padding: 0em;
|
150
|
+
font-weight: normal;
|
151
|
+
text-align: center;
|
152
|
+
}
|
153
|
+
.datepick-month th {
|
154
|
+
border: 1px solid #777;
|
155
|
+
}
|
156
|
+
.datepick-month th, .datepick-month th a {
|
157
|
+
background-color: #777;
|
158
|
+
color: #fff;
|
159
|
+
}
|
160
|
+
.datepick-month td {
|
161
|
+
background-color: #eee;
|
162
|
+
border: 1px solid #aaa;
|
163
|
+
}
|
164
|
+
.datepick-month td.datepick-week {
|
165
|
+
border: 1px solid #777;
|
166
|
+
}
|
167
|
+
.datepick-month td.datepick-week * {
|
168
|
+
background-color: #777;
|
169
|
+
color: #fff;
|
170
|
+
border: none;
|
171
|
+
}
|
172
|
+
.datepick-month a {
|
173
|
+
display: block;
|
174
|
+
width: 100%;
|
175
|
+
padding: 0.125em 0em;
|
176
|
+
background-color: #eee;
|
177
|
+
color: #000;
|
178
|
+
text-decoration: none;
|
179
|
+
}
|
180
|
+
.datepick-month span {
|
181
|
+
display: block;
|
182
|
+
width: 100%;
|
183
|
+
padding: 0.125em 0em;
|
184
|
+
}
|
185
|
+
.datepick-month td span {
|
186
|
+
color: #888;
|
187
|
+
}
|
188
|
+
.datepick-month td .datepick-other-month {
|
189
|
+
background-color: #fff;
|
190
|
+
}
|
191
|
+
.datepick-month td .datepick-weekend {
|
192
|
+
background-color: #ddd;
|
193
|
+
}
|
194
|
+
.datepick-month td .datepick-today {
|
195
|
+
background-color: #f0c0c0;
|
196
|
+
}
|
197
|
+
.datepick-month td .datepick-highlight {
|
198
|
+
background-color: #f08080;
|
199
|
+
}
|
200
|
+
.datepick-month td .datepick-selected {
|
201
|
+
background-color: #777;
|
202
|
+
color: #fff;
|
203
|
+
}
|
204
|
+
.datepick-month th.datepick-week {
|
205
|
+
background-color: #777;
|
206
|
+
color: #fff;
|
207
|
+
}
|
208
|
+
.datepick-status {
|
209
|
+
clear: both;
|
210
|
+
background-color: #ddd;
|
211
|
+
text-align: center;
|
212
|
+
}
|
213
|
+
.datepick-clear-fix {
|
214
|
+
clear: both;
|
215
|
+
}
|
216
|
+
.datepick-cover {
|
217
|
+
display: none;
|
218
|
+
display/**/: block;
|
219
|
+
position: absolute;
|
220
|
+
z-index: -1;
|
221
|
+
filter: mask();
|
222
|
+
top: -1px;
|
223
|
+
left: -1px;
|
224
|
+
width: 100px;
|
225
|
+
height: 100px;
|
226
|
+
}
|
@@ -1,13 +1,10 @@
|
|
1
|
-
|
2
|
-
.
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
.
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
%img.percentage_img{src: asset_path('percentage.png'), 'data-width' => percentage}/
|
12
|
-
.elapsed= project.elapsed
|
13
|
-
.clearfix
|
1
|
+
- present project do |presenter|
|
2
|
+
%article.project[project]
|
3
|
+
.name
|
4
|
+
%a{href: path_to(:project).with(presenter.id), alt: presenter.path}
|
5
|
+
= presenter.name.camelcase
|
6
|
+
.percentage_img_container
|
7
|
+
.percentage
|
8
|
+
%img.percentage_img{src: asset_path('percentage.png'), alt: "#{presenter.percent}% of total time", 'data-width' => presenter.percent}/
|
9
|
+
.elapsed= presenter.elapsed(project.durations.date_range(session[:date_filtering][:from_date], session[:date_filtering][:to_date]).sum(:duration))
|
10
|
+
.clearfix
|
@@ -1,7 +1,10 @@
|
|
1
1
|
%section#projects
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
- if @projects.any?
|
3
|
+
%header
|
4
|
+
.name Project
|
5
|
+
.percentage Percentage
|
6
|
+
.elapsed Total time
|
7
|
+
.clearfix
|
8
|
+
= partial('project', collection: @projects)
|
9
|
+
- else
|
10
|
+
No projects available for the selected date range.
|
@@ -8,6 +8,8 @@
|
|
8
8
|
%meta{:charset => "utf-8"}/
|
9
9
|
%meta{:content => "IE=edge,chrome=1", "http-equiv" => "X-UA-Compatible"}/
|
10
10
|
%meta{:content => "width=device-width,initial-scale=1", :name => "viewport"}/
|
11
|
+
%meta{name: 'date_filtering_from', content: session[:date_filtering][:from_date] }/
|
12
|
+
%meta{name: 'date_filtering_to', content: session[:date_filtering][:to_date]}/
|
11
13
|
|
12
14
|
/ Link tags
|
13
15
|
%link{:href => asset_path('application.css'), :rel => "stylesheet"}/
|
@@ -23,10 +25,11 @@
|
|
23
25
|
%h1 Watch Tower
|
24
26
|
|
25
27
|
%section#main
|
26
|
-
|
28
|
+
%aside#date
|
29
|
+
%input{type: 'text'}
|
30
|
+
.page= yield
|
27
31
|
|
28
32
|
%section#footer
|
29
|
-
|
30
|
-
|
31
|
-
%a{href: 'http://www.technogate.fr'}
|
33
|
+
© Copyright 2011
|
34
|
+
%a{href: 'https://github.com/TechnoGate', target: '_blank'}
|
32
35
|
TechnoGate
|
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
%
|
3
|
-
%h1.project_name= @project.name.camelcase
|
4
|
-
%h2.project_path= @project.path
|
5
|
-
%section#files
|
1
|
+
- present @project do |presenter|
|
2
|
+
%article#project
|
6
3
|
%header
|
7
|
-
.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
4
|
+
%h1.project_name= presenter.name.camelcase
|
5
|
+
%h2.project_path= presenter.path
|
6
|
+
%section#files
|
7
|
+
- if @files.any?
|
8
|
+
= presenter.file_tree(@files)
|
9
|
+
- else
|
10
|
+
No files available for the selected date range.
|
data/lib/watch_tower/server.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
module WatchTower
|
2
4
|
module Server
|
3
5
|
extend ::ActiveSupport::Autoload
|
@@ -9,7 +11,7 @@ module WatchTower
|
|
9
11
|
autoload :TimeEntry, ::File.join(MODELS_PATH, 'time_entry.rb')
|
10
12
|
autoload :Helpers
|
11
13
|
autoload :Configurations
|
12
|
-
autoload :
|
14
|
+
autoload :Presenters
|
13
15
|
autoload :App
|
14
16
|
|
15
17
|
# Start the server
|
@@ -45,6 +47,10 @@ module WatchTower
|
|
45
47
|
WatchTower.threads[:web_server] = Thread.new do
|
46
48
|
LOG.debug("#{__FILE__}:#{__LINE__}: Starting a new Thread for the web server.")
|
47
49
|
|
50
|
+
# Signal handling
|
51
|
+
Signal.trap("INT") { exit }
|
52
|
+
Signal.trap("TERM") { exit }
|
53
|
+
|
48
54
|
begin
|
49
55
|
LOG.debug("#{__FILE__}:#{__LINE__}: Starting the web server in the new Thread.")
|
50
56
|
|
@@ -52,6 +58,7 @@ module WatchTower
|
|
52
58
|
App.run!(options)
|
53
59
|
|
54
60
|
LOG.debug("#{__FILE__}:#{__LINE__}: The server has stopped.")
|
61
|
+
exit
|
55
62
|
rescue Exception => e
|
56
63
|
LOG.fatal "#{__FILE__}:#{__LINE__ - 4}: #{e}"
|
57
64
|
raise e
|
@@ -4,19 +4,18 @@
|
|
4
4
|
<dict>
|
5
5
|
<key>Label</key>
|
6
6
|
<string>fr.technogate.WatchTower</string>
|
7
|
-
|
8
|
-
<key>Program</key>
|
9
|
-
<string>watchtower</string>
|
10
|
-
|
11
7
|
<key>ProgramArguments</key>
|
12
8
|
<array>
|
9
|
+
<string><%= ruby_binary %></string>
|
10
|
+
<string><%= watch_tower_binary %></string>
|
13
11
|
<string>start</string>
|
14
12
|
<string>--bootloader</string>
|
13
|
+
<string>--foreground</string>
|
15
14
|
</array>
|
16
|
-
|
15
|
+
<key>KeepAlive</key>
|
16
|
+
<true/>
|
17
17
|
<key>OnDemand</key>
|
18
18
|
<false/>
|
19
|
-
|
20
19
|
<key>RunAtLoad</key>
|
21
20
|
<true/>
|
22
21
|
</dict>
|
data/lib/watch_tower/version.rb
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
module WatchTower
|
2
4
|
MAJOR = 0
|
3
5
|
MINOR = 0
|
4
|
-
|
5
|
-
PRE =
|
6
|
+
TINY = 1
|
7
|
+
PRE = "beta1"
|
6
8
|
|
7
|
-
|
9
|
+
def self.version
|
10
|
+
# Init the version
|
11
|
+
version = [MAJOR, MINOR, TINY]
|
12
|
+
# Add the pre if available
|
13
|
+
version << PRE unless PRE.nil? || PRE !~ /\S/
|
14
|
+
# Return the version joined by a dot
|
15
|
+
version.join('.')
|
16
|
+
end
|
8
17
|
end
|
data/lib/watch_tower.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
# RubyGems is needed at first
|
2
4
|
require 'rubygems'
|
3
5
|
|
@@ -33,7 +35,7 @@ FileUtils.mkdir_p LOG_PATH
|
|
33
35
|
module WatchTower
|
34
36
|
|
35
37
|
# Create a logger
|
36
|
-
LOG = Logger.new(File.join(LOG_PATH, '
|
38
|
+
LOG = Logger.new(File.join(LOG_PATH, "#{ENV['WATCH_TOWER_ENV']}.log"))
|
37
39
|
|
38
40
|
# Threads
|
39
41
|
# Hash
|
@@ -46,8 +48,24 @@ module WatchTower
|
|
46
48
|
@@threads
|
47
49
|
end
|
48
50
|
|
51
|
+
# Get WatchTower's environment
|
52
|
+
#
|
53
|
+
# @return [String] The current environment
|
54
|
+
def self.env
|
55
|
+
ENV['WATCH_TOWER_ENV']
|
56
|
+
end
|
57
|
+
|
58
|
+
# Set WatchTower's environment
|
59
|
+
#
|
60
|
+
# @param [String] The environment
|
61
|
+
def self.env=(environment)
|
62
|
+
ENV['WATCH_TOWER_ENV'] = environment
|
63
|
+
end
|
49
64
|
end
|
50
65
|
|
66
|
+
# Make sure we are running UTF-8
|
67
|
+
Encoding.default_external = 'utf-8'
|
68
|
+
|
51
69
|
# Require watch_tower's libraries
|
52
70
|
require "watch_tower/version"
|
53
71
|
require "watch_tower/errors"
|
@@ -57,4 +75,5 @@ require "watch_tower/cli"
|
|
57
75
|
require "watch_tower/editor"
|
58
76
|
require "watch_tower/project"
|
59
77
|
require "watch_tower/eye"
|
78
|
+
require "watch_tower/file_tree"
|
60
79
|
require "watch_tower/server"
|
data/spec/factories.rb
CHANGED
@@ -1,6 +1,40 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'watch_tower/appscript'
|
3
3
|
|
4
|
-
|
5
|
-
|
4
|
+
module ::Appscript
|
5
|
+
describe "Module" do
|
6
|
+
subject do
|
7
|
+
Class.new do
|
8
|
+
extend ::Appscript
|
9
|
+
end
|
10
|
+
end
|
11
|
+
describe "#app" do
|
12
|
+
|
13
|
+
it { should respond_to :app }
|
14
|
+
|
15
|
+
it "should return an instance of Application" do
|
16
|
+
subject.app.should be_instance_of ::Appscript::Application
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#its" do
|
21
|
+
it { should respond_to :its }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#name" do
|
25
|
+
it { should respond_to :name }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "Application" do
|
30
|
+
subject { ::Appscript.app('TextMate') }
|
31
|
+
|
32
|
+
[:name, :version, :processes, :unix_id, :by_pid, :is_running?].each do |method|
|
33
|
+
it "should respond to #{method}" do
|
34
|
+
-> {
|
35
|
+
subject.send(method)
|
36
|
+
}.should_not raise_error NoMethodError
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
6
40
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Editor
|
4
|
+
describe BaseAppscript do
|
5
|
+
|
6
|
+
subject do
|
7
|
+
Class.new do
|
8
|
+
include BaseAppscript
|
9
|
+
end.new
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@editor = mock
|
14
|
+
@editor.stubs(:is_running?).returns(true)
|
15
|
+
@documents = mock
|
16
|
+
@document = mock
|
17
|
+
@file_path = '/path/to/file.rb'
|
18
|
+
@path = mock
|
19
|
+
@path.stubs(:get).returns(@file_path)
|
20
|
+
@document.stubs(:path).returns(@path)
|
21
|
+
@documents.stubs(:get).returns([@document])
|
22
|
+
@editor.stubs(:document).returns(@documents)
|
23
|
+
|
24
|
+
subject.class.any_instance.stubs(:editor).returns(@editor)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#is_running" do
|
28
|
+
it "should return true if the editor is running" do
|
29
|
+
@editor.expects(:is_running?).returns(true).once
|
30
|
+
|
31
|
+
subject.is_running?.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return false if the editor is running" do
|
35
|
+
@editor.expects(:is_running?).returns(false).once
|
36
|
+
|
37
|
+
subject.is_running?.should be_false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#cuurent_path" do
|
42
|
+
it { should respond_to :current_path }
|
43
|
+
|
44
|
+
it "should return the current_path if textmate running" do
|
45
|
+
@path.expects(:get).returns(@file_path).once
|
46
|
+
@document.expects(:path).returns(@path).once
|
47
|
+
@documents.expects(:get).returns([@document]).once
|
48
|
+
|
49
|
+
subject.current_path.should == @file_path
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return nil if textmate ain't running" do
|
53
|
+
@editor.stubs(:is_running?).returns(false)
|
54
|
+
|
55
|
+
subject.current_path.should be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#cuurent_path" do
|
60
|
+
it { should respond_to :current_paths }
|
61
|
+
|
62
|
+
it "should return the current_paths if textmate running" do
|
63
|
+
@path.expects(:get).returns(@file_path).once
|
64
|
+
@document.expects(:path).returns(@path).once
|
65
|
+
@documents.expects(:get).returns([@document]).once
|
66
|
+
|
67
|
+
subject.current_paths.should == [@file_path]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return nil if textmate ain't running" do
|
71
|
+
@editor.stubs(:is_running?).returns(false)
|
72
|
+
|
73
|
+
subject.current_paths.should be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return nil if the application does not respond to document" do
|
77
|
+
@editor.stubs(:respond_to?).with(:document).returns(false)
|
78
|
+
|
79
|
+
subject.current_paths.should be_nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -4,6 +4,12 @@ module Editor
|
|
4
4
|
describe Textmate do
|
5
5
|
it { should respond_to :current_path }
|
6
6
|
|
7
|
+
it { should respond_to :name }
|
8
|
+
its(:name) { should_not raise_error NotImplementedError }
|
9
|
+
|
10
|
+
it { should respond_to :version }
|
11
|
+
its(:version) { should_not raise_error NotImplementedError }
|
12
|
+
|
7
13
|
describe "#is_running?" do
|
8
14
|
it { should respond_to :is_running? }
|
9
15
|
|
@@ -14,6 +20,10 @@ module Editor
|
|
14
20
|
|
15
21
|
subject.is_running?.should be_true
|
16
22
|
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#cuurent_path" do
|
26
|
+
it { should respond_to :current_path }
|
17
27
|
|
18
28
|
it "should return the current_path if textmate running" do
|
19
29
|
app = mock()
|
@@ -37,7 +47,34 @@ module Editor
|
|
37
47
|
|
38
48
|
subject.current_path.should be_nil
|
39
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#cuurent_path" do
|
53
|
+
it { should respond_to :current_paths }
|
54
|
+
|
55
|
+
it "should return the current_paths if textmate running" do
|
56
|
+
app = mock()
|
57
|
+
app.expects(:is_running?).returns(true).once
|
58
|
+
documents = mock
|
59
|
+
document = mock
|
60
|
+
path = mock
|
61
|
+
path.expects(:get).returns('/path/to/file.rb')
|
62
|
+
document.expects(:path).returns(path).once
|
63
|
+
documents.expects(:get).returns([document]).once
|
64
|
+
app.expects(:document).returns(documents).once
|
65
|
+
Textmate.any_instance.stubs(:editor).returns(app)
|
66
|
+
|
67
|
+
subject.current_paths.should == ['/path/to/file.rb']
|
68
|
+
end
|
40
69
|
|
70
|
+
it "should return nil if textmate ain't running" do
|
71
|
+
app = mock()
|
72
|
+
app.expects(:is_running?).returns(false).once
|
73
|
+
Textmate.any_instance.stubs(:editor).returns(app)
|
74
|
+
|
75
|
+
subject.current_paths.should be_nil
|
76
|
+
end
|
41
77
|
end
|
78
|
+
|
42
79
|
end
|
43
80
|
end
|
@@ -4,6 +4,12 @@ module Editor
|
|
4
4
|
describe Xcode do
|
5
5
|
it { should respond_to :current_path }
|
6
6
|
|
7
|
+
it { should respond_to :name }
|
8
|
+
pending(:name) { should_not raise_error NotImplementedError }
|
9
|
+
|
10
|
+
it { should respond_to :version }
|
11
|
+
pending(:version) { should_not raise_error NotImplementedError }
|
12
|
+
|
7
13
|
describe "#is_running?" do
|
8
14
|
it { should respond_to :is_running? }
|
9
15
|
|
@@ -9,12 +9,15 @@ describe Eye do
|
|
9
9
|
@file_path = '/home/user/Code/OpenSource/watch_tower/lib/watch_tower/server/models/time_entries.rb'
|
10
10
|
@project_path = '/home/user/Code/OpenSource/watch_tower'
|
11
11
|
@project_name = 'watch_tower'
|
12
|
+
::File.stubs(:exists?).with(@file_path).returns(true)
|
12
13
|
|
13
14
|
# Mock the editor
|
14
15
|
@editor = mock
|
15
16
|
@editor.stubs(:new).returns(@editor)
|
16
17
|
@editor.stubs(:is_running?).returns(true)
|
17
18
|
@editor.stubs(:current_paths).returns([@file_path])
|
19
|
+
@editor.stubs(:name).returns("Textmate")
|
20
|
+
@editor.stubs(:version).returns("1.5.10")
|
18
21
|
Editor.stubs(:editors).returns([@editor])
|
19
22
|
|
20
23
|
# Mock the project
|
@@ -65,6 +68,12 @@ describe Eye do
|
|
65
68
|
subject.start
|
66
69
|
end
|
67
70
|
|
71
|
+
it "should call File.exists?" do
|
72
|
+
::File.expects(:exists?).with(@file_path).returns(true).once
|
73
|
+
|
74
|
+
subject.start
|
75
|
+
end
|
76
|
+
|
68
77
|
it "should get the file's hash from Digest::SHA1" do
|
69
78
|
Digest::SHA1.expects(:file).with(@file_path).returns(@file_hash).once
|
70
79
|
|
@@ -99,6 +108,18 @@ describe Eye do
|
|
99
108
|
|
100
109
|
subject.start
|
101
110
|
end
|
111
|
+
|
112
|
+
it "should ask the editor for the name" do
|
113
|
+
@editor.expects(:name).returns("Textmate").once
|
114
|
+
|
115
|
+
subject.start
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should ask the editor for the version" do
|
119
|
+
@editor.expects(:version).returns("1.5.10").once
|
120
|
+
|
121
|
+
subject.start
|
122
|
+
end
|
102
123
|
end
|
103
124
|
|
104
125
|
describe "#start database validations" do
|