breaktime 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +73 -0
- data/Rakefile +1 -0
- data/bin/breaktime +4 -0
- data/breaktime.gemspec +24 -0
- data/lib/breaktime.rb +26 -0
- data/lib/breaktime/cli.rb +55 -0
- data/lib/breaktime/command.rb +50 -0
- data/lib/breaktime/dialog.rb +30 -0
- data/lib/breaktime/linux_win_manager.rb +28 -0
- data/lib/breaktime/main.rb +209 -0
- data/lib/breaktime/schedule.rb +84 -0
- data/lib/breaktime/version.rb +3 -0
- metadata +142 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jon Cairns
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Breaktime
|
2
|
+
|
3
|
+
Breaktime loves your eyes. That's why it gives them a screen break every so often - as often as you like. It hides in the background, waiting for it's moment to shine. When it's time for you to take a break it opens a dialog box with a timer counting down from 10, giving you the chance to cancel. But when the timer hits zero your screensaver will pop up, forcing you to go and make some tea/coffee/mojitos.
|
4
|
+
|
5
|
+
You can set how often it runs, which day(s) of the week it runs, and which system command you want to execute when it's time for a break. All of this can be configured with some lovely YAML.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
As breaktime is a ruby gem, you need to have access to the rubygems command line tool, `gem`. If you do, installation will hopefully be as simple as:
|
10
|
+
|
11
|
+
$ gem install breaktime
|
12
|
+
|
13
|
+
But breaktime depends on the [green_shoes](https://github.com/ashbb/green_shoes) gem, which itself depends on gtk2. Building this gem requires native extensions, so you will need to have the right libraries to get it to install.
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
After installing you have access to the `breaktime` command line tool.
|
18
|
+
|
19
|
+
```bash
|
20
|
+
$ breaktime --help
|
21
|
+
NAME
|
22
|
+
breaktime
|
23
|
+
|
24
|
+
SYNOPSIS
|
25
|
+
breaktime (start|stop|dialog|now) [options]+
|
26
|
+
|
27
|
+
DESCRIPTION
|
28
|
+
Give your eyes scheduled screen breaks
|
29
|
+
|
30
|
+
PARAMETERS
|
31
|
+
--config, -c <s>: Configuration yaml file (default: /home/jon/.breaktime.yml)
|
32
|
+
--level, -l <s>: Output level = (debug|info|warn|error|fatal) (default: info)
|
33
|
+
--help, -h: Show this message
|
34
|
+
```
|
35
|
+
|
36
|
+
Simply running `breaktime` on its own should work - it will run every 60 minutes by default, and will try and work out the right screensaver command for your OS and window manager. If it can't work out your OS, then you can just set the **command** in the YAML file (read on).
|
37
|
+
|
38
|
+
If you want to do a bit more fine-tuning, create a YAML file at `$HOME/.breaktime.yml` that looks like this (everything's optional):
|
39
|
+
|
40
|
+
```yml
|
41
|
+
command: xscreensaver-command -a
|
42
|
+
interval: 40
|
43
|
+
daemonize: true
|
44
|
+
log_file: /path/to/log/file.log
|
45
|
+
pid_file: /path/to/pid/file.pid
|
46
|
+
days:
|
47
|
+
- monday
|
48
|
+
- tuesday
|
49
|
+
- wednesday
|
50
|
+
- thursday
|
51
|
+
- friday
|
52
|
+
```
|
53
|
+
|
54
|
+
* **command** is the system command run every break time
|
55
|
+
* **interval** is the time, in minutes, between each break
|
56
|
+
* **daemonize** says whether the scheduling should run as a background process (daemon)
|
57
|
+
* **log_file** specifies the file that output is written to (only if **daemonize** is true)
|
58
|
+
* **pid_file** specifies the file that contains the PID (only if **daemonize** is true)
|
59
|
+
* **days** allows you to specify which days of the week to run it
|
60
|
+
|
61
|
+
If you want your YAML file to be elsewhere, then just pass it as the `--config` parameter to the breaktime command.
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create new Pull Request
|
70
|
+
|
71
|
+
## License
|
72
|
+
|
73
|
+
MIT
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/breaktime
ADDED
data/breaktime.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'breaktime/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "breaktime"
|
8
|
+
gem.version = Breaktime::VERSION
|
9
|
+
gem.authors = ["Jon Cairns"]
|
10
|
+
gem.email = ["jon@joncairns.com"]
|
11
|
+
gem.description = %q{Enforce screen breaks at regular intervals, when you want them}
|
12
|
+
gem.summary = %q{Breaktime}
|
13
|
+
gem.homepage = "https://github.com/joonty/breaktime"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = ['breaktime']
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib","lib/breaktime"]
|
19
|
+
gem.add_dependency 'green_shoes', '~> 1.1.373'
|
20
|
+
gem.add_dependency 'trollop', '~> 2.0.0'
|
21
|
+
gem.add_dependency 'rufus-scheduler', '~> 2.0.17'
|
22
|
+
gem.add_dependency 'log4r', '~> 1.1.10'
|
23
|
+
gem.add_dependency 'dante', '~> 0.1.5'
|
24
|
+
end
|
data/lib/breaktime.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# The encapsulating module for the breaktime gem.
|
2
|
+
#
|
3
|
+
# Breaktime gives you regular screen breaks on a schedule that you choose.
|
4
|
+
#
|
5
|
+
# This should be run as the command line tool `breaktime`. For more information
|
6
|
+
# try running `breaktime --help`.
|
7
|
+
module Breaktime
|
8
|
+
lib_dir = File.dirname(__FILE__) + File::SEPARATOR + 'breaktime'
|
9
|
+
$:.unshift lib_dir
|
10
|
+
|
11
|
+
# Exit status codes.
|
12
|
+
EX_OK = 0 # Everything fine
|
13
|
+
EX_UNKNOWN = 1 # Unknown exception
|
14
|
+
EX_OS_UNKNOWN = 2 # Unknown OS
|
15
|
+
EX_LINUX_WM_UNKNOWN = 3 # Unknown window manager (linux)
|
16
|
+
EX_SIGNAL = 128 # Process signal caught
|
17
|
+
EX_INTERRUPT = 130 # Control-C caught
|
18
|
+
EX_BREAK_CANCELLED = 254 # Cancel from the countdown GUI
|
19
|
+
EX_CLI = 255 # CLI option errors
|
20
|
+
|
21
|
+
require 'rubygems'
|
22
|
+
require 'bundler/setup'
|
23
|
+
require 'version'
|
24
|
+
require 'command'
|
25
|
+
require 'main'
|
26
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
class Breaktime::CLI
|
4
|
+
attr_reader :options, :mode
|
5
|
+
|
6
|
+
# Available sub commands (modes) for CLI.
|
7
|
+
SUB_COMMANDS = %w(start stop dialog now)
|
8
|
+
|
9
|
+
# Default location of YAML config file.
|
10
|
+
DEFAULT_CONFIG = ENV['HOME'] + File::SEPARATOR + ".breaktime.yml"
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@options = parse_cli_options
|
14
|
+
@mode = ARGV.shift || 'start'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
# Parse CLI options with Trollop.
|
19
|
+
def parse_cli_options
|
20
|
+
Trollop::options do
|
21
|
+
banner <<-BAN
|
22
|
+
NAME
|
23
|
+
breaktime
|
24
|
+
|
25
|
+
SYNOPSIS
|
26
|
+
breaktime (#{SUB_COMMANDS.join("|")}) [options]+
|
27
|
+
|
28
|
+
DESCRIPTION
|
29
|
+
Give your eyes scheduled screen breaks by starting up the screensaver at
|
30
|
+
regular intervals. By default it will give you a break every 60 minutes.
|
31
|
+
It is configurable via a YAML file which sits at $HOME/.breaktime.yml by
|
32
|
+
default.
|
33
|
+
|
34
|
+
USAGE
|
35
|
+
breaktime (start) - start breaktime, as a daemon by default
|
36
|
+
breaktime stop - stop a daemonized process
|
37
|
+
breaktime now - run the command to have a break instantly
|
38
|
+
breaktime dialog - show the countdown dialog box
|
39
|
+
|
40
|
+
PARAMETERS
|
41
|
+
BAN
|
42
|
+
|
43
|
+
opt :config,
|
44
|
+
"Configuration yaml file",
|
45
|
+
:short => '-c',
|
46
|
+
:default => DEFAULT_CONFIG
|
47
|
+
|
48
|
+
opt :level,
|
49
|
+
"Output level = (debug|info|warn|error|fatal)",
|
50
|
+
:short => '-l',
|
51
|
+
:default => 'info'
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'linux_win_manager'
|
2
|
+
|
3
|
+
# Used to determine and run the screensaver command.
|
4
|
+
class Breaktime::Command
|
5
|
+
class OSUnknown < StandardError; end
|
6
|
+
|
7
|
+
attr_reader :command
|
8
|
+
|
9
|
+
# Determine the default screensaver command based on the user's OS.
|
10
|
+
#
|
11
|
+
# If Linux, use the LinuxWinManager class to determine the appropriate
|
12
|
+
# command.
|
13
|
+
def self.system_default(log)
|
14
|
+
case RbConfig::CONFIG['target_os']
|
15
|
+
when 'linux'
|
16
|
+
require 'linux_win_manager'
|
17
|
+
log.debug { "Using Linux, detecting window manager and appropriate command" }
|
18
|
+
Breaktime::LinuxWinManager.detect_command(log)
|
19
|
+
|
20
|
+
when 'darwin10'
|
21
|
+
log.debug { "Using Mac OSX10" }
|
22
|
+
'open -a /System/Library/Frameworks/ScreenSaver.framework/Versions/A/Resources/ScreenSaverEngine.app'
|
23
|
+
|
24
|
+
when /mswin.*$/
|
25
|
+
log.debug { "Using Windows" }
|
26
|
+
'rundll32.exe user32.dll,LockWorkStation'
|
27
|
+
|
28
|
+
else
|
29
|
+
raise OSUnknown, 'Unknown OS'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Store the command if specified, or determine the system default.
|
34
|
+
def initialize(command, log)
|
35
|
+
@command = if command.nil?
|
36
|
+
self.class.system_default(log)
|
37
|
+
else
|
38
|
+
log.debug { "User defined command: #{command}" }
|
39
|
+
command
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute the command with Kernel#exec.
|
44
|
+
#
|
45
|
+
# This replaces the current process, exiting when the command exits.
|
46
|
+
def execute
|
47
|
+
exec @command
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'green_shoes'
|
2
|
+
|
3
|
+
module Breaktime
|
4
|
+
# The shoes GUI app for notifying the user about their imminent breaktime.
|
5
|
+
#
|
6
|
+
# They have 10 seconds to cancel the break. If they cancel the process exits
|
7
|
+
# with EX_BREAK_CANCELLED, otherwise EX_OK. This is used by calling processes
|
8
|
+
# to determine what to do.
|
9
|
+
Shoes.app :height => 60, :width => 380, :title => 'Take a break!' do
|
10
|
+
seconds = 10
|
11
|
+
str = "Take a break! You have %d seconds to cancel."
|
12
|
+
|
13
|
+
background white
|
14
|
+
flow :margin => 4 do
|
15
|
+
@sent = para str % seconds
|
16
|
+
|
17
|
+
button "Cancel" do
|
18
|
+
exit Breaktime::EX_BREAK_CANCELLED
|
19
|
+
end
|
20
|
+
|
21
|
+
every 1 do |i|
|
22
|
+
if i >= seconds
|
23
|
+
exit Breaktime::EX_OK
|
24
|
+
else
|
25
|
+
@sent.text = str % (seconds - i)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Used to detect the Linux window manager.
|
2
|
+
#
|
3
|
+
# This information is used to determine the default screensaver command.
|
4
|
+
class Breaktime::LinuxWinManager
|
5
|
+
# Thrown if the window manager can't be detected.
|
6
|
+
class ManagerUnknown < StandardError; end
|
7
|
+
|
8
|
+
@@managers = {'kcmserver' => 'dcop kdesktop KScreensaverIface lock',
|
9
|
+
'gnome-session' => 'gnome-screensaver-command -a',
|
10
|
+
'xfce-mcs-manage' => 'xscreensaver-command --lock'}
|
11
|
+
|
12
|
+
attr_reader :cmd
|
13
|
+
|
14
|
+
# Check the process list for known window manager services.
|
15
|
+
#
|
16
|
+
# If the service is found, return the associated command for starting the
|
17
|
+
# screensaver.
|
18
|
+
def self.detect_command(log)
|
19
|
+
log.debug { "Checking for known window manager processes: #{@@managers.keys.join(", ")}" }
|
20
|
+
lines = `ps -eo args|egrep "#{@@managers.keys.join("|")}"|grep -v "egrep"`.split "\n"
|
21
|
+
|
22
|
+
lines.any? or raise ManagerUnknown, 'Unable to detect a known window manager'
|
23
|
+
|
24
|
+
m = @@managers.keys.select {|k| lines.first.include? k}
|
25
|
+
log.debug { "Found #{m.first}" }
|
26
|
+
@@managers[m.first]
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'log4r'
|
3
|
+
require 'schedule'
|
4
|
+
require 'dante'
|
5
|
+
require 'cli'
|
6
|
+
|
7
|
+
# Handles configuration options, CLI stuff and process daemonizing.
|
8
|
+
class Breaktime::Main
|
9
|
+
include Log4r
|
10
|
+
|
11
|
+
attr_reader :options, :log, :cli
|
12
|
+
|
13
|
+
# Default options that can be overridden in the YAML file.
|
14
|
+
DEFAULT_OPTIONS = {'interval' => 60,
|
15
|
+
'pid_path' => ENV['HOME'] + File::SEPARATOR + "breaktime.pid",
|
16
|
+
'log_path' => ENV['HOME'] + File::SEPARATOR + "breaktime.log",
|
17
|
+
'daemonize' => true,
|
18
|
+
'days' => ['monday',
|
19
|
+
'tuesday',
|
20
|
+
'wednesday',
|
21
|
+
'thursday',
|
22
|
+
'friday',
|
23
|
+
'saturday',
|
24
|
+
'sunday']}
|
25
|
+
|
26
|
+
# Set up the logger, parse CLI options and the YAML file.
|
27
|
+
def initialize
|
28
|
+
create_logger 'error'
|
29
|
+
@cli = Breaktime::CLI.new
|
30
|
+
@options = DEFAULT_OPTIONS
|
31
|
+
set_log_level @cli.options[:level]
|
32
|
+
|
33
|
+
parse_yaml_file
|
34
|
+
end
|
35
|
+
|
36
|
+
# Exit with a trollop message.
|
37
|
+
def die(message)
|
38
|
+
Trollop::die message
|
39
|
+
end
|
40
|
+
|
41
|
+
# Print out the gem motto and exit with the given exit code.
|
42
|
+
def say_goodbye(exit_code)
|
43
|
+
puts "\n\s\sBreaktime says, \"Have a break, have an unbranded chocolate snack.\""
|
44
|
+
exit exit_code
|
45
|
+
end
|
46
|
+
|
47
|
+
# Run the given mode.
|
48
|
+
#
|
49
|
+
# The mode is one of the command line modes (run with the --help flag).
|
50
|
+
def run_mode(mode)
|
51
|
+
command = Breaktime::Command.new @options['command'], @log
|
52
|
+
|
53
|
+
# Switch on CLI mode.
|
54
|
+
case mode
|
55
|
+
# Schedule the breaktime.
|
56
|
+
when "start"
|
57
|
+
@log.info { "When it's breaktime I'll run: `#{command.command}`" }
|
58
|
+
startd
|
59
|
+
|
60
|
+
# Stop a currently running daemonized process.
|
61
|
+
when "stop"
|
62
|
+
@log.info { "Stopping breaktime background process" }
|
63
|
+
stopd
|
64
|
+
say_goodbye Breaktime::EX_OK
|
65
|
+
|
66
|
+
# Open a dialog to notify the user about an impending screen break.
|
67
|
+
when "dialog"
|
68
|
+
@log.info { "Opening dialog" }
|
69
|
+
require 'dialog'
|
70
|
+
# Automatically loads green shoes window
|
71
|
+
|
72
|
+
# Run the command that will start the break.
|
73
|
+
when "now"
|
74
|
+
command.execute
|
75
|
+
|
76
|
+
# Unknown mode.
|
77
|
+
else
|
78
|
+
die "unknown mode #{mode.inspect}"
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Start the scheduler as a daemon.
|
84
|
+
#
|
85
|
+
# The process can be kept on top if the "daemonize" option is set to be false
|
86
|
+
# in the configuration YAML file.
|
87
|
+
#
|
88
|
+
# The logger output format is changed to add the time, as this is more
|
89
|
+
# helpful for debugging.
|
90
|
+
#
|
91
|
+
# Uses Dante for daemonizing.
|
92
|
+
def startd
|
93
|
+
dante_opts = {:daemonize => @options['daemonize'],
|
94
|
+
:pid_path => @options['pid_path'],
|
95
|
+
:log_path => @options['log_path']}
|
96
|
+
|
97
|
+
if dante_opts[:daemonize]
|
98
|
+
@log.info { "Starting daemon, PID file => #{dante_opts[:pid_path]}, log file => #{dante_opts[:log_path]}" }
|
99
|
+
end
|
100
|
+
|
101
|
+
schedule = Breaktime::Schedule.new(@options['interval'], @options['days'], @cli.options, @log)
|
102
|
+
|
103
|
+
Dante::Runner.new('breaktime').execute(dante_opts) do
|
104
|
+
schedule.start
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Stop the daemonized process, if it is running.
|
109
|
+
def stopd
|
110
|
+
dante_opts = {:kill => true,
|
111
|
+
:pid_path => @options['pid_path']}
|
112
|
+
Dante::Runner.new('breaktime').execute(dante_opts)
|
113
|
+
end
|
114
|
+
|
115
|
+
class << self
|
116
|
+
# Create a new Main object and run the mode given as a CLI parameter.
|
117
|
+
#
|
118
|
+
# Also rescue exceptions and display helpful messages.
|
119
|
+
#
|
120
|
+
# TODO: tidy this up
|
121
|
+
def start
|
122
|
+
main = self.new
|
123
|
+
main.log.debug { "Starting cli mode: #{main.cli.mode}" }
|
124
|
+
|
125
|
+
begin
|
126
|
+
main.run_mode main.cli.mode
|
127
|
+
# Exception handling and appropriate exit codes.
|
128
|
+
rescue Breaktime::LinuxWinManager::ManagerUnknown
|
129
|
+
main.log.fatal do
|
130
|
+
<<-FATAL
|
131
|
+
It looks like you're using Linux, but I'm unable to detect your window manager to determine how to start your screensaver.
|
132
|
+
|
133
|
+
To get round this problem, just specify a "command" in your $HOME/.breaktime.yml file, and this will be executed at the start of your break.
|
134
|
+
FATAL
|
135
|
+
end
|
136
|
+
exit Breaktime::EX_LINUX_WM_UNKNOWN
|
137
|
+
|
138
|
+
rescue Breaktime::Command::OSUnknown
|
139
|
+
main.log.fatal do
|
140
|
+
<<-FATAL
|
141
|
+
I can't work out which operating system you're using. If you think this is unreasonable then please let me know on Github.
|
142
|
+
|
143
|
+
To get round this problem in the meantime, just specify a "command" in your $HOME/.breaktime.yml file, and this will be executed at the start of your break.
|
144
|
+
FATAL
|
145
|
+
end
|
146
|
+
exit Breaktime::EX_OS_UNKNOWN
|
147
|
+
|
148
|
+
rescue Interrupt
|
149
|
+
main.log.warn { "Caught Control-C, shutting down..." }
|
150
|
+
main.say_goodbye Breaktime::EX_INTERRUPT
|
151
|
+
|
152
|
+
rescue SignalException => e
|
153
|
+
main.log.warn { "Caught signal #{e.message}, shutting down..." }
|
154
|
+
main.say_goodbye Breaktime::EX_SIGNAL
|
155
|
+
|
156
|
+
rescue SystemExit
|
157
|
+
raise
|
158
|
+
|
159
|
+
rescue Exception => e
|
160
|
+
main.log.fatal { "Unexpected exception {#{e.class.name}}: #{e.message}" }
|
161
|
+
main.log.debug { $!.backtrace.join("\n\t") }
|
162
|
+
exit Breaktime::EX_UNKNOWN
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
# Create a Log4r logger with the given log level.
|
171
|
+
#
|
172
|
+
# The logger prints to stdout by default, and spits out the level, time and
|
173
|
+
# message.
|
174
|
+
def create_logger(level)
|
175
|
+
@log = Logger.new 'breaktime'
|
176
|
+
outputter = Outputter.stdout
|
177
|
+
outputter.formatter = PatternFormatter.new(:pattern => "[%l] %d :: %m")
|
178
|
+
@log.outputters << outputter
|
179
|
+
@log.level = ERROR
|
180
|
+
end
|
181
|
+
|
182
|
+
# Overwrite the current logger level.
|
183
|
+
def set_log_level(level)
|
184
|
+
@log.level = self.class.const_get(level.upcase)
|
185
|
+
end
|
186
|
+
|
187
|
+
# Parse the YAML configuration file.
|
188
|
+
#
|
189
|
+
# Any errors in the parsing cause the program to exit, but a YAML file is not
|
190
|
+
# required - the defaults are used if it doesn't exist.
|
191
|
+
#
|
192
|
+
# TODO: separate into separate module/class?
|
193
|
+
def parse_yaml_file
|
194
|
+
@log.debug { "Configuration yaml file: #{@cli.options[:config]}" }
|
195
|
+
if File.exist? @cli.options[:config]
|
196
|
+
begin
|
197
|
+
@options.merge! YAML.load_file(@cli.options[:config])
|
198
|
+
rescue Exception => e
|
199
|
+
@log.debug { e.message }
|
200
|
+
Trollop::die :config, "must be a valid yaml file"
|
201
|
+
end
|
202
|
+
elsif @cli.options[:config] != Breaktime::CLI::DEFAULT_CONFIG
|
203
|
+
Trollop::die :config, "must be a valid yaml file"
|
204
|
+
else
|
205
|
+
@log.warn { "No configuration file found at #{Breaktime::CLI::DEFAULT_CONFIG}, using defaults" }
|
206
|
+
@log.info { "Check the README for info on creating a configuration file" }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rufus/scheduler'
|
2
|
+
|
3
|
+
# Schedule the running of the breaktime dialog and screensaver.
|
4
|
+
#
|
5
|
+
# Uses rufus-scheduler to schedule the task running.
|
6
|
+
class Breaktime::Schedule
|
7
|
+
def initialize(interval, days, cli_options, log)
|
8
|
+
@interval = interval.to_s + 'm'
|
9
|
+
@cli_options = cli_options
|
10
|
+
@days = days
|
11
|
+
@log = log
|
12
|
+
end
|
13
|
+
|
14
|
+
# Start the scheduler to run at a given interval.
|
15
|
+
#
|
16
|
+
# The interval (60 minutes by default) can be set in the configuration YAML
|
17
|
+
# file. The days at which breaktime runs can also be set.
|
18
|
+
#
|
19
|
+
# When it's time to run, `run_dialog()` is called.
|
20
|
+
def start
|
21
|
+
scheduler = Rufus::Scheduler.start_new
|
22
|
+
|
23
|
+
@log.info { "Taking a break every #{@interval}" }
|
24
|
+
|
25
|
+
scheduler.every @interval do
|
26
|
+
t = Time.now
|
27
|
+
# Check whether the current day is included in the list
|
28
|
+
if @days.detect {|d| t.send(d + '?')}
|
29
|
+
@log.info { "Starting 10 second warning..." }
|
30
|
+
run_dialog
|
31
|
+
else
|
32
|
+
@log.info { "Not running breaktime today" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
scheduler.join
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
# Open the countdown dialog, showing the user their break is about to start.
|
41
|
+
#
|
42
|
+
# Only if the process returns the EX_OK status code will the screensaver
|
43
|
+
# command run.
|
44
|
+
#
|
45
|
+
# This calls `exec_self()`, which runs same process name as the current
|
46
|
+
# command, but runs it as a `system()` call. It passes the same CLI arguments
|
47
|
+
# as those passed by the user.
|
48
|
+
def run_dialog
|
49
|
+
retcode_d = exec_self "dialog", :level => 'error'
|
50
|
+
|
51
|
+
case retcode_d
|
52
|
+
when Breaktime::EX_OK
|
53
|
+
@log.info { "Taking a break..." }
|
54
|
+
retcode_i = exec_self "now", :level => 'error'
|
55
|
+
if retcode_i == 0
|
56
|
+
@log.info { "Command returned" }
|
57
|
+
else
|
58
|
+
@log.error { "Failed to run breaktime with the `now` mode" }
|
59
|
+
end
|
60
|
+
when Breaktime::EX_BREAK_CANCELLED
|
61
|
+
@log.warn { "Cancelled screen break" }
|
62
|
+
else
|
63
|
+
@log.error { "Failed to run breaktime with the `dialog` mode" }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Execute the breaktime command with a given mode and CLI arguments.
|
68
|
+
#
|
69
|
+
# The exit code is returned.
|
70
|
+
def exec_self(mode, args = {})
|
71
|
+
arg_str = ''
|
72
|
+
@cli_options.merge(args).each do |n,v|
|
73
|
+
if v && !n.to_s.include?("_given")
|
74
|
+
arg_str += " --#{n} #{v}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
exec_str = "#{$PROGRAM_NAME} #{mode} #{arg_str}"
|
78
|
+
@log.debug { "Executing `#{exec_str}`" }
|
79
|
+
system exec_str
|
80
|
+
$?
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: breaktime
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Cairns
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: green_shoes
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.1.373
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.1.373
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: trollop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 2.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rufus-scheduler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.0.17
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.0.17
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: log4r
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.1.10
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.1.10
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: dante
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.1.5
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.1.5
|
94
|
+
description: Enforce screen breaks at regular intervals, when you want them
|
95
|
+
email:
|
96
|
+
- jon@joncairns.com
|
97
|
+
executables:
|
98
|
+
- breaktime
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- .gitignore
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/breaktime
|
108
|
+
- breaktime.gemspec
|
109
|
+
- lib/breaktime.rb
|
110
|
+
- lib/breaktime/cli.rb
|
111
|
+
- lib/breaktime/command.rb
|
112
|
+
- lib/breaktime/dialog.rb
|
113
|
+
- lib/breaktime/linux_win_manager.rb
|
114
|
+
- lib/breaktime/main.rb
|
115
|
+
- lib/breaktime/schedule.rb
|
116
|
+
- lib/breaktime/version.rb
|
117
|
+
homepage: https://github.com/joonty/breaktime
|
118
|
+
licenses: []
|
119
|
+
post_install_message:
|
120
|
+
rdoc_options: []
|
121
|
+
require_paths:
|
122
|
+
- lib
|
123
|
+
- lib/breaktime
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ! '>='
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
requirements: []
|
137
|
+
rubyforge_project:
|
138
|
+
rubygems_version: 1.8.24
|
139
|
+
signing_key:
|
140
|
+
specification_version: 3
|
141
|
+
summary: Breaktime
|
142
|
+
test_files: []
|