winever 0.1.0
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 +66 -0
- data/Rakefile +1 -0
- data/bin/winever +30 -0
- data/lib/winever.rb +20 -0
- data/lib/winever/command_line.rb +54 -0
- data/lib/winever/cron_entry.rb +58 -0
- data/lib/winever/setup_schedule.rb +13 -0
- data/lib/winever/task_manager.rb +158 -0
- data/lib/winever/version.rb +3 -0
- data/lib/winever/whenever_interface.rb +64 -0
- data/winever.gemspec +26 -0
- metadata +132 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Maxime Handfield Lapointe
|
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,66 @@
|
|
1
|
+
# Winever
|
2
|
+
|
3
|
+
Winever is a gem that adds features to the [whenever](https://github.com/javan/whenever) gem, making it also compatible
|
4
|
+
with Windows, without breaking anything when using Whenever only.
|
5
|
+
|
6
|
+
Winever creates and removes tasks in the Windows task scheduler using [win32-taskscheduler](https://github.com/djberg96/win32-taskscheduler).
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'winever'
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
Winever adds the command `winever` which behaves similarly to `whenever`.
|
25
|
+
|
26
|
+
You can use `winever` without parameters to list a "cron file" using an internal syntax. It will tell you which of the
|
27
|
+
jobs of your schedule are supported and which ones aren't. Just like with Whenever, you can use `winever -i` to install/update
|
28
|
+
the jobs on your Windows machine and `winever -c` to remove them.
|
29
|
+
|
30
|
+
Winever creates tasks in Windows' task scheduler. In order for a job to be compatible with Winever, it needs to have an
|
31
|
+
additional option: task_name. Note that this task_name will have an identifier (similar to Whenever's comment in the crontab)
|
32
|
+
added as suffix to enable Winever to remove old tasks when needed.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
every 1.day, at: '00:30 am' do
|
36
|
+
rake 'my_backup_task', :task_name => 'MyAppBackup'
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
If you define new job_types in your schedule. Then you will need to define them differently for Winever. To do so, first add
|
41
|
+
`require 'winever'` to the top of your schedule file. This will add the function `winever?` to your schedule, which you can
|
42
|
+
use to define some tasks only for Windows or for Linux, and to define a job_type differently for Whenever and for Winever.
|
43
|
+
This is the basic line for create a job_type for Winever.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
if winever?
|
47
|
+
job_type :something, ":task_folder|:task_name|:path|command_you_want_executed_here :output"
|
48
|
+
else
|
49
|
+
job_type :something, "cd :path && command_you_want_executed_here :output"
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
The pipes (|) are important, so make sure not to remove any.
|
54
|
+
If your task doesn't need to be run in the folder of your application (like the existing job_type "command" of Whenever),
|
55
|
+
then remove the :path (leaving the pipes around it intact).
|
56
|
+
|
57
|
+
As of right now the only type of schedule that is supported are the daily ones (run once per day, at a specific time, every day).
|
58
|
+
Pull requests welcomed to add more, cron_entry.rb should be the only file needing edit for that.
|
59
|
+
|
60
|
+
## Contributing
|
61
|
+
|
62
|
+
1. Fork it
|
63
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
64
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
65
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
66
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/winever
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'winever'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: whenever [options]"
|
10
|
+
opts.on('-i', '--update [identifier]', 'Default: full path to schedule.rb file') do |identifier|
|
11
|
+
options[:update] = true
|
12
|
+
options[:identifier] = identifier if identifier
|
13
|
+
end
|
14
|
+
opts.on('-c', '--clear [identifier]') do |identifier|
|
15
|
+
options[:clear] = true
|
16
|
+
options[:identifier] = identifier if identifier
|
17
|
+
end
|
18
|
+
opts.on('-s', '--set [variables]', 'Example: --set \'environment=staging&path=/my/sweet/path\'') do |set|
|
19
|
+
options[:set] = set if set
|
20
|
+
end
|
21
|
+
opts.on('-f', '--load-file [schedule file]', 'Default: config/schedule.rb') do |file|
|
22
|
+
options[:file] = file if file
|
23
|
+
end
|
24
|
+
opts.on('-k', '--cut [lines]', 'Cut lines from the top of the cronfile') do |lines|
|
25
|
+
options[:cut] = lines.to_i if lines
|
26
|
+
end
|
27
|
+
opts.on('-v', '--version') { puts "Winever v#{Winever::VERSION}"; exit(0) }
|
28
|
+
end.parse!
|
29
|
+
|
30
|
+
Winever::CommandLine.execute(options)
|
data/lib/winever.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'winever/version'
|
2
|
+
require 'whenever'
|
3
|
+
|
4
|
+
# A very tiny monkey patch of whatever, adding a function useable in the schedule to know if this is going through winever.
|
5
|
+
module Whenever
|
6
|
+
class JobList
|
7
|
+
# We are running from winever
|
8
|
+
def winever?
|
9
|
+
Winever::WheneverInterface.run_from_winever?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
module Winever
|
16
|
+
autoload :CommandLine, 'winever/command_line'
|
17
|
+
autoload :CronEntry, 'winever/cron_entry'
|
18
|
+
autoload :TaskManager, 'winever/task_manager'
|
19
|
+
autoload :WheneverInterface, 'winever/whenever_interface'
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Winever
|
2
|
+
class CommandLine
|
3
|
+
def self.execute options={}
|
4
|
+
new(options).run
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize options={}
|
8
|
+
@options = options
|
9
|
+
|
10
|
+
@options[:file] ||= 'config/schedule.rb'
|
11
|
+
@options[:cut] ||= 0
|
12
|
+
@options[:identifier] ||= default_identifier
|
13
|
+
|
14
|
+
unless File.exists?(@options[:file])
|
15
|
+
warn("[fail] Can't find file: #{@options[:file]}")
|
16
|
+
exit(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
if [@options[:update], @options[:clear]].compact.length > 1
|
20
|
+
warn("[fail] Can only update or clear. Choose one.")
|
21
|
+
exit(1)
|
22
|
+
end
|
23
|
+
|
24
|
+
unless @options[:cut].to_s =~ /[0-9]*/
|
25
|
+
warn("[fail] Can't cut negative lines from the crontab #{options[:cut]}")
|
26
|
+
exit(1)
|
27
|
+
end
|
28
|
+
@options[:cut] = @options[:cut].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def run
|
33
|
+
if @options[:update]
|
34
|
+
Winever::TaskManager.update_tasks(@options)
|
35
|
+
elsif @options[:clear]
|
36
|
+
Winever::TaskManager.clear_tasks(@options)
|
37
|
+
else
|
38
|
+
puts Winever::WheneverInterface.cron(@options)
|
39
|
+
puts "## [message] Above is your schedule file converted to cron-winever syntax; your crontab file /scheduled tasks were not updated."
|
40
|
+
puts "## [message] Run `winever --help' for more options."
|
41
|
+
exit(0)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#protected
|
46
|
+
|
47
|
+
def default_identifier
|
48
|
+
File.expand_path(@options[:file])
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Winever
|
2
|
+
class CronEntry
|
3
|
+
attr_accessor :cron_time, :task_folder, :task_name, :working_directory, :parameters, :cron_line
|
4
|
+
|
5
|
+
def self.from_cron_output cron_output, include_invalid=false
|
6
|
+
entries = cron_output.split("\n").select(&:present?).map{|o| new(o)}
|
7
|
+
entries = entries.select(&:valid?) unless include_invalid
|
8
|
+
entries
|
9
|
+
end
|
10
|
+
|
11
|
+
def triggers
|
12
|
+
# For now, we don't support anything other than specific time.
|
13
|
+
# But it is possible to handle almost all cron schedule options in the task scheduler of Windows.
|
14
|
+
# It doesn't help that win32-taskscheduler also seems to only support one trigger per task.
|
15
|
+
return [] unless valid_triggers?
|
16
|
+
|
17
|
+
cron_minute, cron_hour, cron_day, cron_month, cron_dow = @cron_time_parts
|
18
|
+
trigger = {
|
19
|
+
:start_year => Date.today.year,
|
20
|
+
:start_month => Date.today.month,
|
21
|
+
:start_day => Date.today.day,
|
22
|
+
:start_hour => cron_hour.to_i,
|
23
|
+
:start_minute => cron_minute.to_i,
|
24
|
+
:trigger_type => Win32::TaskScheduler::TASK_TIME_TRIGGER_DAILY
|
25
|
+
}
|
26
|
+
|
27
|
+
[trigger]
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(cron_line)
|
31
|
+
@cron_line = cron_line
|
32
|
+
@cron_parts = cron_line.split("|", 5)
|
33
|
+
@cron_time, @task_folder, @task_name, @working_directory, @parameters = @cron_parts
|
34
|
+
@cron_time_parts = @cron_time.split(/ +/)
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid?
|
38
|
+
invalid_reason.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def valid_triggers?
|
42
|
+
return false if @cron_time_parts.length < 5
|
43
|
+
cron_minute, cron_hour, cron_day, cron_month, cron_dow = @cron_time_parts
|
44
|
+
|
45
|
+
return false if [cron_day, cron_month, cron_dow].detect{|v| v != '*'}
|
46
|
+
return false if [cron_minute, cron_hour].detect{|v| (v =~ /^\d+$/).nil? }
|
47
|
+
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def invalid_reason
|
52
|
+
return "Doesn't match the Winever format" unless @cron_parts.length == 5
|
53
|
+
return "Doesn't have a task_name specified" unless @task_name.present?
|
54
|
+
return "The schedule is either invalid or not supported" unless valid_triggers?
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
if winever?
|
3
|
+
set :job_template, "|:job"
|
4
|
+
|
5
|
+
# Overwrite to put tasks in a different subfolder of the task scheduler.
|
6
|
+
# Right now, anything other than \\ will break clear_tasks, so don't change folder for now.
|
7
|
+
set :task_folder, "\\"
|
8
|
+
|
9
|
+
job_type :command, ":task_folder|:task_name||:task :output"
|
10
|
+
job_type :rake, ":task_folder|:task_name|:path|:bundle_command rake :task --silent :environment_variable=:environment :output"
|
11
|
+
job_type :script, ":task_folder|:task_name|:path|:bundle_command script/:task :environment_variable=:environment :output"
|
12
|
+
job_type :runner, ":task_folder|:task_name|:path|:runner_command -e :environment ':task' :output"
|
13
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Winever
|
2
|
+
class TaskManager
|
3
|
+
def self.has_task_scheduler?
|
4
|
+
return @has_task_scheduler unless @has_task_scheduler.nil?
|
5
|
+
begin
|
6
|
+
require 'win32/taskscheduler'
|
7
|
+
@has_task_scheduler = true
|
8
|
+
rescue LoadError => e
|
9
|
+
@has_task_scheduler = false
|
10
|
+
end
|
11
|
+
@has_task_scheduler
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_task_scheduler?
|
15
|
+
self.class.has_task_scheduler?
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.clear_tasks options={}
|
19
|
+
new(options).clear_tasks_except
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.update_tasks options={}
|
23
|
+
new(options).update_tasks
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize options={}
|
27
|
+
if !has_task_scheduler?
|
28
|
+
raise "Cannot use win32/taskscheduler on this system. Are you on windows?"
|
29
|
+
end
|
30
|
+
|
31
|
+
@options = options
|
32
|
+
end
|
33
|
+
|
34
|
+
def password
|
35
|
+
return @password.presence if @password
|
36
|
+
require 'highline/import'
|
37
|
+
prompt = <<-PRMP.gsub(/^ +/, '')
|
38
|
+
To setup tasks correctly, the password of the current user account is needed.
|
39
|
+
You can leave it empty, but without the password, the task will only be run the user is logged on and will open a black
|
40
|
+
console window while running.
|
41
|
+
You can manually go edit the scheduled task to add the password manually if you prefer not to give it to Winever, but you will need to go do that every time you edit the tasks through Winever, for each task.
|
42
|
+
Enter the password of the current user (or just press enter to skip):
|
43
|
+
PRMP
|
44
|
+
|
45
|
+
pw = ask(prompt){|q| q.echo = false}
|
46
|
+
while pw.present? && !validate_password(pw)
|
47
|
+
prompt = <<-PRMP.gsub(/^ +/, '')
|
48
|
+
Invalid password entered.
|
49
|
+
Enter the password of the current user (or just press enter to skip):
|
50
|
+
PRMP
|
51
|
+
pw = ask(prompt){|q| q.echo = false}
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
#TODO get the password somehow.
|
56
|
+
# require File.expand_path('../../extensions/password', __FILE__)
|
57
|
+
# password = Password.ask("Enter password for current user account of the machine to setup tasks: ")
|
58
|
+
# validate_password(password)
|
59
|
+
|
60
|
+
@password = pw
|
61
|
+
pw.presence
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_tasks
|
65
|
+
cron_entries = Winever::WheneverInterface.valid_cron_entries(@options)
|
66
|
+
|
67
|
+
created_task_names = []
|
68
|
+
cron_entries.each do |cron_entry|
|
69
|
+
created_task_names << create_task(cron_entry)
|
70
|
+
end
|
71
|
+
created_task_names
|
72
|
+
end
|
73
|
+
|
74
|
+
def update_tasks
|
75
|
+
task_names = create_tasks
|
76
|
+
clear_tasks_except(task_names)
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear_tasks_except keep_tasks=[]
|
80
|
+
ts = Win32::TaskScheduler.new
|
81
|
+
task_names = ts.tasks.select{|tn| tn.end_with?('.' + identifier)}
|
82
|
+
task_names = task_names.reject{|tn| keep_tasks.include?(tn)}
|
83
|
+
|
84
|
+
task_names.each{|tn| ts.delete(tn)}
|
85
|
+
end
|
86
|
+
|
87
|
+
def create_task cron_entry
|
88
|
+
task_name = generate_task_name(cron_entry.task_name)
|
89
|
+
|
90
|
+
# Replacing the /dev/null by NUL
|
91
|
+
parameters = cron_entry.parameters.gsub(/([\s'"])\/dev\/null([\s'"])/, '\1NUL\2')
|
92
|
+
|
93
|
+
pw = password
|
94
|
+
trigger = cron_entry.triggers.first
|
95
|
+
work_directory = cron_entry.working_directory
|
96
|
+
|
97
|
+
ts = Win32::TaskScheduler.new(nil, nil, cron_entry.task_folder, true)
|
98
|
+
begin
|
99
|
+
ts.password = pw
|
100
|
+
ts.new_work_item(task_name, trigger)
|
101
|
+
ts.application_name = 'cmd'
|
102
|
+
ts.parameters = '/C ' + parameters
|
103
|
+
ts.working_directory = work_directory
|
104
|
+
ts.activate(task_name)
|
105
|
+
rescue
|
106
|
+
raise 'Failed at setting the task up. It might have been partially created/updated. This most likely means a bad password was entered.'
|
107
|
+
end
|
108
|
+
|
109
|
+
task_name
|
110
|
+
end
|
111
|
+
|
112
|
+
def generate_task_name task_name
|
113
|
+
"#{task_name}.#{identifier}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def identifier
|
117
|
+
# Removing the characters blocked by the windows file system. The single quote is just for simplicity.
|
118
|
+
iden = @options[:identifier].gsub(/[:\/\\<>:"|?*']/, '_')
|
119
|
+
raise 'Identifier must contain at least one letter or number.' unless iden =~ /\w/
|
120
|
+
iden
|
121
|
+
end
|
122
|
+
|
123
|
+
def validate_password password
|
124
|
+
# Validate a password by trying to create a task with it. If it fails, then the password is wrong.
|
125
|
+
# Will delete the created task after.
|
126
|
+
ts = Win32::TaskScheduler.new
|
127
|
+
base_test_task_name = test_task_name = "Winever_test_task"
|
128
|
+
i = 0
|
129
|
+
while ts.exists?(test_task_name)
|
130
|
+
i += 1
|
131
|
+
test_task_name = "#{base_test_task_name}_#{i}"
|
132
|
+
end
|
133
|
+
|
134
|
+
trigger = { :start_year => 2000,
|
135
|
+
:start_month => 6,
|
136
|
+
:start_day => 12,
|
137
|
+
:start_hour => 13,
|
138
|
+
:start_minute => 17,
|
139
|
+
:trigger_type => Win32::TaskScheduler::TASK_TIME_TRIGGER_ONCE}
|
140
|
+
|
141
|
+
ts.new_work_item(test_task_name, trigger)
|
142
|
+
valid = false
|
143
|
+
begin
|
144
|
+
ts.password = password
|
145
|
+
ts.application_name = "cmd"
|
146
|
+
valid = true
|
147
|
+
rescue
|
148
|
+
ts.password = nil
|
149
|
+
valid = false
|
150
|
+
end
|
151
|
+
ts.delete(test_task_name)
|
152
|
+
|
153
|
+
return valid
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Winever
|
2
|
+
module WheneverInterface
|
3
|
+
def self.run_from_winever?
|
4
|
+
@run_from_winever || false
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.raw_cron options={}
|
8
|
+
# The output of whenever with the custom job_types and job_template.
|
9
|
+
options[:file] ||= 'config/schedule.rb'
|
10
|
+
options[:cut] ||= 0
|
11
|
+
options[:identifier] ||= File.expand_path(options[:file])
|
12
|
+
|
13
|
+
schedule = if options[:string]
|
14
|
+
options[:string]
|
15
|
+
elsif options[:file]
|
16
|
+
File.read(options[:file])
|
17
|
+
end
|
18
|
+
|
19
|
+
# Prepending out own setup for the schedule to override the existing job_types and job_template.
|
20
|
+
options[:string] = File.read(File.dirname(__FILE__)+"/setup_schedule.rb") + "\n" + schedule
|
21
|
+
|
22
|
+
@run_from_winever = true
|
23
|
+
output = Whenever.cron(options)
|
24
|
+
@run_from_winever = false
|
25
|
+
output
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.valid_cron_entries options={}
|
29
|
+
# Array of CronEntry containing only the entry that we support.
|
30
|
+
Winever::CronEntry.from_cron_output(raw_cron(options))
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.all_cron_entries options={}
|
34
|
+
# Array of CronEntry containing only the entry that we support.
|
35
|
+
Winever::CronEntry.from_cron_output(raw_cron(options), true)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.cron options={}
|
39
|
+
entries = all_cron_entries(options)
|
40
|
+
valid_entries = entries.select(&:valid?)
|
41
|
+
invalid_entries = entries.reject(&:valid?)
|
42
|
+
|
43
|
+
|
44
|
+
output = "# Valid tasks for Winever in internal format:\n"
|
45
|
+
if valid_entries.present?
|
46
|
+
output << valid_entries.map(&:cron_line).join("\n\n")
|
47
|
+
else
|
48
|
+
output << "No valid entries"
|
49
|
+
end
|
50
|
+
output << "\n\n"
|
51
|
+
|
52
|
+
if invalid_entries.present?
|
53
|
+
output << "\n# Invalid entries for Winever in internal format:\n"
|
54
|
+
invalid_entries.each do |invalid_entry|
|
55
|
+
output << "# #{invalid_entry.invalid_reason}\n"
|
56
|
+
output << "#{invalid_entry.cron_line}\n\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
output
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
data/winever.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'winever/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "winever"
|
8
|
+
spec.version = Winever::VERSION
|
9
|
+
spec.authors = ["Maxime Handfield Lapointe"]
|
10
|
+
spec.email = ["hunter_spawn@hotmail.com"]
|
11
|
+
spec.description = %q{Make it possible to use the Whenever gem's clean ruby syntax for writing and deploying tasks in the windows scheduler, using the same schedule file.}
|
12
|
+
spec.summary = %q{Make it possible to use the Whenever gem on Windows.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "whenever", ">= 0.9.1"
|
22
|
+
spec.add_dependency "highline", ">= 0.5.0"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: winever
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Maxime Handfield Lapointe
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: whenever
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.1
|
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: 0.9.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: highline
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.5.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: 0.5.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Make it possible to use the Whenever gem's clean ruby syntax for writing
|
79
|
+
and deploying tasks in the windows scheduler, using the same schedule file.
|
80
|
+
email:
|
81
|
+
- hunter_spawn@hotmail.com
|
82
|
+
executables:
|
83
|
+
- winever
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files: []
|
86
|
+
files:
|
87
|
+
- .gitignore
|
88
|
+
- Gemfile
|
89
|
+
- LICENSE.txt
|
90
|
+
- README.md
|
91
|
+
- Rakefile
|
92
|
+
- bin/winever
|
93
|
+
- lib/winever.rb
|
94
|
+
- lib/winever/command_line.rb
|
95
|
+
- lib/winever/cron_entry.rb
|
96
|
+
- lib/winever/setup_schedule.rb
|
97
|
+
- lib/winever/task_manager.rb
|
98
|
+
- lib/winever/version.rb
|
99
|
+
- lib/winever/whenever_interface.rb
|
100
|
+
- winever.gemspec
|
101
|
+
homepage: ''
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
hash: -2189449078382166788
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -2189449078382166788
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.8.25
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Make it possible to use the Whenever gem on Windows.
|
132
|
+
test_files: []
|