schedule_job 1.0.0 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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