taskloop 0.1.0
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 +7 -0
- data/.idea/.gitignore +8 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/taskloop.iml +51 -0
- data/.idea/vcs.xml +6 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +36 -0
- data/README.md +31 -0
- data/Rakefile +4 -0
- data/exe/taskloop +16 -0
- data/lib/taskloop/command/deploy.rb +136 -0
- data/lib/taskloop/command/env.rb +134 -0
- data/lib/taskloop/command/init.rb +42 -0
- data/lib/taskloop/command/launch.rb +67 -0
- data/lib/taskloop/command/list.rb +59 -0
- data/lib/taskloop/command/log.rb +104 -0
- data/lib/taskloop/command/run.rb +106 -0
- data/lib/taskloop/command/shutdown.rb +49 -0
- data/lib/taskloop/command/undeploy.rb +46 -0
- data/lib/taskloop/command.rb +168 -0
- data/lib/taskloop/dsl/dsl.rb +63 -0
- data/lib/taskloop/extension/integer_extension.rb +25 -0
- data/lib/taskloop/extension/string_extension.rb +18 -0
- data/lib/taskloop/rules/after_scope_rule.rb +91 -0
- data/lib/taskloop/rules/before_scope_rule.rb +90 -0
- data/lib/taskloop/rules/between_scope_rule.rb +130 -0
- data/lib/taskloop/rules/date_list_rule.rb +47 -0
- data/lib/taskloop/rules/default_rule.rb +19 -0
- data/lib/taskloop/rules/interval_rule.rb +26 -0
- data/lib/taskloop/rules/loop_rule.rb +25 -0
- data/lib/taskloop/rules/rule.rb +34 -0
- data/lib/taskloop/rules/scope_rule.rb +22 -0
- data/lib/taskloop/rules/specific_rule.rb +64 -0
- data/lib/taskloop/rules/time_list_rule.rb +49 -0
- data/lib/taskloop/task/task.rb +244 -0
- data/lib/taskloop/task/task_data_file.rb +46 -0
- data/lib/taskloop/task/task_error.rb +17 -0
- data/lib/taskloop/task/task_property.rb +294 -0
- data/lib/taskloop/utils/proj_tasklist.rb +145 -0
- data/lib/taskloop/version.rb +5 -0
- data/lib/taskloop.rb +9 -0
- data/sig/taskloop.rbs +4 -0
- data/taskloop.gemspec +37 -0
- metadata +103 -0
@@ -0,0 +1,104 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
class Log < Command
|
3
|
+
self.abstract_command = false
|
4
|
+
|
5
|
+
self.summary = "Check log"
|
6
|
+
|
7
|
+
self.description = <<-DESC
|
8
|
+
The 'taskloop log' is used to check log. It supports two options to check different kinds of log.
|
9
|
+
With '--task-name=TASK_NAME' option, you can check a specific task' log.
|
10
|
+
With '--cron' option, you can check the cron log of taskloop.
|
11
|
+
DESC
|
12
|
+
|
13
|
+
def self.options
|
14
|
+
[
|
15
|
+
['--task-name=TASK_NAME', "To show the log of a task specified by option."],
|
16
|
+
['--cron', 'To show the log of taskloop, which is based on cron.'],
|
17
|
+
].concat(super)
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(argv)
|
21
|
+
@task_name = argv.option('task-name')
|
22
|
+
@cron = argv.flag?('cron', false)
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate!
|
27
|
+
super
|
28
|
+
if @task_name && @cron
|
29
|
+
help! "The --task-name option and the --cron option cannot be used simultaneously."
|
30
|
+
end
|
31
|
+
|
32
|
+
if @task_name == nil && !@cron
|
33
|
+
help! "Use --task-name option or --cron option for 'taskloop log' command."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
super
|
39
|
+
if @task_name
|
40
|
+
check_log_of_task(@task_name)
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
if @cron
|
45
|
+
check_log_of_cron
|
46
|
+
return
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_log_of_task(name)
|
51
|
+
found = false
|
52
|
+
data_proj_dirs = Dir.entries(taskloop_data_dir)
|
53
|
+
data_proj_dirs.each do |dir|
|
54
|
+
if dir == "." or dir == ".."
|
55
|
+
next
|
56
|
+
end
|
57
|
+
data_proj_dir = File.join(taskloop_data_dir, dir)
|
58
|
+
|
59
|
+
print_proj = false
|
60
|
+
log_files = Dir.entries(data_proj_dir)
|
61
|
+
log_files.each do |file|
|
62
|
+
if "#{name.sha1}_log" == file
|
63
|
+
found = true
|
64
|
+
|
65
|
+
if !print_proj
|
66
|
+
print_proj = true
|
67
|
+
desc_file_path = File.join(data_proj_dir, ".description")
|
68
|
+
puts "=============================".ansi.blue
|
69
|
+
File.open(desc_file_path).each_line do |line|
|
70
|
+
puts "Project of <#{line.strip}>".ansi.blue
|
71
|
+
end
|
72
|
+
end
|
73
|
+
# print
|
74
|
+
task_log_path = File.join(data_proj_dir, "#{name.sha1}_log")
|
75
|
+
puts "Log of <Task.name: #{name}> above: ".ansi.blue
|
76
|
+
File.open(task_log_path).each_line do |line|
|
77
|
+
puts line
|
78
|
+
end
|
79
|
+
|
80
|
+
puts "=============================".ansi.blue
|
81
|
+
puts ""
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
unless found
|
87
|
+
puts "Warning: log of <Task.name: #{name}> not exist. Please check if the name of task is correct.".ansi.yellow
|
88
|
+
puts ""
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def check_log_of_cron
|
93
|
+
puts "=============================".ansi.blue
|
94
|
+
puts "Log of cron: ".ansi.blue
|
95
|
+
puts ""
|
96
|
+
log_file = File.open(taskloop_cron_log_path, "r")
|
97
|
+
log_file.each_line do |line|
|
98
|
+
puts line
|
99
|
+
end
|
100
|
+
puts "=============================".ansi.blue
|
101
|
+
puts ""
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
class Run < Command
|
3
|
+
require_relative '../task/task'
|
4
|
+
require_relative '../rules/rule'
|
5
|
+
require_relative '../rules/interval_rule'
|
6
|
+
require_relative '../rules/scope_rule'
|
7
|
+
require_relative '../rules/default_rule'
|
8
|
+
require_relative '../rules/specific_rule'
|
9
|
+
require_relative '../rules/after_scope_rule'
|
10
|
+
require_relative '../rules/before_scope_rule'
|
11
|
+
require_relative '../rules/between_scope_rule'
|
12
|
+
require_relative '../rules/loop_rule'
|
13
|
+
require_relative '../rules/date_list_rule'
|
14
|
+
require_relative '../rules/time_list_rule'
|
15
|
+
require_relative '../extension/string_extension'
|
16
|
+
require_relative '../extension/integer_extension'
|
17
|
+
require_relative '../utils/proj_tasklist'
|
18
|
+
require_relative '../dsl/dsl'
|
19
|
+
require 'open3'
|
20
|
+
|
21
|
+
include TaskLoop::DSL
|
22
|
+
include TaskLoop::ProjTaskList
|
23
|
+
|
24
|
+
self.abstract_command = false
|
25
|
+
|
26
|
+
self.summary = "Execute all the registered tasks that meet their requirements."
|
27
|
+
|
28
|
+
self.description = <<-DESC
|
29
|
+
The `taskloop run` command will execute all the registered tasks that meet their requiremets.
|
30
|
+
Taskloop will read all the registered Taskfiles from `~/.taskloop/tasklist.json`, then execute
|
31
|
+
each Tasfile to figure out if there is any task need to be executed. If needed, they will be
|
32
|
+
executed.
|
33
|
+
DESC
|
34
|
+
|
35
|
+
#################################
|
36
|
+
# Utils Methods
|
37
|
+
#################################
|
38
|
+
|
39
|
+
def run
|
40
|
+
super
|
41
|
+
create_data_proj_dir_if_needed
|
42
|
+
create_data_proj_description_if_needed
|
43
|
+
|
44
|
+
construct_proj_tasklist_map
|
45
|
+
setup_task_property
|
46
|
+
|
47
|
+
create_data_proj_task_log_if_needed
|
48
|
+
create_data_proj_task_time_if_needed
|
49
|
+
create_data_proj_task_loop_if_needed
|
50
|
+
|
51
|
+
execute_tasks_if_needed
|
52
|
+
clean_cache_file_if_needed
|
53
|
+
end
|
54
|
+
|
55
|
+
private def execute_tasks_if_needed
|
56
|
+
unless @proj_tasklist_map != nil
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
puts "Trigger Time: <#{Time.now}>"
|
61
|
+
@proj_tasklist_map.each do |proj, list|
|
62
|
+
list.each do |task|
|
63
|
+
unless task.check_rule_conflict?
|
64
|
+
puts "Warning: There is a rule conflict in #{task.desc}, taskloop will skip its execution.".ansi.yellow
|
65
|
+
next
|
66
|
+
end
|
67
|
+
unless task.check_all_rules?
|
68
|
+
puts "Checking: #{task.desc} does not meet the execution rules, taskloop will skip its execution.".ansi.blue
|
69
|
+
next
|
70
|
+
end
|
71
|
+
puts "Checking: #{task.desc} does meet the execution rules, taskloop start to execute.".ansi.blue
|
72
|
+
execute_task(proj, task)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private def execute_task(proj, task)
|
78
|
+
path = task.path
|
79
|
+
unless path[0] == '/'
|
80
|
+
path = File.join(proj, path)
|
81
|
+
end
|
82
|
+
|
83
|
+
unless File.exists?(path)
|
84
|
+
errmsg = "No such file or directory - #{path}"
|
85
|
+
task.write_to_logfile(errmsg)
|
86
|
+
return
|
87
|
+
end
|
88
|
+
|
89
|
+
# record execute timestamp into task's timefile
|
90
|
+
timestamp = Time.now.to_i
|
91
|
+
task.write_to_timefile(timestamp)
|
92
|
+
count = task.loop_count + 1
|
93
|
+
task.write_to_loopfile(count)
|
94
|
+
|
95
|
+
cmd = path
|
96
|
+
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
97
|
+
# record execute information into task's logfile
|
98
|
+
out = stdout.read
|
99
|
+
err = stderr.read
|
100
|
+
content = out + "\n" + err
|
101
|
+
content = "<Trigger Time: #{Time.now}>\n" + content
|
102
|
+
task.write_to_logfile(content)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
class Shutdown < Command
|
3
|
+
self.abstract_command = false
|
4
|
+
|
5
|
+
self.summary = "Shutdown taskloop. "
|
6
|
+
|
7
|
+
self.description = <<-DESC
|
8
|
+
The `taskloop shutdown` command will shutdown taskloop. Therefore, every Taskfile registered in taskloop will stop.
|
9
|
+
It is a global switch that controls taskloop. If you execute `taskloop launch` command again after executing 'taskloop shutdown',
|
10
|
+
every Taskfile you deployed before will resume automatically.
|
11
|
+
DESC
|
12
|
+
def run
|
13
|
+
super
|
14
|
+
unregister_taskloop_from_crontab_if_needed
|
15
|
+
end
|
16
|
+
|
17
|
+
def unregister_taskloop_from_crontab_if_needed
|
18
|
+
system("crontab -l > #{taskloop_cron_tab_path}")
|
19
|
+
registered = false
|
20
|
+
pattern = /\A\* \* \* \* \* sh ~\/\.tasklooprc/
|
21
|
+
remain = []
|
22
|
+
File.open(taskloop_cron_tab_path, "r").each_line do |line|
|
23
|
+
if line.match?(pattern)
|
24
|
+
registered = true
|
25
|
+
else
|
26
|
+
remain << line
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
unless registered
|
31
|
+
puts "Warning: taskloop has already shutdown. Please do not shutdown again.".ansi.yellow
|
32
|
+
puts " If your want to launch taskloop, please execute the `taskloop launch` command.".ansi.yellow
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
File.open(taskloop_cron_tab_path, "w") do |file|
|
37
|
+
file.write(remain.join)
|
38
|
+
end
|
39
|
+
|
40
|
+
system("crontab #{taskloop_cron_tab_path}")
|
41
|
+
|
42
|
+
puts LOGO.ansi.blue
|
43
|
+
puts " taskloop has shutdown successfully. ".ansi.blue
|
44
|
+
puts ""
|
45
|
+
puts " byeeeeeeeeeeeeeeeee !".ansi.blue
|
46
|
+
puts ""
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module TaskLoop
|
4
|
+
class Undeploy < Command
|
5
|
+
self.abstract_command = false
|
6
|
+
|
7
|
+
self.summary = "Undeploy a Taskfile from taskloop."
|
8
|
+
|
9
|
+
self.description = <<-DESC
|
10
|
+
The "taskloop undeploy" command will undeploy a Taskfile from taskloop. It should be executed in the directory where
|
11
|
+
Taskfile exists.
|
12
|
+
DESC
|
13
|
+
|
14
|
+
def run
|
15
|
+
super
|
16
|
+
unless File.exists?(:Taskfile.to_s)
|
17
|
+
puts "Error: 'taskloop undeploy' command should be executed in the directory where Taskfile exists.".ansi.red
|
18
|
+
return
|
19
|
+
end
|
20
|
+
|
21
|
+
remove_proj_path_from_projlist
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove_proj_path_from_projlist
|
25
|
+
current_dir = Dir.pwd
|
26
|
+
proj_list_dirs = taskloop_proj_list_dirs
|
27
|
+
unless proj_list_dirs.include?(current_dir)
|
28
|
+
puts "Warning: current Taskfile is not deployed before. Do not need to undeploy it again.".ansi.yellow
|
29
|
+
return
|
30
|
+
end
|
31
|
+
proj_list_dirs.delete(current_dir)
|
32
|
+
File.open(taskloop_proj_list_path, "w") do |file|
|
33
|
+
file.write(JSON.pretty_generate(proj_list_dirs))
|
34
|
+
end
|
35
|
+
|
36
|
+
data_proj_dir = File.join(taskloop_data_dir, current_dir.sha1_8bit)
|
37
|
+
unless File.directory?(data_proj_dir)
|
38
|
+
puts "Warning: #{data_proj_dir} not exist. ".ansi.yellow
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
FileUtils.rm_rf(data_proj_dir)
|
43
|
+
puts "Taskfile in <#{current_dir}> has been undeployed successfully.".ansi.blue
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
require 'claide'
|
3
|
+
|
4
|
+
class Command < CLAide::Command
|
5
|
+
require 'digest'
|
6
|
+
require 'taskloop/extension/string_extension'
|
7
|
+
require 'taskloop/command/init'
|
8
|
+
require 'taskloop/command/list'
|
9
|
+
require 'taskloop/command/log'
|
10
|
+
require 'taskloop/command/deploy'
|
11
|
+
require 'taskloop/command/run'
|
12
|
+
require 'taskloop/command/launch'
|
13
|
+
require 'taskloop/command/shutdown'
|
14
|
+
require 'taskloop/command/env'
|
15
|
+
require 'taskloop/command/undeploy'
|
16
|
+
|
17
|
+
self.abstract_command = true
|
18
|
+
|
19
|
+
self.description = <<-DESC
|
20
|
+
Taskloop is a scheduled task manager based on cron. It offers a more clear syntax, more convenient log management.
|
21
|
+
It also solves environment variable import issues, and provides a more user-friendly experience.'
|
22
|
+
DESC
|
23
|
+
|
24
|
+
self.command = 'taskloop'
|
25
|
+
|
26
|
+
def initialize(argv)
|
27
|
+
# @verbose = argv.flag?('verbose', true)
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def run
|
32
|
+
create_taskloop_file_structure_if_needed
|
33
|
+
end
|
34
|
+
|
35
|
+
#################################
|
36
|
+
# Path and Directory and Files
|
37
|
+
#################################
|
38
|
+
def create_taskloop_file_structure_if_needed
|
39
|
+
# create ~/.taskloop/ dir
|
40
|
+
create_dir_if_needed(taskloop_dir)
|
41
|
+
# create ~/.taskloop/projlist file
|
42
|
+
unless File.exists?(taskloop_proj_list_path)
|
43
|
+
projlist = File.new(taskloop_proj_list_path, "w+")
|
44
|
+
projlist.puts "[]"
|
45
|
+
projlist.close
|
46
|
+
end
|
47
|
+
|
48
|
+
# create ~/.taskloop/crontab file
|
49
|
+
create_file_if_needed(taskloop_cron_tab_path)
|
50
|
+
# create ~/.taskloop/cronlog file
|
51
|
+
create_file_if_needed(taskloop_cron_log_path)
|
52
|
+
|
53
|
+
# create ~/.taskloop/data/ dir
|
54
|
+
create_dir_if_needed(taskloop_data_dir)
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_file_if_needed(path)
|
58
|
+
unless File.file?(path)
|
59
|
+
File.new(path, "w")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
def create_dir_if_needed(dir)
|
63
|
+
unless File.directory?(dir)
|
64
|
+
FileUtils.mkdir(dir)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def tasklooprc_path
|
69
|
+
File.join(Dir.home, ".tasklooprc")
|
70
|
+
end
|
71
|
+
|
72
|
+
def taskloop_dir
|
73
|
+
File.join(Dir.home, ".taskloop")
|
74
|
+
end
|
75
|
+
|
76
|
+
def taskloop_cron_log_path
|
77
|
+
File.join(taskloop_dir, "cronlog")
|
78
|
+
end
|
79
|
+
|
80
|
+
def taskloop_cron_tab_path
|
81
|
+
File.join(taskloop_dir, "crontab")
|
82
|
+
end
|
83
|
+
|
84
|
+
def taskloop_environments_path
|
85
|
+
File.join(taskloop_dir, "environments")
|
86
|
+
end
|
87
|
+
|
88
|
+
def taskloop_proj_list_path
|
89
|
+
File.join(taskloop_dir, "projlist")
|
90
|
+
end
|
91
|
+
|
92
|
+
def taskloop_data_dir
|
93
|
+
File.join(taskloop_dir, "data")
|
94
|
+
end
|
95
|
+
|
96
|
+
def taskloop_proj_list_dirs
|
97
|
+
json_string = File.read(taskloop_proj_list_path)
|
98
|
+
parsed_json = JSON.parse(json_string)
|
99
|
+
return parsed_json
|
100
|
+
end
|
101
|
+
|
102
|
+
def taskloop_data_proj_dirs
|
103
|
+
dirs = Dir.entries(taskloop_data_dir)
|
104
|
+
result = []
|
105
|
+
dirs.each do |dir|
|
106
|
+
if dir != '.' && dir != '..'
|
107
|
+
result.push(dir)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
return result
|
111
|
+
end
|
112
|
+
|
113
|
+
def taskloop_taskfile_paths
|
114
|
+
paths = taskloop_data_proj_dirs
|
115
|
+
result = []
|
116
|
+
paths.each do |path|
|
117
|
+
result.push(File.join(path, ".Taskfile.deploy"))
|
118
|
+
end
|
119
|
+
return result
|
120
|
+
end
|
121
|
+
|
122
|
+
LOGO = <<-DESC
|
123
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
124
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
125
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
126
|
+
@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ @@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
127
|
+
@@@@@@@@@@@ @@@@@@ @@@@@ @@@ @@ @@ @@@@@ @@@@ @@@ @@@@@@@@@
|
128
|
+
@@@@@@@@@@@ @@@@ @@ @@ @@@ @@ @ @@@ @@@@ @@ @@ @@ @@ @@ @@@@@@@@
|
129
|
+
@@@@@@@@@@@ @@@@@@@@@ @@@ @@@@@@ @@@@ @@@@ @@ @@ @@ @@ @@ @@@@@@@@
|
130
|
+
@@@@@@@@@@@ @@@@ @@@@@@ @@@ @@@@ @@@@ @@ @@ @@ @@ @@ @@@@@@@@
|
131
|
+
@@@@@@@@@@@ @@@ @@@ @@ @@@ @@ @ @@@ @@@@ @@ @@ @@ @@ @@ @@@@@@@@
|
132
|
+
@@@@@@@@@@@ @@@@ @@@ @@@ @@ @@ @@@ @@@@ @@@ @@@@@@@@@
|
133
|
+
@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@
|
134
|
+
@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
135
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
136
|
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
137
|
+
DESC
|
138
|
+
|
139
|
+
DOLPHIN = <<-DESC
|
140
|
+
|
141
|
+
(@&/////%@@@@@@@@@@@@@#
|
142
|
+
@@&@&////////////////(@@#
|
143
|
+
/@(///////////////////////%@/
|
144
|
+
*@////////////////////////////#@,
|
145
|
+
@&///////////////////////////////@%
|
146
|
+
@&//////////////(@////@&#/////////(@
|
147
|
+
@////////////@@ @////@ ,.@////@@
|
148
|
+
/@//////////&@ ,@@////@@@&. *///@@
|
149
|
+
,@/////////(@@@ @///&@ /@@///@@
|
150
|
+
@%////////@@ @@@& @@/@#
|
151
|
+
@#///////@ ,
|
152
|
+
@@//////@& @(//@
|
153
|
+
@@/////%@ @////@
|
154
|
+
@@/////#@@@////@
|
155
|
+
&@@@&#((&@@
|
156
|
+
/&# @///@@
|
157
|
+
,///,*. @////@
|
158
|
+
&# %/,@ @@///@
|
159
|
+
(, .*/&*%/*%///& (@@@ ,*/////*.
|
160
|
+
%/#@, ////& @ % .& /@%/(/ /#/#@( #@#/&
|
161
|
+
(/& . .////, &//
|
162
|
+
&(//@ &//////& @///@
|
163
|
+
(@%//////#&@@@@@@@@@@%///////@@ @@///////%@@@@@@@@@@&#//////#@#
|
164
|
+
%@@@@&@@@@@&&@@@@/ /@@@@&&@@@@@&@@@@&
|
165
|
+
DESC
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
#################################
|
5
|
+
# Loop Syntax
|
6
|
+
#################################
|
7
|
+
def interval(interval)
|
8
|
+
IntervalRule.new(:unknown, interval)
|
9
|
+
end
|
10
|
+
|
11
|
+
#################################
|
12
|
+
# Specific Syntax
|
13
|
+
#################################
|
14
|
+
def at(value)
|
15
|
+
SpecificRule.new(:unknown, value)
|
16
|
+
end
|
17
|
+
|
18
|
+
#################################
|
19
|
+
# Scope Syntax
|
20
|
+
#################################
|
21
|
+
def before(right)
|
22
|
+
BeforeScopeRule.new(:unknown, :before, right)
|
23
|
+
end
|
24
|
+
|
25
|
+
def between(left, right)
|
26
|
+
BetweenScopeRule.new(:unknown, :between, left, right)
|
27
|
+
end
|
28
|
+
|
29
|
+
def after(left)
|
30
|
+
AfterScopeRule.new(:unknown, :after, left)
|
31
|
+
end
|
32
|
+
|
33
|
+
#################################
|
34
|
+
# Loop Syntax
|
35
|
+
#################################
|
36
|
+
def loop(count)
|
37
|
+
LoopRule.new(:unknown, count)
|
38
|
+
end
|
39
|
+
|
40
|
+
#################################
|
41
|
+
# Time List Syntax
|
42
|
+
#################################
|
43
|
+
def time(*args)
|
44
|
+
TimeListRule.new(:unknown, args)
|
45
|
+
end
|
46
|
+
|
47
|
+
#################################
|
48
|
+
# Date List Syntax
|
49
|
+
#################################
|
50
|
+
def date(*args)
|
51
|
+
DateListRule.new(:unknown, args)
|
52
|
+
end
|
53
|
+
|
54
|
+
#################################
|
55
|
+
# Env
|
56
|
+
#################################
|
57
|
+
def env(name, value)
|
58
|
+
ENV[name] = value
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module TaskLoop
|
2
|
+
class AfterScopeRule < ScopeRule
|
3
|
+
|
4
|
+
attr_accessor :left
|
5
|
+
|
6
|
+
def initialize(unit, scope, left)
|
7
|
+
super unit, scope
|
8
|
+
@left = left
|
9
|
+
end
|
10
|
+
|
11
|
+
def invalidate!
|
12
|
+
super
|
13
|
+
if @unit == :day
|
14
|
+
unless Task::WEEK.has_key?(@left) || Task::DAY.has_key?(@left)
|
15
|
+
raise ArgumentError, "#{left} must be a Symbol defined in Task::WEEK or Task::DAY"
|
16
|
+
end
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
if @unit == :month
|
21
|
+
unless Task::MONTH.has_key?(@left)
|
22
|
+
raise ArgumentError, "#{left} must be a Symbol defined in Task::MONTH"
|
23
|
+
end
|
24
|
+
return
|
25
|
+
end
|
26
|
+
|
27
|
+
unless @left.is_a?(Integer)
|
28
|
+
raise TypeError, "'left' need to be Symbol or Integer"
|
29
|
+
end
|
30
|
+
|
31
|
+
if @unit == :minute && (@left < 0 || @left > 59)
|
32
|
+
raise ArgumentError, "'right' for 'minute' must >= 0 and <= 59"
|
33
|
+
end
|
34
|
+
|
35
|
+
if @unit == :hour && (@left < 0 || @left > 23)
|
36
|
+
raise ArgumentError, "'right' for 'hour' must >= 0 and <= 23"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def left_value
|
42
|
+
if (Task::DAY.has_key?(@left))
|
43
|
+
return Task::DAY[@left]
|
44
|
+
end
|
45
|
+
if (Task::WEEK.has_key?(@left))
|
46
|
+
return Task::WEEK[@left]
|
47
|
+
end
|
48
|
+
if (Task::MONTH.has_key?(@left))
|
49
|
+
return Task::MONTH[@left]
|
50
|
+
end
|
51
|
+
|
52
|
+
unless @left != nil && @left.is_a?(Integer)
|
53
|
+
return -1
|
54
|
+
end
|
55
|
+
|
56
|
+
return @left
|
57
|
+
end
|
58
|
+
|
59
|
+
def is_week_value?
|
60
|
+
if @unit == :day && Task::WEEK.has_key?(@left)
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
|
66
|
+
def is_conform_rule?(last_exec_time)
|
67
|
+
current = Time.now
|
68
|
+
value = left_value
|
69
|
+
result = false
|
70
|
+
case @unit
|
71
|
+
when :year then
|
72
|
+
result = current.year > value
|
73
|
+
when :month then
|
74
|
+
result = current.month > value
|
75
|
+
when :day then
|
76
|
+
if is_week_value?
|
77
|
+
result = current.wday > (value % TaskLoop::WEEK_BASE)
|
78
|
+
else
|
79
|
+
result = current.day > value
|
80
|
+
end
|
81
|
+
when :hour then
|
82
|
+
result = current.hour > value
|
83
|
+
end
|
84
|
+
return result
|
85
|
+
end
|
86
|
+
|
87
|
+
def desc
|
88
|
+
super + " #{left}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|