watch_tower 0.0.0.1 → 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/.todo +3 -0
  2. data/.travis.yml +4 -0
  3. data/Gemfile +0 -4
  4. data/README.md +48 -2
  5. data/TODO +3 -0
  6. data/ci/travis.rb +4 -1
  7. data/lib/watch_tower/appscript.rb +65 -7
  8. data/lib/watch_tower/cli/install.rb +27 -3
  9. data/lib/watch_tower/cli/open.rb +2 -0
  10. data/lib/watch_tower/cli/start.rb +3 -1
  11. data/lib/watch_tower/cli.rb +2 -0
  12. data/lib/watch_tower/config.rb +2 -0
  13. data/lib/watch_tower/core_ext.rb +2 -0
  14. data/lib/watch_tower/editor/base_appscript.rb +28 -1
  15. data/lib/watch_tower/editor/base_ps.rb +25 -0
  16. data/lib/watch_tower/editor/textmate.rb +2 -0
  17. data/lib/watch_tower/editor/xcode.rb +2 -0
  18. data/lib/watch_tower/editor.rb +2 -0
  19. data/lib/watch_tower/errors.rb +2 -0
  20. data/lib/watch_tower/eye.rb +13 -2
  21. data/lib/watch_tower/file_tree.rb +78 -0
  22. data/lib/watch_tower/project/any_based.rb +2 -0
  23. data/lib/watch_tower/project/git_based.rb +2 -0
  24. data/lib/watch_tower/project/init.rb +2 -0
  25. data/lib/watch_tower/project/path_based.rb +2 -0
  26. data/lib/watch_tower/project.rb +2 -0
  27. data/lib/watch_tower/server/app.rb +37 -7
  28. data/lib/watch_tower/server/assets/javascripts/application.js +4 -0
  29. data/lib/watch_tower/server/assets/javascripts/datepicker.coffee +21 -0
  30. data/lib/watch_tower/server/assets/javascripts/file_tree.coffee +30 -0
  31. data/lib/watch_tower/server/assets/javascripts/percentage.coffee +15 -5
  32. data/lib/watch_tower/server/assets/stylesheets/application.css +1 -0
  33. data/lib/watch_tower/server/assets/stylesheets/date.sass +17 -0
  34. data/lib/watch_tower/server/assets/stylesheets/file_tree.sass +42 -0
  35. data/lib/watch_tower/server/assets/stylesheets/global.sass +7 -4
  36. data/lib/watch_tower/server/configurations/asset.rb +2 -0
  37. data/lib/watch_tower/server/configurations.rb +2 -0
  38. data/lib/watch_tower/server/database.rb +2 -0
  39. data/lib/watch_tower/server/db/migrate/001_create_projects.rb +2 -0
  40. data/lib/watch_tower/server/db/migrate/002_create_files.rb +2 -0
  41. data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +2 -0
  42. data/lib/watch_tower/server/db/migrate/004_create_durations.rb +2 -0
  43. data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +2 -0
  44. data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +2 -0
  45. data/lib/watch_tower/server/db/migrate/007_add_editor_to_times_entries.rb +8 -0
  46. data/lib/watch_tower/server/db/migrate/008_rename_editor_to_editor_name_in_times_entries.rb +5 -0
  47. data/lib/watch_tower/server/db/migrate/009_remove_editor_index_from_time_entries.rb +7 -0
  48. data/lib/watch_tower/server/db/migrate/010_add_editor_version_to_times_entries.rb +7 -0
  49. data/lib/watch_tower/server/helpers/asset.rb +2 -0
  50. data/lib/watch_tower/server/helpers/improved_partials.rb +2 -0
  51. data/lib/watch_tower/server/helpers/presenters.rb +33 -0
  52. data/lib/watch_tower/server/helpers.rb +3 -0
  53. data/lib/watch_tower/server/models/duration.rb +9 -0
  54. data/lib/watch_tower/server/models/file.rb +17 -0
  55. data/lib/watch_tower/server/models/project.rb +30 -0
  56. data/lib/watch_tower/server/models/time_entry.rb +5 -0
  57. data/lib/watch_tower/server/presenters/application_presenter.rb +165 -0
  58. data/lib/watch_tower/server/presenters/file_presenter.rb +10 -0
  59. data/lib/watch_tower/server/presenters/project_presenter.rb +20 -0
  60. data/lib/watch_tower/server/presenters.rb +13 -0
  61. data/lib/watch_tower/server/public/assets/{WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg → WatchTower-58eff0713efffbc6054defddc879e0b1.jpg} +0 -0
  62. data/lib/watch_tower/server/public/assets/application-4e6971066e06aa53b0c8e52c764044d1.css +389 -0
  63. data/lib/watch_tower/server/public/assets/application-6a1be75d4fd6a545faceb638e47a2486.js +23778 -0
  64. data/lib/watch_tower/server/public/assets/calendar-379834cd6e6321a940b662ace47f3032.gif +0 -0
  65. data/lib/watch_tower/server/public/assets/calendar-blue-d6aa74feef7ee4287532761db99a6c0a.gif +0 -0
  66. data/lib/watch_tower/server/public/assets/calendar-green-3752fe2996091379c8d321f759039385.gif +0 -0
  67. data/lib/watch_tower/server/public/assets/jquery.datepick-9c8dfe3a4d40bcafc7b182e194c13836.css +227 -0
  68. data/lib/watch_tower/server/public/assets/{percentage-d8589e21a5fc85d32a445f531ff8ab95.png → percentage-d0176e99520c95e93eee63738ef5d487.png} +0 -0
  69. data/lib/watch_tower/server/vendor/assets/images/calendar-blue.gif +0 -0
  70. data/lib/watch_tower/server/vendor/assets/images/calendar-green.gif +0 -0
  71. data/lib/watch_tower/server/vendor/assets/images/calendar.gif +0 -0
  72. data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-ext.js +266 -0
  73. data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick-validation.js +232 -0
  74. data/lib/watch_tower/server/vendor/assets/javascripts/jquery-datepick.js +2092 -0
  75. data/lib/watch_tower/server/vendor/assets/stylesheets/jquery.datepick.css +226 -0
  76. data/lib/watch_tower/server/views/_project.haml +10 -13
  77. data/lib/watch_tower/server/views/index.haml +9 -6
  78. data/lib/watch_tower/server/views/layout.haml +7 -4
  79. data/lib/watch_tower/server/views/project.haml +9 -11
  80. data/lib/watch_tower/server.rb +8 -1
  81. data/lib/watch_tower/templates/{watchtower.plist → watchtower.plist.erb} +5 -6
  82. data/lib/watch_tower/version.rb +12 -3
  83. data/lib/watch_tower.rb +20 -1
  84. data/spec/factories.rb +2 -0
  85. data/spec/watch_tower/appscript_spec.rb +36 -2
  86. data/spec/watch_tower/editor/base_appscript_spec.rb +83 -0
  87. data/spec/watch_tower/editor/textmate_spec.rb +37 -0
  88. data/spec/watch_tower/editor/xcode_spec.rb +6 -0
  89. data/spec/watch_tower/eye_spec.rb +21 -0
  90. data/spec/watch_tower/file_tree_spec.rb +156 -0
  91. data/spec/watch_tower/server/app_spec.rb +64 -20
  92. data/spec/watch_tower/server/models/file_spec.rb +93 -31
  93. data/spec/watch_tower/server/models/project_spec.rb +147 -18
  94. data/spec/watch_tower/server/models/time_entry_spec.rb +10 -0
  95. data/spec/watch_tower/server/{decorator/project_decorator_spec.rb → presenters/application_presenter_spec.rb} +24 -13
  96. data/spec/watch_tower/server/presenters/file_presenter_spec.rb +8 -0
  97. data/spec/watch_tower/server/presenters/project_presenter_spec.rb +130 -0
  98. data/watch_tower.gemspec +10 -4
  99. metadata +114 -74
  100. data/lib/watch_tower/server/decorator/application_decorator.rb +0 -91
  101. data/lib/watch_tower/server/decorator/file_decorator.rb +0 -38
  102. data/lib/watch_tower/server/decorator/project_decorator.rb +0 -51
  103. data/lib/watch_tower/server/decorator.rb +0 -21
  104. data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +0 -107
  105. data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +0 -9359
  106. data/lib/watch_tower/server/views/_file.haml +0 -9
data/.todo CHANGED
@@ -12,6 +12,9 @@
12
12
  <note priority="medium" time="1317889118" done="1317980852">
13
13
  Add a ci/travis.rb script which runs the tests under Travis-CI, needed because the config file added in todo number 3 won't exist and the current setup (sqlite) does not work with JRuby
14
14
  </note>
15
+ <note priority="veryhigh" time="1319041505">
16
+ The elapsed time of the project should change when the duration changes
17
+ </note>
15
18
  <note priority="high" time="1318256016">
16
19
  Figure out how to load assets from gems and remove the bundled jQuery files.
17
20
  </note>
data/.travis.yml CHANGED
@@ -1,4 +1,8 @@
1
1
  script: 'ci/travis.rb'
2
+ branches:
3
+ only:
4
+ - master
5
+ - develop
2
6
  rvm:
3
7
  - 1.9.2
4
8
  - 1.9.3
data/Gemfile CHANGED
@@ -36,8 +36,4 @@ end
36
36
 
37
37
  platforms :mri do
38
38
  gem 'pg'
39
-
40
- if RbConfig::CONFIG['target_os'] =~ /darwin/i
41
- gem 'rb-appscript', '~>0.6.1'
42
- end
43
39
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Watch Tower [![Build Status](http://travis-ci.org/TechnoGate/watch_tower.png)](http://travis-ci.org/TechnoGate/watch_tower) ![Still Maintained](http://stillmaintained.com/TechnoGate/watch_tower.png)
2
2
 
3
- <a href='http://www.pledgie.com/campaigns/16123'><img alt='Click here to lend your support to: Open Source Projects and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/16123.png?skin_name=chrome' border='0' /></a>
3
+ [![Click here to lend your support to: Open Source Projects and make a donation at www.pledgie.com !](http://www.pledgie.com/campaigns/16123.png?skin_name=chrome)](http://www.pledgie.com/campaigns/16123)
4
4
 
5
5
  WatchTower helps you track the time you spend on each project.
6
6
 
@@ -35,4 +35,50 @@ http://localhost:9282 or using the command
35
35
 
36
36
  ```bash
37
37
  $ watchtower open
38
- ```
38
+ ```
39
+
40
+ # Screenshots
41
+
42
+ ## Home page
43
+
44
+ ![Home page](http://cloud.github.com/downloads/TechnoGate/watch_tower/home_page.png)
45
+
46
+ ## Project page
47
+
48
+ ![Project page](http://cloud.github.com/downloads/TechnoGate/watch_tower/project_page.png)
49
+
50
+ # Contributing
51
+
52
+ Please feel free to fork and send pull requests, but please follow the
53
+ following guidelines:
54
+
55
+ - Prefix each commit message with the filename or the module followed by a
56
+ colon and a space, for example 'README: fix a typo' or 'Server/Project: Fix
57
+ a typo'.
58
+ - Include tests.
59
+ - Do not change the version, We will take care of that.
60
+
61
+ # License
62
+
63
+ ## This code is free to use under the terms of the MIT license.
64
+
65
+ Copyright (c) 2011 TechnoGate &lt;support@technogate.fr&gt;
66
+
67
+ Permission is hereby granted, free of charge, to any person obtaining
68
+ a copy of this software and associated documentation files (the
69
+ "Software"), to deal in the Software without restriction, including
70
+ without limitation the rights to use, copy, modify, merge, publish,
71
+ distribute, sublicense, and/or sell copies of the Software, and to
72
+ permit persons to whom the Software is furnished to do so, subject to
73
+ the following conditions:
74
+
75
+ The above copyright notice and this permission notice shall be
76
+ included in all copies or substantial portions of the Software.
77
+
78
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
79
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
80
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
81
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
82
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
83
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
84
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/TODO CHANGED
@@ -1,3 +1,6 @@
1
+ - The elapsed time of the project should change when the duration changes
2
+ (added Wed Oct 19 18:25:05 2011, incomplete, priority veryhigh)
3
+
1
4
  - Figure out how to load assets from gems and remove the bundled jQuery files.
2
5
  (added Mon Oct 10 16:13:36 2011, incomplete, priority high)
3
6
 
data/ci/travis.rb CHANGED
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
2
3
  # This file has been taken from rails
3
4
  # https://github.com/rails/rails/blob/master/ci/travis.rb
4
5
  require 'fileutils'
5
6
  include FileUtils
6
7
 
7
8
  commands = [
9
+ 'mysql -e "drop database if exists watch_tower_test;"',
8
10
  'mysql -e "create database watch_tower_test;"',
11
+ 'psql -c "drop database if exists watch_tower_test;" -U postgres',
9
12
  'psql -c "create database watch_tower_test;" -U postgres'
10
13
  ]
11
14
 
@@ -97,6 +100,6 @@ if failures.empty?
97
100
  else
98
101
  puts
99
102
  puts "WatchTower build FAILED"
100
- puts "Failed adapters: #{failures.join(', ')}"
103
+ puts "Failed adapters: #{failures.keys.join(', ')}"
101
104
  exit(false)
102
105
  end
@@ -1,22 +1,80 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  begin
2
- require 'rubygems'
3
4
  require 'appscript'
4
5
  rescue LoadError
5
- require 'rbconfig'
6
- if RbConfig::CONFIG['target_os'] =~ /darwin/i
7
- STDERR.puts "Please install 'appscript' to use this gem with Textmate"
8
- STDERR.puts "gem install appscript"
9
- end
10
- # Define a simple class so the gem works even if Appscript is not installed
6
+ # Define a part of the Appscript gem so WatchTower is fully operational
11
7
  module ::Appscript
8
+ CommandError = Class.new(Exception)
9
+
12
10
  class Application
11
+
12
+ MOCK_METHODS = [:name, :version, :unix_id, :by_pid]
13
+
13
14
  def is_running?
14
15
  false
15
16
  end
17
+
18
+ def get
19
+ "Not available"
20
+ end
21
+
22
+ def processes
23
+ Process.new(self)
24
+ end
25
+
26
+ MOCK_METHODS.each do |method|
27
+ define_method method do |*args|
28
+ self
29
+ end
30
+ end
31
+ end
32
+
33
+ class Process
34
+ def initialize(klass)
35
+ @klass = klass
36
+ end
37
+
38
+ def [](*args)
39
+ [@klass]
40
+ end
16
41
  end
17
42
 
18
43
  def app(*args)
19
44
  Application.new
20
45
  end
46
+
47
+ def its
48
+ self
49
+ end
50
+
51
+ def name
52
+ self
53
+ end
54
+
55
+ def eq(*args)
56
+ self
57
+ end
58
+
59
+ def Appscript.app(*args)
60
+ Application.new
61
+ end
62
+
63
+ def Appscript.its
64
+ self
65
+ end
66
+
67
+ def Appscript.name
68
+ self
69
+ end
70
+
71
+ def Appscript.eq(*args)
72
+ self
73
+ end
74
+
75
+ end
76
+
77
+ module ::FindApp
78
+ ApplicationNotFoundError = Class.new(Exception)
21
79
  end
22
80
  end
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module CLI
3
5
  module Install
@@ -25,6 +27,22 @@ module WatchTower
25
27
  end
26
28
 
27
29
  protected
30
+ # Taken from hub
31
+ # https://github.com/defunkt/hub/blob/master/lib/hub/context.rb#L186
32
+ # Cross-platform way of finding an executable in the $PATH.
33
+ #
34
+ # which('ruby') #=> /usr/bin/ruby
35
+ def which(cmd)
36
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
37
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
38
+ exts.each { |ext|
39
+ exe = "\#{path}/\#{cmd}\#{ext}"
40
+ return exe if File.executable? exe
41
+ }
42
+ end
43
+ return nil
44
+ end
45
+
28
46
  # Install the configuration file
29
47
  def install_config_file
30
48
  self.class.source_root(TEMPLATE_PATH)
@@ -42,7 +60,7 @@ module WatchTower
42
60
  WatchTower bootloader is not supported on your OS, you'd have to run it manually
43
61
  for the time being. Support for many editors and many OSes is planned for the
44
62
  future, if you would like to help, or drop in an issue please don't hesitate to
45
- do so on the Github page: https://github.com/TechnoGate/watch_tower
63
+ do so on the project's Github page: https://github.com/TechnoGate/watch_tower
46
64
  MSG
47
65
  end
48
66
  end
@@ -50,8 +68,14 @@ MSG
50
68
  # Install bootloader on Mac OS X
51
69
  def install_bootloader_on_mac
52
70
  self.class.source_root(TEMPLATE_PATH)
53
- copy_file 'watchtower.plist', File.join(ENV['HOME'], 'Library',
54
- 'LaunchAgents', 'fr.technogate.WatchTower.plist')
71
+ # copy_file 'watchtower.plist', File.join(ENV['HOME'], 'Library',
72
+ # 'LaunchAgents', 'fr.technogate.WatchTower.plist')
73
+ create_file File.join(ENV['HOME'], 'Library', 'LaunchAgents', 'fr.technogate.WatchTower.plist') do
74
+ ruby_binary = which('ruby')
75
+ watch_tower_binary = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'bin', 'watchtower'))
76
+ template = File.expand_path(find_in_source_paths('watchtower.plist.erb'))
77
+ ERB.new(File.read(template)).result(binding)
78
+ end
55
79
 
56
80
  puts "\nCreated. Now run:\n launchctl load ~/Library/LaunchAgents/fr.technogate.WatchTower.plist\n\n"
57
81
  end
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module CLI
3
5
  module Open
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module CLI
3
5
  module Start
@@ -40,7 +42,7 @@ module WatchTower
40
42
  desc: "Set the server's port."
41
43
  def start
42
44
  if Config[:enabled] &&
43
- (!options[:bootloader] || (options(:bootloader) && Config[:launch_on_boot]))
45
+ (!options[:bootloader] || (options[:bootloader] && Config[:launch_on_boot]))
44
46
  LOG.info "Starting WatchTower."
45
47
  start!
46
48
  else
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'thor'
2
4
 
3
5
  # Load all modules
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'active_support/hash_with_indifferent_access'
2
4
 
3
5
  module WatchTower
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'active_support/core_ext'
2
4
  require 'active_support/dependencies/autoload'
3
5
 
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'watch_tower/appscript'
2
4
 
3
5
  module WatchTower
@@ -13,16 +15,41 @@ module WatchTower
13
15
  # Include AppScript
14
16
  include ::Appscript
15
17
 
18
+ # Is the editor running ?
19
+ #
20
+ # @return [Boolean]
16
21
  def is_running?
17
22
  editor.is_running? if editor
18
23
  end
19
24
 
25
+ # Returns the name of the editor
26
+ #
27
+ # Child class should implement this method
28
+ def name
29
+ editor.try(:name).try(:get)
30
+ end
31
+
32
+ # Returns the version of the editor
33
+ #
34
+ # Child class should implement this method
35
+ def version
36
+ editor.try(:version).try(:get)
37
+ end
38
+
39
+ # Return the path of the document being edited
40
+ # Child classes can override this method if the behaviour is different
41
+ #
42
+ # @return [String] path to the document currently being edited
20
43
  def current_path
21
44
  current_paths.try(:first)
22
45
  end
23
46
 
47
+ # Return the pathes of the documents being edited
48
+ # Child classes can override this method if the behaviour is different
49
+ #
50
+ # @return [Array] pathes to the documents currently being edited
24
51
  def current_paths
25
- if is_running?
52
+ if is_running? && editor.respond_to?(:document)
26
53
  editor.document.get.collect(&:path).collect(&:get)
27
54
  end
28
55
  end
@@ -1,6 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module Editor
3
5
  module BasePs
6
+ def self.included(base)
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module InstanceMethods
11
+ def self.included(base)
12
+ base.class_eval <<-END, __FILE__, __LINE__ + 1
13
+ # Returns the name of the editor
14
+ #
15
+ # Child class should implement this method
16
+ def name
17
+ raise NotImplementedError, "Please define this function in your class."
18
+ end
19
+
20
+ # Returns the version of the editor
21
+ #
22
+ # Child class should implement this method
23
+ def version
24
+ raise NotImplementedError, "Please define this function in your class."
25
+ end
26
+ END
27
+ end
28
+ end
4
29
  end
5
30
  end
6
31
  end
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module Editor
3
5
  class Textmate
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module Editor
3
5
  class Xcode
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  module Editor
3
5
  extend ::ActiveSupport::Autoload
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  # Global Error
3
5
  WatchTowerError = Class.new Exception
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'digest/sha1'
2
4
 
3
5
  module WatchTower
@@ -22,8 +24,10 @@ module WatchTower
22
24
  LOG.debug("#{__FILE__}:#{__LINE__}: #{editor.to_s} is running")
23
25
  # Get the currently being edited file from the editor
24
26
  files_paths = editor.current_paths
27
+ # Iterate over the files to fill the database
25
28
  files_paths.each do |file_path|
26
29
  begin
30
+ next unless file_path && File.exists?(file_path)
27
31
  # Get the file_hash of the file
28
32
  file_hash = Digest::SHA1.file(file_path).hexdigest
29
33
  # Create a project from the file_path
@@ -44,7 +48,10 @@ module WatchTower
44
48
  file_model = project_model.files.find_or_create_by_path(file_path)
45
49
  begin
46
50
  # Create a time entry
47
- file_model.time_entries.create!(mtime: File.stat(file_path).mtime, file_hash: file_hash)
51
+ file_model.time_entries.create! mtime: File.stat(file_path).mtime,
52
+ file_hash: file_hash,
53
+ editor_name: editor.name,
54
+ editor_version: editor.version
48
55
  rescue ActiveRecord::RecordInvalid => e
49
56
  # This should happen if the mtime is already present
50
57
  end
@@ -59,7 +66,7 @@ module WatchTower
59
66
  end
60
67
  end
61
68
 
62
- # If $stop global is set, please stop, otherwise sleep for 30 seconds.
69
+ # If $stop global is set, please stop, otherwise sleep for 10 seconds.
63
70
  if $close_eye
64
71
  LOG.debug("#{__FILE__}:#{__LINE__}: Closing eye has been requested, end the loop")
65
72
  break
@@ -73,6 +80,10 @@ module WatchTower
73
80
  #
74
81
  # @param [Hash] options
75
82
  def start!(options = {})
83
+ # Signal handling
84
+ Signal.trap("INT") { $close_eye = true }
85
+ Signal.trap("TERM") { $close_eye = true }
86
+
76
87
  start(options)
77
88
  end
78
89
  end
@@ -0,0 +1,78 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module WatchTower
4
+ # This class is used by the server to provided a FileTree representation
5
+ # of the files and their elapsed time
6
+ class FileTree
7
+
8
+ attr_reader :base_path, :files, :nested_tree, :elapsed_time
9
+
10
+ # Initialize
11
+ #
12
+ # @param [String] base_path: The base path of all files, usually the project's path
13
+ # @param [Array] files: The files and their elapsed time
14
+ # The Array elements should be Hashes with two required keys
15
+ # :path and :elapsed_time
16
+ def initialize(base_path, files)
17
+ # Init with args
18
+ @base_path = base_path
19
+ @all_files = remove_base_path_from_files(@base_path, files)
20
+ # Init with defaults
21
+ @elapsed_time = 0
22
+ @files = Array.new
23
+ @nested_tree = Hash.new
24
+ # Process the tree
25
+ process
26
+ end
27
+
28
+ protected
29
+ # Process the Tree
30
+ def process
31
+ # Parse files
32
+ parse_files
33
+ # Parse folders
34
+ parse_folders
35
+ end
36
+
37
+ # Removes the base_path from the files
38
+ def remove_base_path_from_files(base_path, files)
39
+ files.collect do |f|
40
+ f[:path] = f[:path].gsub(%r(#{base_path}#{File::SEPARATOR}), '')
41
+ f
42
+ end
43
+ end
44
+
45
+ # Parses only files under the current base_path
46
+ def parse_files
47
+ return if @files.any?
48
+
49
+ @all_files.each do |f|
50
+ unless f[:path] =~ %r(#{File::SEPARATOR})
51
+ @elapsed_time += f[:elapsed_time]
52
+ @files << f
53
+ end
54
+ end
55
+ end
56
+
57
+ # Parses only folders under the current base_path
58
+ def parse_folders
59
+ return if @nested_tree.any?
60
+
61
+ @all_files.each do |f|
62
+ if f[:path] =~ %r(#{File::SEPARATOR})
63
+ # Get the base_path
64
+ base_path = f[:path].split(File::SEPARATOR).first
65
+ # Do not continue if we already parsed this path
66
+ next if @nested_tree.has_key?(base_path)
67
+ # Get the nested files
68
+ nested_files = remove_base_path_from_files base_path,
69
+ @all_files.select { |f| f[:path] =~ %r(^#{base_path}#{File::SEPARATOR}) }
70
+ # Create a tree
71
+ @nested_tree[base_path] = self.class.new("#{@base_path}#{File::SEPARATOR}#{base_path}", nested_files)
72
+ # Add the elapsed_time of the tree
73
+ @elapsed_time += @nested_tree[base_path].elapsed_time
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  class Project
3
5
  module AnyBased
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'git'
2
4
 
3
5
  module WatchTower
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  class Project
3
5
  module Init
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  module WatchTower
2
4
  class Project
3
5
  # The module contains Path specific project methods, methods like name, path
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  require 'watch_tower/project/any_based'
2
4
  require 'watch_tower/project/init'
3
5
 
@@ -1,3 +1,5 @@
1
+ # -*- encoding: utf-8 -*-
2
+
1
3
  # Sinatra
2
4
  require 'sinatra'
3
5
 
@@ -7,9 +9,7 @@ module WatchTower
7
9
  # Helper
8
10
  include Helpers::ImprovedPartials
9
11
  include Helpers::Asset
10
-
11
- # Include Decorator
12
- include Decorator
12
+ include Helpers::Presenters
13
13
 
14
14
  # Configurations
15
15
  include Configurations::Asset
@@ -18,19 +18,49 @@ module WatchTower
18
18
  paths :root => '/'
19
19
  paths :project => '/project/:id'
20
20
 
21
+ # Enable sessions
22
+ enable :sessions
23
+
24
+ # Before filter
25
+ before do
26
+ # Parse the from/to date from params and add it to the session
27
+ if params[:from_date] && params[:to_date]
28
+ if params[:from_date].present? && params[:to_date].present?
29
+ session[:date_filtering] = {
30
+ from_date: params[:from_date],
31
+ to_date: params[:to_date]
32
+ }
33
+ else
34
+ session[:date_filtering] = nil
35
+ end
36
+ end
37
+
38
+ # Make sure we have a default date filtering
39
+ unless session.try(:[], :date_filtering).try(:[], :from_date) && session.try(:[], :date_filtering).try(:[], :to_date)
40
+ session[:date_filtering] = {
41
+ from_date: Time.now.to_date.beginning_of_month.strftime('%m/%d/%Y'),
42
+ to_date: Time.now.to_date.strftime('%m/%d/%Y')
43
+ }
44
+ end
45
+ end
46
+
21
47
  # The index action
22
48
  get :root do
23
49
  @title = "Projects"
24
- @projects = ProjectDecorator.decorate(Project.worked_on)
50
+ @durations = Duration.date_range(session[:date_filtering][:from_date], session[:date_filtering][:to_date])
51
+ @projects = @durations.collect(&:file).collect(&:project).uniq
25
52
 
26
- haml :index
53
+ haml :index, layout: (request.xhr? ? false : :layout)
27
54
  end
28
55
 
56
+ # The project action
29
57
  get :project do
30
- @project = ProjectDecorator.find(params[:id])
58
+ @project = Project.find(params[:id])
31
59
  @title = "Project - #{@project.name.camelcase}"
60
+ @durations = @project.durations.date_range(session[:date_filtering][:from_date], session[:date_filtering][:to_date])
61
+ @files = @durations.collect(&:file).uniq
32
62
 
33
- haml :project
63
+ haml :project, layout: (request.xhr? ? false : :layout)
34
64
  end
35
65
  end
36
66
  end
@@ -1,3 +1,7 @@
1
1
  //= require jquery
2
2
  //= require jquery_ujs
3
+ //= require jquery-ui
4
+ //= require jquery-datepick
5
+ //= require jquery-datepick-ext
6
+ //= require jquery-datepick-validation
3
7
  //= require_tree .