schedule_job 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aa14b51b198289543636f7048935e3599a08d5eb2920a2bb7e67b80d259f19d
4
- data.tar.gz: 8841e4a6ec99c02c3485927d4ba6e4335a0347b52bba332fc131fff727225e4f
3
+ metadata.gz: 887f7a67ad740ea939e3c585534e820ad03d85695d07a74b26390c4300a8cb04
4
+ data.tar.gz: d61192e8ac1ba8b74f62de780b4b000d4b235aeb13f202d24e374f381f7c65ba
5
5
  SHA512:
6
- metadata.gz: 0f7832e1cc148800389da6b5f6ff3c053878cc930496f578e37af46c665f5dcb708db558b8220568c35c6ba5363e3a16351ee3453d65503cc494b1ed3b19c61d
7
- data.tar.gz: c7d18b320759e7dccac481d1b4b9af06e91c09b0954d80e53650d7112ff53e202b4ed4c02ebb23039d4a634b53de9800aad9f0d1517fd60786d833d353af38e6
6
+ metadata.gz: 86af048f9a4e1c2e50f9c7a63ffbe483fd5c8ffbda9ec521b5c7d2c39a8a6228367e239f0ab347d3c681a2fbbf03918691e3cbf95d67cbf5c256b8439e2dbfe3
7
+ data.tar.gz: 7866e34e5591ed82159cc81a268166562f07e50033998cee9ff0000baeafd92772df00a7ed3953a6e50f8d627f64fb636898bd432fe460f7099a958f7c078ae5
data/Gemfile CHANGED
@@ -4,9 +4,6 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem "citrus"
7
- # gem "whenever"
8
7
  gem "cronex"
9
8
  gem "parse-cron"
10
- gem "activesupport"
11
- # gem "treetop"
12
- # gem "polyglot"
9
+ gem "activesupport"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- schedule_job (1.0.0)
4
+ schedule_job (1.0.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,15 +1,89 @@
1
- # Schedule
1
+ # ScheduleJob
2
2
 
3
3
  schedule is a frontend around crontab to add/remove cron jobs from user cron tables.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```
8
- gem install schedule_job
8
+ ~ ❯ gem install schedule_job
9
+ Fetching schedule_job-1.0.1.gem
10
+ Successfully installed schedule_job-1.0.1
11
+ Parsing documentation for schedule_job-1.0.1
12
+ Installing ri documentation for schedule_job-1.0.1
13
+ Done installing documentation for schedule_job after 0 seconds
9
14
  ```
10
15
 
11
16
  ## Usage
12
17
 
18
+ Example usage:
19
+ ```
20
+ ~ ❯ schedule --help
21
+ Usage: schedule [options] command
22
+ -d, --dryrun Report what would happen but do not install the scheduled job.
23
+ -l, --list List installed cron jobs.
24
+ -r, --rm JOB_ID Remove the specified job id as indicated by --list
25
+ -u, --user USER User that the crontab belongs to.
26
+ -e, --every DURATION Run command every DURATION units of time (valid suffixes are m, h, d, M). DURATION may also be one of the special keywords: reboot, year, month, week, day, hour
27
+ For example:
28
+ --every 10m # every 10 minutes
29
+ --every 5h # every 5 hours
30
+ --every 2d # every 2 days
31
+ --every 3M # every 3 months
32
+
33
+ Special durations:
34
+ --every reboot # after every reboot
35
+ --every year # every year
36
+ --every month # every month
37
+ --every week # every week
38
+ --every day # every day
39
+ --every hour # every hour
40
+
41
+ -c, --cron CRON Run command on the given cron schedule.
42
+ For example:
43
+ --cron "*/5 15 * * 1-5" # Every 5 minutes, at 3:00 PM, Monday through Friday
44
+ --cron "0 0/30 8-9 5,20 * ?" # Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
45
+
46
+ ~ ❯ schedule -l
47
+ ~ ❯ schedule -d -e 10m backup.sh
48
+ Scheduling: backup.sh Every 10 minutes
49
+ Next three runs:
50
+ 1. 2021-11-01 21:50:00 -0500
51
+ 2. 2021-11-01 22:00:00 -0500
52
+ 3. 2021-11-01 22:10:00 -0500
53
+ ~ ❯ schedule -l
54
+ Jobs
55
+ 1. backup.sh Every 10 minutes
56
+ ~ ❯ crontab -l
57
+ */10 * * * * backup.sh
58
+ ~ ❯ schedule -e 3M quarterly_backup.sh
59
+ Scheduling: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
60
+ Next three runs:
61
+ 1. 2022-01-01 21:50:00 -0600
62
+ 2. 2022-04-01 21:50:00 -0500
63
+ 3. 2022-07-01 21:50:00 -0500
64
+ ~ ❯ schedule -l
65
+ Jobs
66
+ 1. backup.sh Every 10 minutes
67
+ 2. quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
68
+ ~ ❯ crontab -l
69
+ */10 * * * * backup.sh
70
+ 50 21 1 */3 * quarterly_backup.sh
71
+ ~ ❯ schedule --dryrun --rm 1
72
+ Would remove: backup.sh Every 10 minutes
73
+ ~ ❯ schedule --dryrun --rm 2
74
+ Would remove: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
75
+ ~ ❯ schedule --rm 1
76
+ Removing: backup.sh Every 10 minutes
77
+ ~ ❯ schedule -l
78
+ Jobs
79
+ 1. quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
80
+ ~ ❯ schedule --rm 1
81
+ Removing: quarterly_backup.sh At 9:50 PM, on day 1 of the month, every 3 months
82
+ ~ ❯ schedule -l
83
+ ~ ❯ crontab -l
84
+ ~ ❯
85
+ ```
86
+
13
87
  ## License
14
88
 
15
89
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/bin/schedule CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "schedule"
3
+ require "schedule_job"
4
4
 
5
5
  def main
6
- Schedule::Cli.run(ARGV)
6
+ ScheduleJob::Cli.run(ARGV)
7
7
  end
8
8
 
9
9
  main
@@ -1,8 +1,6 @@
1
1
  require "optparse"
2
2
 
3
- # schedule --every 10m "my_command --foo --bar"
4
-
5
- module Schedule
3
+ module ScheduleJob
6
4
  class Cli
7
5
  def self.run(argv = ARGV)
8
6
  cli = Cli.new
@@ -32,20 +30,28 @@ module Schedule
32
30
  options[:crontab_user] = user
33
31
  end
34
32
 
35
- opts.on("-e", "--every DURATION", "Run command every DURATION units of time.
33
+ opts.on("-e", "--every DURATION", "Run command every DURATION units of time (valid suffixes are m, h, d, M). DURATION may also be one of the special keywords: reboot, year, month, week, day, hour
36
34
  For example:
37
- --every 10m # meaning, every 10 minutes
38
- --every 5h # meaning, every 5 hours
39
- --every 2d # meaning, every 2 days
40
- --every 3M # meaning, every 3 months
35
+ --every 10m # every 10 minutes
36
+ --every 5h # every 5 hours
37
+ --every 2d # every 2 days
38
+ --every 3M # every 3 months
39
+
40
+ Special durations:
41
+ --every reboot # after every reboot
42
+ --every year # every year
43
+ --every month # every month
44
+ --every week # every week
45
+ --every day # every day
46
+ --every hour # every hour
41
47
  ") do |every|
42
48
  options[:every] = every
43
49
  end
44
50
 
45
51
  opts.on("-c", "--cron CRON", "Run command on the given cron schedule.
46
52
  For example:
47
- --cron \"*/5 15 * * 1-5\" # meaning, Every 5 minutes, at 3:00 PM, Monday through Friday
48
- --cron \"0 0/30 8-9 5,20 * ?\" # meaning, Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
53
+ --cron \"*/5 15 * * 1-5\" # Every 5 minutes, at 3:00 PM, Monday through Friday
54
+ --cron \"0 0/30 8-9 5,20 * ?\" # Every 30 minutes, between 8:00 AM and 9:59 AM, on day 5 and 20 of the month
49
55
  ") do |cron_schedule|
50
56
  options[:cron] = cron_schedule
51
57
  end
@@ -63,6 +69,8 @@ module Schedule
63
69
  remove_job(args)
64
70
  when args[:cron] || args[:every] # write jobs
65
71
  install_job(args)
72
+ else
73
+ puts "No parameters specified. Please specify one of: --every, --cron, --list, or --rm"
66
74
  end
67
75
  end
68
76
 
@@ -90,13 +98,14 @@ module Schedule
90
98
  Cron::Job.new(cron_schedule, command)
91
99
  when args[:every]
92
100
  duration = args[:every]
93
- match = duration.match(/(\d+)(m|h|d|M)/)
94
- if match
101
+ if match = duration.match(/(\d+)(m|h|d|M)/)
95
102
  qty = match[1].to_i
96
103
  unit_of_time = match[2].to_s
97
104
  Cron::Job.every(qty, unit_of_time, command)
105
+ elsif duration.match(/reboot|year|month|week|day|hour/)
106
+ Cron::Job.every_simple_duration(duration, command)
98
107
  else
99
- puts "'#{duration}' is an invalid duration. The duration must be specified as: integer followed immediately by m (minutes), h (hours), d (days), M (months) (e.g. 10m)"
108
+ puts "'#{duration}' is an invalid duration. The duration must be specified as either (1) integer followed immediately by m (minutes), h (hours), d (days), M (months) (e.g. 10m) or (2) reboot, year, month, week, day, hour"
100
109
  exit(1)
101
110
  end
102
111
  end
File without changes
@@ -8,7 +8,7 @@ require "stringio"
8
8
 
9
9
  require_relative "./cron_parser"
10
10
 
11
- module Schedule
11
+ module ScheduleJob
12
12
  module Cron
13
13
 
14
14
  class EnvironmentVar
@@ -50,12 +50,6 @@ module Schedule
50
50
 
51
51
  raise("Unable to read crontab: #{error_output}") if !exit_status.success? && !no_crontab
52
52
 
53
- # puts "read_crontab()"
54
- # puts "stdout:"
55
- # puts stdout
56
- # puts "stderr:"
57
- # puts stderr
58
-
59
53
  crontab_output
60
54
  end
61
55
 
@@ -63,16 +57,8 @@ module Schedule
63
57
  def parse_crontab(user_crontab)
64
58
  parser = TableParser.new(user_crontab)
65
59
 
66
- # user_crontab.each_line do |line|
67
- # puts line
68
- # puts "valid? #{LineParser.valid?(line)}"
69
- # puts LineParser.parse(line)
70
- # end
71
-
72
60
  return [], [] unless parser.valid?
73
61
 
74
- # puts "valid!"
75
-
76
62
  environment_vars = parser.environment_vars&.map do |env_directive|
77
63
  name = env_directive[:var].to_s
78
64
  expr = env_directive[:expr].to_s
@@ -108,9 +94,9 @@ module Schedule
108
94
 
109
95
  def install_cron_job(job)
110
96
  job_spec = job.specification
111
- # puts "Installing new cron job: #{job_spec}"
112
97
 
113
98
  new_crontab = [read_crontab(@user).strip, job_spec.strip].reject(&:empty?).join("\n")
99
+ new_crontab << "\n" # add a trailing newline
114
100
  write_crontab(new_crontab)
115
101
  end
116
102
 
@@ -135,21 +121,12 @@ module Schedule
135
121
  end
136
122
 
137
123
  def write_crontab(new_crontab, user = @user)
124
+ # overwrite crontab interactively, per https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job
138
125
  command = ["crontab"]
139
126
  command << "-u #{user}" if user
140
127
  command << "-"
141
128
  command = command.join(" ")
142
129
 
143
- # command = "(crontab -l ; echo \"#{job_spec}\") | crontab -" # add new job to bottom of crontab, per https://stackoverflow.com/questions/610839/how-can-i-programmatically-create-a-new-cron-job
144
- # puts "writing new crontab:"
145
- # puts new_crontab
146
- # puts "*" * 80
147
-
148
- # puts "write_crontab:"
149
- # puts "command: #{command}"
150
- # puts "new crontab:"
151
- # puts new_crontab
152
-
153
130
  stdout, stderr, exit_status = Open3.capture3(command, stdin_data: new_crontab)
154
131
  crontab_output = stdout
155
132
  error_output = stderr
@@ -196,6 +173,25 @@ module Schedule
196
173
  self.new(schedule_spec, command)
197
174
  end
198
175
 
176
+ # duration is one of: reboot, year, month, week, day, hour
177
+ def self.every_simple_duration(duration, command)
178
+ schedule_spec = case duration
179
+ when "reboot"
180
+ "@reboot"
181
+ when "year"
182
+ "@yearly"
183
+ when "month"
184
+ "@monthly"
185
+ when "week"
186
+ "@weekly"
187
+ when "day"
188
+ "@daily"
189
+ when "hour"
190
+ "@hourly"
191
+ end
192
+ self.new(schedule_spec, command)
193
+ end
194
+
199
195
  attr_reader :schedule_spec
200
196
  attr_reader :line_number
201
197
 
@@ -15,13 +15,9 @@ module Citrus
15
15
  end
16
16
  end
17
17
 
18
- Citrus.require("schedule/cron")
18
+ Citrus.require("schedule_job/cron")
19
19
 
20
- # require "polyglot"
21
- # require "treetop"
22
- # require "schedule/cron.treetop"
23
-
24
- module Schedule
20
+ module ScheduleJob
25
21
  module Cron
26
22
  Grammar = ScheduleCronParser
27
23
 
@@ -34,7 +30,6 @@ module Schedule
34
30
 
35
31
  def self.parse(user_crontab_string)
36
32
  Grammar.parse(user_crontab_string, root: :user_crontab)
37
- # ::CrontabParser.new.parse(user_crontab_string, root: :user_crontab)
38
33
  end
39
34
 
40
35
  def initialize(user_crontab_string)
@@ -55,17 +50,10 @@ module Schedule
55
50
 
56
51
  def environment_vars
57
52
  @user_crontab&.capture(:environment)&.captures(:directive)
58
- # puts @user_crontab.methods.sort.inspect
59
- # puts @user_crontab.inspect
60
- # puts "*" * 80
61
- # puts @user_crontab.environment_spec.inspect
62
- # exit()
63
- # @user_crontab&.environment&.directive
64
53
  end
65
54
 
66
55
  def job_specs
67
56
  @user_crontab&.capture(:jobspecs)&.captures(:jobspec)
68
- # @user_crontab&.jobspecs&.jobspec
69
57
  end
70
58
  end
71
59
 
@@ -78,7 +66,6 @@ module Schedule
78
66
 
79
67
  def self.parse(cron_line)
80
68
  Grammar.parse(cron_line, root: :jobspec, consume: false)
81
- # ::CrontabParser.new.parse(cron_line, root: :jobspec, consume_all_input: false)
82
69
  end
83
70
  end
84
71
  end
@@ -0,0 +1,3 @@
1
+ module ScheduleJob
2
+ VERSION = "1.0.5"
3
+ end
data/lib/schedule_job.rb CHANGED
@@ -1,9 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
- require "schedule/cli"
5
- require "schedule/cron"
6
-
7
- module ScheduleJob
8
- VERSION = "1.0.0"
9
- end
4
+ require "schedule_job/cli"
5
+ require "schedule_job/cron"
data/schedule_job.gemspec CHANGED
@@ -1,6 +1,8 @@
1
+ require_relative "lib/schedule_job/version"
2
+
1
3
  Gem::Specification.new do |spec|
2
4
  spec.name = "schedule_job"
3
- spec.version = "1.0.0"
5
+ spec.version = ScheduleJob::VERSION
4
6
  spec.authors = ["David Ellis"]
5
7
  spec.email = ["david@conquerthelawn.com"]
6
8
 
@@ -8,7 +10,7 @@ Gem::Specification.new do |spec|
8
10
  spec.description = "job scheduler"
9
11
  spec.homepage = "https://github.com/davidkellis/scheduler"
10
12
  spec.license = "MIT"
11
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
12
14
 
13
15
  spec.files = Dir["**/**"].
14
16
  grep_v(/.gem$/).
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schedule_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Ellis
@@ -64,14 +64,13 @@ files:
64
64
  - Gemfile.lock
65
65
  - LICENSE.txt
66
66
  - README.md
67
- - Rakefile
68
67
  - bin/schedule
69
- - lib/schedule/cli.rb
70
- - lib/schedule/cron.citrus
71
- - lib/schedule/cron.rb
72
- - lib/schedule/cron.treetop
73
- - lib/schedule/cron_parser.rb
74
68
  - lib/schedule_job.rb
69
+ - lib/schedule_job/cli.rb
70
+ - lib/schedule_job/cron.citrus
71
+ - lib/schedule_job/cron.rb
72
+ - lib/schedule_job/cron_parser.rb
73
+ - lib/schedule_job/version.rb
75
74
  - schedule_job.gemspec
76
75
  homepage: https://github.com/davidkellis/scheduler
77
76
  licenses:
@@ -85,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
85
84
  requirements:
86
85
  - - ">="
87
86
  - !ruby/object:Gem::Version
88
- version: 2.7.0
87
+ version: 2.5.0
89
88
  required_rubygems_version: !ruby/object:Gem::Requirement
90
89
  requirements:
91
90
  - - ">="
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: :spec
@@ -1,167 +0,0 @@
1
- grammar Crontab
2
- rule user_crontab
3
- sep?
4
- environment_spec:(environment sep)?
5
- jobspecs?
6
- sep?
7
- end
8
-
9
- rule environment
10
- head:directive tail:(sep directive)*
11
- end
12
-
13
- rule directive
14
- var space "=" space expr
15
- end
16
-
17
- rule var
18
- alpha alphanumeric?
19
- end
20
-
21
- rule expr
22
- command
23
- end
24
-
25
- rule jobspecs
26
- head:jobspec tail:(sep jobspec)*
27
- end
28
-
29
- rule jobspec
30
- schedule_spec space command ws*
31
- end
32
-
33
- rule schedule_spec
34
- standard / special
35
- end
36
-
37
- rule standard
38
- minute space hour space dayofmonth space month space dayofweek
39
- end
40
-
41
- rule special
42
- "@" ("yearly" / "annually" / "monthly" / "weekly" / "daily" / "hourly" / "reboot")
43
- end
44
-
45
- rule minute
46
- step
47
- end
48
-
49
- rule hour
50
- step
51
- end
52
-
53
- rule dayofmonthtypes
54
- step
55
- end
56
-
57
- rule monthtypes
58
- step / altmonths
59
- end
60
-
61
- rule dayofweektypes
62
- step / altdays
63
- end
64
-
65
- rule dayofmonth
66
- dayofmonthtypes ("," dayofmonthtypes)*
67
- end
68
-
69
- rule month
70
- monthtypes ("," monthtypes)*
71
- end
72
-
73
- rule dayofweek
74
- dayofweektypes ("," dayofweektypes)*
75
- end
76
-
77
- rule command
78
- quoted_string
79
- / (!("\n" / comment) .)+
80
- end
81
-
82
- rule step
83
- common ("/" int)?
84
- end
85
-
86
- rule common
87
- range / int / any
88
- end
89
-
90
- rule range
91
- int "-" int
92
- end
93
-
94
- rule altdays
95
- days ("," days)*
96
- end
97
-
98
- rule altmonths
99
- months ("," months)*
100
- end
101
-
102
- rule days
103
- "MON" / "TUE" / "WED" / "THU" / "FRI" / "SAT" / "SUN"
104
- end
105
-
106
- rule months
107
- "JAN" / "FEB" / "MAR" / "APR" / "MAY" / "JUN" / "JUL" / "AUG" / "SEP" / "OCT" / "NOV" / "DEC"
108
- end
109
-
110
- rule any
111
- "*"
112
- end
113
-
114
- rule int
115
- [0-9]+
116
- end
117
-
118
- rule alpha
119
- [a-zA-Z]+
120
- end
121
-
122
- rule alphanumeric
123
- [a-zA-Z0-9]+
124
- end
125
-
126
- rule sep
127
- (ws* nl)+
128
- end
129
-
130
- rule ws
131
- space / comment
132
- end
133
-
134
- rule space
135
- [ \t]+
136
- end
137
-
138
- rule nl
139
- [\n]+
140
- end
141
-
142
- rule comment
143
- "#" (!"\n" .)*
144
- end
145
-
146
- rule quoted_string
147
- "\"" ( (!("\"" / "\\") .) / escape)* "\""
148
- / "'" ( (!("'" / "\\") .) / escape)* "'"
149
- end
150
-
151
- rule escape
152
- "\\" escape_sequence
153
- end
154
-
155
- rule escape_sequence
156
- "'"
157
- / "\""
158
- / "\\"
159
- / "b"
160
- / "f"
161
- / "n"
162
- / "r"
163
- / "t"
164
- / "v"
165
- end
166
-
167
- end