do_run 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/CHANGELOG.md +20 -0
- data/LICENSE +674 -0
- data/README.md +244 -0
- data/bin/do +10 -0
- data/lib/do/cli.rb +448 -0
- data/lib/do/config.rb +163 -0
- data/lib/do/error.rb +14 -0
- data/lib/do/executor.rb +36 -0
- data/lib/do/manager.rb +114 -0
- data/lib/do/scheduler.rb +93 -0
- data/lib/do/systemd.rb +214 -0
- data/lib/do/task.rb +53 -0
- data/lib/do/validator.rb +124 -0
- data/lib/do/version.rb +3 -0
- data/lib/do.rb +13 -0
- metadata +85 -0
data/lib/do/validator.rb
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
require_relative 'config'
|
|
2
|
+
require_relative 'scheduler'
|
|
3
|
+
require_relative 'task'
|
|
4
|
+
require_relative 'error'
|
|
5
|
+
|
|
6
|
+
module Do
|
|
7
|
+
# Stateless validation over a parsed {Config}. Returns human-readable error
|
|
8
|
+
# strings and never touches the system.
|
|
9
|
+
module Validator
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# @param config [Config] parsed configuration
|
|
13
|
+
# @return [Array<String>] validation errors (empty when valid)
|
|
14
|
+
def validate(config)
|
|
15
|
+
errors = []
|
|
16
|
+
errors.concat(validate_commands(config))
|
|
17
|
+
errors.concat(validate_task_fields(config))
|
|
18
|
+
errors.concat(validate_duplicates(config))
|
|
19
|
+
errors.concat(validate_schedules(config))
|
|
20
|
+
errors.concat(validate_unit_names(config))
|
|
21
|
+
errors.concat(validate_directories(config))
|
|
22
|
+
errors.concat(validate_environment(config))
|
|
23
|
+
errors
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def valid?(config)
|
|
27
|
+
validate(config).empty?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @raise [ValidationError] when config is invalid
|
|
31
|
+
def validate!(config)
|
|
32
|
+
errors = validate(config)
|
|
33
|
+
raise ValidationError, errors unless errors.empty?
|
|
34
|
+
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def validate_commands(config)
|
|
39
|
+
config.tasks.flat_map do |task|
|
|
40
|
+
if task.command.nil? || task.command.to_s.strip.empty?
|
|
41
|
+
["task '#{task.name}' is missing required field 'command'"]
|
|
42
|
+
else
|
|
43
|
+
[]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def validate_task_fields(config)
|
|
49
|
+
config.tasks.flat_map do |task|
|
|
50
|
+
unknown = task.raw.keys - Config::KNOWN_TASK_FIELDS
|
|
51
|
+
unknown.map { |field| "unsupported field '#{field}' for task '#{task.name}'" }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate_duplicates(config)
|
|
56
|
+
lowered = config.tasks.map { |t| t.name.downcase }
|
|
57
|
+
lowered
|
|
58
|
+
.select { |n| lowered.count(n) > 1 }.uniq
|
|
59
|
+
.map { |n| "duplicate task name '#{n}'" }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def validate_schedules(config)
|
|
63
|
+
config.tasks.flat_map { |task| schedule_errors(task) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def validate_unit_names(config)
|
|
67
|
+
config.tasks.flat_map do |task|
|
|
68
|
+
name = task.name.to_s
|
|
69
|
+
if name.empty?
|
|
70
|
+
['task has an empty name']
|
|
71
|
+
elsif name.start_with?('.') || name =~ %r{[\s/]|\.}
|
|
72
|
+
["task name '#{name}' is not a valid systemd unit name " \
|
|
73
|
+
"(must not contain spaces, '/', dots, or start with a dot)"]
|
|
74
|
+
else
|
|
75
|
+
[]
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def validate_directories(config)
|
|
81
|
+
config.tasks.flat_map do |task|
|
|
82
|
+
wd = task.working_directory
|
|
83
|
+
next [] if wd.nil? || wd.empty?
|
|
84
|
+
|
|
85
|
+
if File.directory?(File.expand_path(wd))
|
|
86
|
+
[]
|
|
87
|
+
else
|
|
88
|
+
["working directory '#{wd}' for task '#{task.name}' does not exist"]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def validate_environment(config)
|
|
94
|
+
config.tasks.flat_map do |task|
|
|
95
|
+
(task.environment || {}).flat_map do |key, value|
|
|
96
|
+
if key.is_a?(String) && value.is_a?(String)
|
|
97
|
+
[]
|
|
98
|
+
else
|
|
99
|
+
["environment for task '#{task.name}' must map strings to strings"]
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def schedule_errors(task)
|
|
106
|
+
sched = task.schedule
|
|
107
|
+
return [] if sched.nil? || sched.empty?
|
|
108
|
+
|
|
109
|
+
unless Task::SCHEDULES.include?(sched)
|
|
110
|
+
return ["invalid schedule for task '#{task.name}'. " \
|
|
111
|
+
'Expected: once, hourly, daily, weekly, or monthly.']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Driving the calendar generator lets us reuse the exact same parsing
|
|
115
|
+
# rules that will later be used to emit the systemd unit.
|
|
116
|
+
begin
|
|
117
|
+
Scheduler.on_calendar(task)
|
|
118
|
+
[]
|
|
119
|
+
rescue Do::Error => e
|
|
120
|
+
["invalid schedule for task '#{task.name}': #{e.message}"]
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
data/lib/do/version.rb
ADDED
data/lib/do.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require_relative 'do/version'
|
|
2
|
+
require_relative 'do/error'
|
|
3
|
+
require_relative 'do/config'
|
|
4
|
+
require_relative 'do/task'
|
|
5
|
+
require_relative 'do/scheduler'
|
|
6
|
+
require_relative 'do/systemd'
|
|
7
|
+
require_relative 'do/validator'
|
|
8
|
+
require_relative 'do/executor'
|
|
9
|
+
require_relative 'do/manager'
|
|
10
|
+
require_relative 'do/cli'
|
|
11
|
+
|
|
12
|
+
module Do
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: do_run
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- do contributors
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: thor
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: toml-rb
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '4.2'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '4.2'
|
|
40
|
+
description: do is a declarative execution layer for Linux. It translates a small
|
|
41
|
+
TOML configuration into systemd user services and timers, giving you a friendly
|
|
42
|
+
control plane without reinventing scheduling.
|
|
43
|
+
executables:
|
|
44
|
+
- do
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- CHANGELOG.md
|
|
49
|
+
- LICENSE
|
|
50
|
+
- README.md
|
|
51
|
+
- bin/do
|
|
52
|
+
- lib/do.rb
|
|
53
|
+
- lib/do/cli.rb
|
|
54
|
+
- lib/do/config.rb
|
|
55
|
+
- lib/do/error.rb
|
|
56
|
+
- lib/do/executor.rb
|
|
57
|
+
- lib/do/manager.rb
|
|
58
|
+
- lib/do/scheduler.rb
|
|
59
|
+
- lib/do/systemd.rb
|
|
60
|
+
- lib/do/task.rb
|
|
61
|
+
- lib/do/validator.rb
|
|
62
|
+
- lib/do/version.rb
|
|
63
|
+
homepage: https://sahil.im./tools/do
|
|
64
|
+
licenses:
|
|
65
|
+
- GPL-3.0-or-later
|
|
66
|
+
metadata:
|
|
67
|
+
rubygems_mfa_required: 'true'
|
|
68
|
+
rdoc_options: []
|
|
69
|
+
require_paths:
|
|
70
|
+
- lib
|
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '3.1'
|
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '0'
|
|
81
|
+
requirements: []
|
|
82
|
+
rubygems_version: 4.0.16
|
|
83
|
+
specification_version: 4
|
|
84
|
+
summary: Declarative Linux execution layer backed by systemd user services and timers.
|
|
85
|
+
test_files: []
|