locd 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/locd +1 -9
- data/lib/locd/agent.rb +108 -78
- data/lib/locd/agent/job.rb +3 -2
- data/lib/locd/agent/site.rb +1 -1
- data/lib/locd/agent/system.rb +1 -1
- data/lib/locd/cli/command/agent.rb +260 -53
- data/lib/locd/cli/command/job.rb +38 -30
- data/lib/locd/cli/command/main.rb +3 -10
- data/lib/locd/cli/command/proxy.rb +2 -2
- data/lib/locd/cli/command/rotate_logs.rb +24 -7
- data/lib/locd/label.rb +3 -3
- data/lib/locd/launchctl.rb +38 -1
- data/lib/locd/logging.rb +49 -10
- data/lib/locd/newsyslog.rb +1 -4
- data/lib/locd/pattern.rb +41 -5
- data/lib/locd/version.rb +1 -1
- data/locd.gemspec +3 -3
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 630061e7d172448491a1da49c70cfac510519d26
|
4
|
+
data.tar.gz: 417ac04a01d1bc9e6e888f3e8a1e847407d7b017
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3bf11b09b944869c254175fd90984f54959596c9506220d9a79ec49fe6a4ee7d7beb355bff2773b6db552d7bec74f69d3e1c3fb7a313550790ff3334384f72e
|
7
|
+
data.tar.gz: 5c03efd66d67973b72a2608ee21c695b2e9aa473c7f9659c713da8a13736799e8941406a2c4d5b2f24ddcfff56915badb785c5ef7c949c580c728d3b49e3d5e5
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/exe/locd
CHANGED
data/lib/locd/agent.rb
CHANGED
@@ -40,14 +40,6 @@ class Locd::Agent
|
|
40
40
|
# Constants
|
41
41
|
# ==========================================================================
|
42
42
|
|
43
|
-
# Extra plist key we store Loc'd config under (this is where the port is
|
44
|
-
# stored). We also use it's presence to detect that a plist is Loc'd.
|
45
|
-
#
|
46
|
-
# @return [String]
|
47
|
-
#
|
48
|
-
CONFIG_KEY = 'locd_config'
|
49
|
-
|
50
|
-
|
51
43
|
# Attribute / method names that {#to_h} uses.
|
52
44
|
#
|
53
45
|
# @return [Hamster::SortedSet<Symbol>]
|
@@ -69,7 +61,7 @@ class Locd::Agent
|
|
69
61
|
# ==========================================================================
|
70
62
|
|
71
63
|
# Test if the parse of a property list is for a Loc'd agent by seeing if
|
72
|
-
# it has
|
64
|
+
# it has the config key (from `Locd.config[:agent, :config_key]`) as a key.
|
73
65
|
#
|
74
66
|
# @param [Hash<String, Object>] plist
|
75
67
|
# {include:file:doc/include/plist.md}
|
@@ -78,7 +70,7 @@ class Locd::Agent
|
|
78
70
|
# `true` if the plist looks like it's from Loc'd.
|
79
71
|
#
|
80
72
|
def self.plist? plist
|
81
|
-
plist.key?
|
73
|
+
plist.key? Locd.config[:agent, :config_key]
|
82
74
|
end # .plist?
|
83
75
|
|
84
76
|
|
@@ -351,7 +343,7 @@ class Locd::Agent
|
|
351
343
|
# Parameters are passed to {Locd::Label.regexp_for_glob} and the resulting
|
352
344
|
# {Regexp} is matched against each agent's {#label}.
|
353
345
|
#
|
354
|
-
# @see Locd::
|
346
|
+
# @see Locd::Pattern
|
355
347
|
#
|
356
348
|
# @param (see .find_all)
|
357
349
|
#
|
@@ -364,7 +356,7 @@ class Locd::Agent
|
|
364
356
|
|
365
357
|
# Find all the agents that match a pattern.
|
366
358
|
#
|
367
|
-
# @see Locd::
|
359
|
+
# @see Locd::Pattern
|
368
360
|
#
|
369
361
|
# @param [String | Pattern] pattern
|
370
362
|
# Pattern to match against agent.
|
@@ -539,7 +531,7 @@ class Locd::Agent
|
|
539
531
|
|
540
532
|
# Extras we need... `launchd` complains in the system log about this
|
541
533
|
# but it's the easiest way to handle it at the moment
|
542
|
-
|
534
|
+
Locd.config[:agent, :config_key] => {
|
543
535
|
# Save this too why the hell not, might help debuging at least
|
544
536
|
cmd_template: cmd_template,
|
545
537
|
|
@@ -636,27 +628,11 @@ class Locd::Agent
|
|
636
628
|
logger.debug "Property list written", path: plist_abs_path
|
637
629
|
|
638
630
|
from_path( plist_abs_path ).tap { |agent|
|
639
|
-
|
631
|
+
agent.send :log_info, "added"
|
640
632
|
}
|
641
633
|
end # .add
|
642
634
|
|
643
635
|
|
644
|
-
# @!group Removing Agents
|
645
|
-
# ----------------------------------------------------------------------------
|
646
|
-
|
647
|
-
# Find an agent using a label pattern and call {#remove} on it.
|
648
|
-
#
|
649
|
-
# @param (see .find_only!)
|
650
|
-
# @return (see #remove)
|
651
|
-
# @raise See {.find_only!} and {#remove}
|
652
|
-
#
|
653
|
-
def self.remove *find_only_args
|
654
|
-
Locd::Agent.find_only!( *find_only_args ).remove
|
655
|
-
end # .remove
|
656
|
-
|
657
|
-
# @!endgroup
|
658
|
-
|
659
|
-
|
660
636
|
# Attributes
|
661
637
|
# ============================================================================
|
662
638
|
|
@@ -689,9 +665,9 @@ class Locd::Agent
|
|
689
665
|
|
690
666
|
# Sanity check...
|
691
667
|
|
692
|
-
unless plist.key?
|
668
|
+
unless plist.key? Locd.config[:agent, :config_key]
|
693
669
|
raise ArgumentError.new binding.erb <<~END
|
694
|
-
Not a Loc'd plist (no <%= Locd
|
670
|
+
Not a Loc'd plist (no <%= Locd.config[:agent, :config_key] %> key)
|
695
671
|
|
696
672
|
path: <%= path %>
|
697
673
|
plist:
|
@@ -779,7 +755,7 @@ class Locd::Agent
|
|
779
755
|
|
780
756
|
|
781
757
|
def config
|
782
|
-
plist[
|
758
|
+
plist[Locd.config[:agent, :config_key]]
|
783
759
|
end
|
784
760
|
|
785
761
|
|
@@ -822,6 +798,18 @@ class Locd::Agent
|
|
822
798
|
plist['StandardErrorPath'].to_pn if plist['StandardErrorPath']
|
823
799
|
end
|
824
800
|
|
801
|
+
|
802
|
+
# Get a list of all unique log paths.
|
803
|
+
#
|
804
|
+
# @return [Array<Pathname>]
|
805
|
+
#
|
806
|
+
def log_paths
|
807
|
+
[
|
808
|
+
out_path,
|
809
|
+
err_path,
|
810
|
+
].compact.uniq
|
811
|
+
end
|
812
|
+
|
825
813
|
# @!endgroup Instance Methods: Attribute Readers
|
826
814
|
|
827
815
|
|
@@ -875,15 +863,15 @@ class Locd::Agent
|
|
875
863
|
# @param [Boolean] force:
|
876
864
|
# Force the loading of the plist. Ignore the `launchd` *Disabled* key.
|
877
865
|
#
|
878
|
-
# @param [Boolean]
|
866
|
+
# @param [Boolean] enable:
|
879
867
|
# Overrides the `launchd` *Disabled* key and sets it to `false`.
|
880
868
|
#
|
881
869
|
# @return [self]
|
882
870
|
#
|
883
|
-
def load force: false,
|
884
|
-
logger.debug "Loading #{ label } agent...", force: force,
|
871
|
+
def load force: false, enable: false
|
872
|
+
logger.debug "Loading #{ label } agent...", force: force, enable: enable
|
885
873
|
|
886
|
-
result = Locd::Launchctl.load! path, force: force, write:
|
874
|
+
result = Locd::Launchctl.load! path, force: force, write: enable
|
887
875
|
|
888
876
|
message = if result.err =~ /service\ already\ loaded/
|
889
877
|
"already loaded"
|
@@ -891,7 +879,7 @@ class Locd::Agent
|
|
891
879
|
"LOADED"
|
892
880
|
end
|
893
881
|
|
894
|
-
|
882
|
+
log_info message, status: status
|
895
883
|
|
896
884
|
self
|
897
885
|
end
|
@@ -901,17 +889,17 @@ class Locd::Agent
|
|
901
889
|
#
|
902
890
|
# This is a bit low-level; you probably want to use {#stop}.
|
903
891
|
#
|
904
|
-
# @param [Boolean]
|
892
|
+
# @param [Boolean] disable:
|
905
893
|
# Overrides the `launchd` *Disabled* key and sets it to `true`.
|
906
894
|
#
|
907
895
|
# @return [self]
|
908
896
|
#
|
909
|
-
def unload
|
910
|
-
logger.debug "Unloading #{ label } agent...",
|
897
|
+
def unload disable: false
|
898
|
+
logger.debug "Unloading #{ label } agent...", disable: disable
|
911
899
|
|
912
|
-
result = Locd::Launchctl.unload! path, write:
|
900
|
+
result = Locd::Launchctl.unload! path, write: disable
|
913
901
|
|
914
|
-
|
902
|
+
log_info "UNLOADED"
|
915
903
|
|
916
904
|
self
|
917
905
|
end
|
@@ -922,9 +910,9 @@ class Locd::Agent
|
|
922
910
|
# @param (see #load)
|
923
911
|
# @return (see #load)
|
924
912
|
#
|
925
|
-
def reload force: false,
|
913
|
+
def reload force: false, enable: false
|
926
914
|
unload
|
927
|
-
load force: force,
|
915
|
+
load force: force, enable: enable
|
928
916
|
end
|
929
917
|
|
930
918
|
|
@@ -935,23 +923,23 @@ class Locd::Agent
|
|
935
923
|
# start, even if it's {#disabled?}).
|
936
924
|
#
|
937
925
|
# @param [Boolean] load:
|
938
|
-
# Call {#load} first, passing it `
|
926
|
+
# Call {#load} first, passing it `enable` and `force`.
|
939
927
|
#
|
940
|
-
# @param force
|
941
|
-
# @param
|
928
|
+
# @param force (see #load)
|
929
|
+
# @param enable (see #load)
|
942
930
|
#
|
943
931
|
# @return [self]
|
944
932
|
#
|
945
|
-
def start load: true, force:
|
933
|
+
def start load: true, force: false, enable: false
|
946
934
|
logger.trace "Starting `#{ label }` agent...",
|
947
935
|
load: load,
|
948
936
|
force: force,
|
949
|
-
|
937
|
+
enable: enable
|
950
938
|
|
951
|
-
self.load( force: force,
|
939
|
+
self.load( force: force, enable: enable ) if load
|
952
940
|
|
953
941
|
Locd::Launchctl.start! label
|
954
|
-
|
942
|
+
log_info "STARTED"
|
955
943
|
|
956
944
|
self
|
957
945
|
end
|
@@ -962,19 +950,19 @@ class Locd::Agent
|
|
962
950
|
# @param [Boolean] unload:
|
963
951
|
# Call {#unload} first, passing it `write`.
|
964
952
|
#
|
965
|
-
# @param
|
953
|
+
# @param disable (see #unload)
|
966
954
|
#
|
967
955
|
# @return [self]
|
968
956
|
#
|
969
|
-
def stop unload: true,
|
957
|
+
def stop unload: true, disable: false
|
970
958
|
logger.debug "Stopping `#{ label } agent...`",
|
971
959
|
unload: unload,
|
972
|
-
|
960
|
+
disable: disable
|
973
961
|
|
974
962
|
Locd::Launchctl.stop label
|
975
|
-
|
963
|
+
log_info "STOPPED"
|
976
964
|
|
977
|
-
self.unload(
|
965
|
+
self.unload( disable: disable ) if unload
|
978
966
|
|
979
967
|
self
|
980
968
|
end
|
@@ -982,28 +970,44 @@ class Locd::Agent
|
|
982
970
|
|
983
971
|
# Restart the agent ({#stop} then {#start}).
|
984
972
|
#
|
985
|
-
# @param
|
973
|
+
# @param [Boolean] reload:
|
974
|
+
# Unload then load the agent in `launchd`.
|
975
|
+
#
|
986
976
|
# @param force (see #start)
|
987
|
-
# @param
|
977
|
+
# @param enable (see #start)
|
988
978
|
#
|
989
979
|
# @return [self]
|
990
980
|
#
|
991
|
-
def restart
|
992
|
-
stop unload:
|
993
|
-
start load:
|
981
|
+
def restart reload: true, force: true, enable: false
|
982
|
+
stop unload: reload
|
983
|
+
start load: reload, force: force, enable: enable
|
994
984
|
end # #restart
|
995
985
|
|
996
986
|
|
997
987
|
# Remove the agent by removing it's {#path} file. Will {#stop} and
|
998
988
|
# {#unloads} the agent first.
|
999
989
|
#
|
990
|
+
# @param [Boolean] logs:
|
991
|
+
# When `true` remove all logs as well.
|
992
|
+
#
|
1000
993
|
# @return [self]
|
1001
994
|
#
|
1002
|
-
def remove
|
995
|
+
def remove logs: false
|
1003
996
|
stop unload: true
|
1004
997
|
|
998
|
+
if logs
|
999
|
+
log_paths.each { |log_path|
|
1000
|
+
if log_path.exists?
|
1001
|
+
FileUtils.rm log_path
|
1002
|
+
log_info "Removed log", path: log_path.to_s
|
1003
|
+
else
|
1004
|
+
log_info "Log path does not exist", path: log_path.to_s
|
1005
|
+
end
|
1006
|
+
}
|
1007
|
+
end
|
1008
|
+
|
1005
1009
|
FileUtils.rm path
|
1006
|
-
|
1010
|
+
log_info "REMOVED"
|
1007
1011
|
|
1008
1012
|
self
|
1009
1013
|
end
|
@@ -1011,18 +1015,25 @@ class Locd::Agent
|
|
1011
1015
|
# @!endgroup Instance Methods: `launchctl` Interface
|
1012
1016
|
|
1013
1017
|
|
1018
|
+
# @!group Modifying Agents
|
1019
|
+
# --------------------------------------------------------------------------
|
1020
|
+
|
1014
1021
|
# Update specific values on the agent, which *may* change it's file path if
|
1015
1022
|
# a different label is provided.
|
1016
1023
|
#
|
1017
1024
|
# **_Does not mutate this instance! Returns a new {Locd::Agent} with the
|
1018
1025
|
# updated values._**
|
1019
1026
|
#
|
1020
|
-
# @param
|
1027
|
+
# @param [Boolean] force:
|
1028
|
+
# Overwrite any existing agent with the same label.
|
1029
|
+
#
|
1030
|
+
# @param [Hash<Symbol, Object>] **values
|
1031
|
+
# See {.create_plist_data}.
|
1021
1032
|
#
|
1022
1033
|
# @return [Locd::Agent]
|
1023
1034
|
# A new instance with the updated values.
|
1024
1035
|
#
|
1025
|
-
def update **values
|
1036
|
+
def update force: false, **values
|
1026
1037
|
logger.trace "Updating `#{ label }` agent", **values
|
1027
1038
|
|
1028
1039
|
# Remove the `cmd_template` if it's nil of an empty array so that
|
@@ -1066,16 +1077,22 @@ class Locd::Agent
|
|
1066
1077
|
# another agent
|
1067
1078
|
|
1068
1079
|
if File.exists? new_plist_abs_path
|
1069
|
-
# There's someone already there!
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1080
|
+
# There's someone already there!
|
1081
|
+
# Bail out unless we are forcing the operation
|
1082
|
+
if force
|
1083
|
+
logger.info "Overwriting agent #{ new_label } with update to " \
|
1084
|
+
"agent #{ label } (force: `true`)"
|
1085
|
+
else
|
1086
|
+
raise binding.erb <<-END
|
1087
|
+
A different agent already exists at:
|
1088
|
+
|
1089
|
+
<%= new_plist_abs_path %>
|
1090
|
+
|
1091
|
+
Remove that agent first if you really want to replace it with an
|
1092
|
+
updated version of this one or provide `force: true`.
|
1093
|
+
|
1094
|
+
END
|
1095
|
+
end
|
1079
1096
|
end
|
1080
1097
|
|
1081
1098
|
# Ok, we're in the clear (save for the obvious race condition, but,
|
@@ -1092,6 +1109,7 @@ class Locd::Agent
|
|
1092
1109
|
end
|
1093
1110
|
end # #update
|
1094
1111
|
|
1112
|
+
# @!endgroup Modifying Agents
|
1095
1113
|
|
1096
1114
|
|
1097
1115
|
# @!group Instance Methods: Language Integration
|
@@ -1167,8 +1185,20 @@ class Locd::Agent
|
|
1167
1185
|
end
|
1168
1186
|
|
1169
1187
|
|
1170
|
-
|
1171
|
-
|
1188
|
+
# Log a message with a details payload, prefixing the agent's label.
|
1189
|
+
#
|
1190
|
+
# Used to relay info to the user in the CLI.
|
1191
|
+
#
|
1192
|
+
# @param [#to_s] message
|
1193
|
+
# Message to log.
|
1194
|
+
#
|
1195
|
+
# @param [Hash<Symbol, Object>] **payload
|
1196
|
+
# Optional values to dump.
|
1197
|
+
#
|
1198
|
+
# @return [void]
|
1199
|
+
#
|
1200
|
+
def log_info message, **payload
|
1201
|
+
logger.info "Agent `#{ label }` #{ message }", **payload
|
1172
1202
|
end
|
1173
1203
|
|
1174
1204
|
# end protected
|
data/lib/locd/agent/job.rb
CHANGED
@@ -113,11 +113,12 @@ class Locd::Agent::Job < Locd::Agent
|
|
113
113
|
|
114
114
|
start_interval_data = t.match start_interval,
|
115
115
|
t.pos_int,
|
116
|
-
{"StartInterval" => start_interval},
|
116
|
+
{ "StartInterval" => start_interval },
|
117
117
|
|
118
118
|
Types.start_calendar_interval,
|
119
119
|
->( interval ) {
|
120
|
-
|
120
|
+
{ 'StartCalendarInterval' =>
|
121
|
+
interval.map { |key, value| [key.to_s.capitalize, value] }.to_h }
|
121
122
|
},
|
122
123
|
|
123
124
|
Types.start_calendar_intervals,
|
data/lib/locd/agent/site.rb
CHANGED
data/lib/locd/agent/system.rb
CHANGED
@@ -117,18 +117,36 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
117
117
|
# Options when provided a `PATTERN` argument used to find agents by label.
|
118
118
|
#
|
119
119
|
|
120
|
-
shared_option :
|
120
|
+
shared_option :full,
|
121
121
|
groups: :pattern,
|
122
|
-
desc: "
|
123
|
-
aliases: '-
|
122
|
+
desc: "Require label PATTERN to match entire string",
|
123
|
+
aliases: '-u',
|
124
|
+
type: :boolean
|
125
|
+
|
126
|
+
shared_option :ignore_case,
|
127
|
+
groups: :pattern,
|
128
|
+
desc: "Make label PATTERN case-insensitive",
|
129
|
+
aliases: '-i',
|
124
130
|
type: :boolean
|
125
131
|
|
126
132
|
shared_option :recursive,
|
127
133
|
groups: :pattern,
|
128
|
-
desc: "
|
134
|
+
desc: "Make workdir PATTERN match all subdirs too",
|
129
135
|
aliases: '-r',
|
130
136
|
type: :boolean
|
131
137
|
|
138
|
+
# NOTE We don't expose the workdir pattern's `:cwd` option...
|
139
|
+
# If you want to match a directory from the CLI, just provide that
|
140
|
+
# directory... no reason to specify the `:cwd` in an option then
|
141
|
+
# provide a relative PATTERN
|
142
|
+
#
|
143
|
+
|
144
|
+
# `:multi` Group
|
145
|
+
# ----------------------------------------------------------------------------
|
146
|
+
#
|
147
|
+
# For commands that can match multiple agents.
|
148
|
+
#
|
149
|
+
|
132
150
|
shared_option :all,
|
133
151
|
groups: :multi,
|
134
152
|
desc: "Apply to ALL agents that PATTERN matches",
|
@@ -161,11 +179,25 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
161
179
|
aliases: ['--log'],
|
162
180
|
type: :string
|
163
181
|
|
182
|
+
shared_option :keep_alive,
|
183
|
+
groups: :write,
|
184
|
+
desc: "Try to keep the agent running",
|
185
|
+
type: :boolean,
|
186
|
+
default: false
|
187
|
+
|
188
|
+
shared_option :run_at_load,
|
189
|
+
groups: :write,
|
190
|
+
desc: "Start the agent when loading it",
|
191
|
+
type: :boolean,
|
192
|
+
default: false
|
193
|
+
|
194
|
+
|
195
|
+
# `:add` Group
|
196
|
+
# ----------------------------------------------------------------------------
|
164
197
|
|
165
198
|
shared_option :force,
|
166
199
|
groups: :add,
|
167
200
|
desc: "Overwrite any existing agent",
|
168
|
-
aliases: '-f',
|
169
201
|
type: :boolean,
|
170
202
|
default: false
|
171
203
|
|
@@ -177,12 +209,6 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
177
209
|
default: true
|
178
210
|
|
179
211
|
|
180
|
-
shared_option :unload,
|
181
|
-
groups: :start,
|
182
|
-
desc: "Unload the agent from `launchd` after stopping",
|
183
|
-
type: :boolean,
|
184
|
-
default: true
|
185
|
-
|
186
212
|
# Commands
|
187
213
|
# ============================================================================
|
188
214
|
|
@@ -191,9 +217,12 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
191
217
|
|
192
218
|
desc "ls [PATTERN]",
|
193
219
|
"List agents"
|
220
|
+
|
194
221
|
map list: :ls
|
222
|
+
|
195
223
|
include_options :long,
|
196
224
|
groups: :pattern
|
225
|
+
|
197
226
|
def ls pattern = nil
|
198
227
|
results = if pattern.nil?
|
199
228
|
agent_class.all
|
@@ -205,20 +234,74 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
205
234
|
end
|
206
235
|
|
207
236
|
|
208
|
-
|
237
|
+
desc "plist PATTERN",
|
238
|
+
"Print an agent's launchd property list"
|
239
|
+
|
240
|
+
include_options groups: :pattern
|
241
|
+
|
242
|
+
def plist pattern
|
243
|
+
agent = find_only! pattern
|
244
|
+
|
245
|
+
if options[:json] || options[:yaml]
|
246
|
+
respond agent.plist
|
247
|
+
else
|
248
|
+
respond agent.path.read
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
desc 'status PATTERN',
|
254
|
+
"Print agent status"
|
255
|
+
|
256
|
+
include_options groups: :pattern
|
257
|
+
|
258
|
+
def status pattern
|
259
|
+
agent = find_only! pattern
|
260
|
+
respond \
|
261
|
+
label: agent.label,
|
262
|
+
port: agent.port,
|
263
|
+
status: agent.status
|
264
|
+
end
|
265
|
+
|
266
|
+
|
267
|
+
# Commands for Manipulating Agent Definitions
|
209
268
|
# ----------------------------------------------------------------------------
|
210
269
|
|
211
270
|
desc "add CMD_TEMPLATE...",
|
212
|
-
"Add
|
271
|
+
"Add an agent that runs a command in the current directory"
|
272
|
+
|
213
273
|
include_options groups: [:write, :add, :respond_with_agents]
|
214
|
-
|
215
|
-
|
274
|
+
|
275
|
+
def add *cmd_template, **kwds
|
276
|
+
logger.trace __method__.to_s,
|
216
277
|
cmd_template: cmd_template,
|
217
|
-
|
278
|
+
kwds: kwds,
|
279
|
+
options: options
|
218
280
|
|
219
|
-
|
281
|
+
# Merge all the keywords together into the format needed to call
|
282
|
+
# {Locd::Agent.add}
|
283
|
+
kwds.merge! **option_kwds( :force, groups: [:write] ),
|
284
|
+
cmd_template: cmd_template
|
220
285
|
|
221
|
-
|
286
|
+
# Check args
|
287
|
+
|
288
|
+
# `:cmd_template` can not be empty at this point
|
289
|
+
if kwds[:cmd_template].empty? || kwds[:cmd_template].all?( &:empty? )
|
290
|
+
raise Thor::RequiredArgumentMissingError,
|
291
|
+
"CMD_TEMPLATE argument is required to add an agent"
|
292
|
+
end
|
293
|
+
|
294
|
+
# Need a `:label` too
|
295
|
+
unless t.non_empty_str === kwds[:label]
|
296
|
+
raise Thor::RequiredArgumentMissingError,
|
297
|
+
"--label=LABEL option is required to add an agent"
|
298
|
+
end
|
299
|
+
|
300
|
+
# Do the add
|
301
|
+
agent = agent_class.add **kwds
|
302
|
+
|
303
|
+
# Reload (unless we were told not to... usually you want to reload)
|
304
|
+
agent.reload if options[:load]
|
222
305
|
|
223
306
|
respond agent
|
224
307
|
end
|
@@ -226,7 +309,9 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
226
309
|
|
227
310
|
desc "update PATTERN [OPTIONS] [-- CMD_TEMPLATE...]",
|
228
311
|
"Update an existing agent"
|
312
|
+
|
229
313
|
include_options groups: [:pattern, :write, :respond_with_agents]
|
314
|
+
|
230
315
|
def update pattern, *cmd_template
|
231
316
|
agent = find_only! pattern
|
232
317
|
|
@@ -240,71 +325,193 @@ class Locd::CLI::Command::Agent < Locd::CLI::Command::Base
|
|
240
325
|
end
|
241
326
|
|
242
327
|
|
243
|
-
desc "open PATTERN",
|
244
|
-
"Open an agent's URL in the browser"
|
245
|
-
include_options groups: [:pattern, :multi]
|
246
|
-
def open pattern
|
247
|
-
find_multi!( pattern ).each do |agent|
|
248
|
-
Cmds! "open %s", agent.url
|
249
|
-
logger.info "Opened agent `#{ agent.label }` at #{ agent.url }"
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
|
254
328
|
desc "rm PATTERN",
|
255
329
|
"Remove (uninstall, delete) a agent"
|
330
|
+
|
256
331
|
map remove: :rm
|
332
|
+
|
257
333
|
include_options groups: [:pattern, :multi]
|
334
|
+
|
335
|
+
option :logs,
|
336
|
+
desc: "Remove logs too",
|
337
|
+
type: :boolean,
|
338
|
+
default: false
|
339
|
+
|
258
340
|
def rm pattern
|
259
|
-
|
341
|
+
kwds = option_kwds :logs
|
342
|
+
find_multi!( pattern ).each { |agent| agent.remove **kwds }
|
260
343
|
end
|
261
344
|
|
262
345
|
|
263
|
-
|
264
|
-
|
265
|
-
include_options groups: :pattern
|
266
|
-
def plist pattern
|
267
|
-
# TODO Why doesn't this use {#find_only!}?
|
268
|
-
agent = agent_class.find_only! pattern, **option_kwds( :exact )
|
269
|
-
|
270
|
-
if options[:json] || options[:yaml]
|
271
|
-
respond agent.plist
|
272
|
-
else
|
273
|
-
respond agent.path.read
|
274
|
-
end
|
275
|
-
end
|
346
|
+
# Commands for Manipulating Agent State
|
347
|
+
# --------------------------------------------------------------------------
|
276
348
|
|
277
|
-
|
278
349
|
desc "start PATTERN",
|
279
350
|
"Start an agent"
|
351
|
+
|
280
352
|
include_options groups: :pattern
|
281
|
-
|
353
|
+
|
354
|
+
option :load,
|
355
|
+
desc: "Load the agent before starting",
|
356
|
+
type: :boolean,
|
357
|
+
default: true
|
358
|
+
|
359
|
+
option :force,
|
360
|
+
desc: "Force loading of agent even if it's disabled",
|
361
|
+
type: :boolean,
|
362
|
+
default: false
|
363
|
+
|
364
|
+
option :enable,
|
282
365
|
desc: "Set `launchd` *Disabled* key to `false`",
|
283
|
-
type: :boolean
|
366
|
+
type: :boolean,
|
367
|
+
default: false
|
368
|
+
|
284
369
|
def start pattern
|
285
|
-
find_only!( pattern ).start
|
370
|
+
find_only!( pattern ).start **option_kwds( :load, :force, :enable )
|
286
371
|
end
|
287
372
|
|
288
373
|
|
289
374
|
desc "stop PATTERN",
|
290
375
|
"Stop an agent"
|
376
|
+
|
291
377
|
include_options groups: [:pattern, :stop]
|
292
|
-
|
378
|
+
|
379
|
+
option :unload,
|
380
|
+
desc: "Unload the agent from `launchd` after stopping",
|
381
|
+
type: :boolean,
|
382
|
+
default: true
|
383
|
+
|
384
|
+
option :disable,
|
293
385
|
desc: "Set `launchd` *Disabled* key to `true`",
|
294
|
-
type: :boolean
|
386
|
+
type: :boolean,
|
387
|
+
default: false
|
388
|
+
|
295
389
|
def stop pattern
|
296
|
-
find_only!( pattern ).stop **option_kwds( :unload )
|
390
|
+
find_only!( pattern ).stop **option_kwds( :unload, :disable )
|
297
391
|
end
|
298
392
|
|
299
393
|
|
300
394
|
desc "restart PATTERN",
|
301
395
|
"Restart an agent"
|
396
|
+
|
302
397
|
include_options groups: [:pattern, :stop]
|
303
|
-
|
398
|
+
|
399
|
+
option :reload,
|
400
|
+
desc: "Unload and reload the agent in `launchd`",
|
401
|
+
type: :boolean,
|
402
|
+
default: true
|
403
|
+
|
404
|
+
option :force,
|
405
|
+
desc: "Force loading of agent even if it's disabled",
|
406
|
+
type: :boolean,
|
407
|
+
default: false
|
408
|
+
|
409
|
+
option :enable,
|
304
410
|
desc: "Set `launchd` *Disabled* key to `false`",
|
305
|
-
type: :boolean
|
411
|
+
type: :boolean,
|
412
|
+
default: false
|
413
|
+
|
306
414
|
def restart pattern
|
307
|
-
find_only!( pattern ).restart
|
415
|
+
find_only!( pattern ).restart **option_kwds( :reload, :force, :enable )
|
308
416
|
end
|
309
417
|
|
418
|
+
|
419
|
+
# Assorted Other Commands
|
420
|
+
# ----------------------------------------------------------------------------
|
421
|
+
|
422
|
+
desc "open PATTERN",
|
423
|
+
"Open an agent's URL in the browser"
|
424
|
+
|
425
|
+
include_options groups: [:pattern, :multi]
|
426
|
+
|
427
|
+
def open pattern
|
428
|
+
find_multi!( pattern ).each do |agent|
|
429
|
+
Cmds! "open %s", agent.url
|
430
|
+
logger.info "Opened agent `#{ agent.label }` at #{ agent.url }"
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
|
435
|
+
desc 'truncate_logs PATTERN',
|
436
|
+
"Truncate agent log file(s)."
|
437
|
+
|
438
|
+
include_options groups: [:pattern, :multi]
|
439
|
+
|
440
|
+
option :restart,
|
441
|
+
desc: "Restart the agent after truncation",
|
442
|
+
type: :boolean,
|
443
|
+
default: true
|
444
|
+
|
445
|
+
def truncate_logs pattern
|
446
|
+
find_multi!( pattern ).each do |agent|
|
447
|
+
log_paths = [agent.out_path, agent.err_path].compact.uniq
|
448
|
+
|
449
|
+
unless log_paths.empty?
|
450
|
+
restart = options[:restart] && agent.running?
|
451
|
+
|
452
|
+
agent.stop if restart
|
453
|
+
|
454
|
+
log_paths.each do |log_path|
|
455
|
+
begin
|
456
|
+
log_path.open( 'w' ) { |f| f.truncate 0 }
|
457
|
+
rescue Exception => error
|
458
|
+
logger.error "Failed to truncate #{ log_path }", error
|
459
|
+
else
|
460
|
+
logger.info "Truncated",
|
461
|
+
'file' => log_path.to_s,
|
462
|
+
'agent.label' => agent.label
|
463
|
+
end
|
464
|
+
end # each log_path
|
465
|
+
|
466
|
+
agent.start if restart
|
467
|
+
end # unless log_paths.empty?
|
468
|
+
end # each agent
|
469
|
+
end # #truncate_logs
|
470
|
+
|
471
|
+
|
472
|
+
desc 'tail [OPTIONS] PATTERN [-- TAIL_OPTIONS]',
|
473
|
+
"Tail agent logs"
|
474
|
+
|
475
|
+
include_options groups: :pattern
|
476
|
+
|
477
|
+
option :stream,
|
478
|
+
desc: "Stream to tail. May omit if uses single log file.",
|
479
|
+
aliases: ['-s'],
|
480
|
+
type: :string,
|
481
|
+
enum: ['out', 'err']
|
482
|
+
|
483
|
+
def tail pattern, *tail_options
|
484
|
+
agent = find_only! pattern
|
485
|
+
|
486
|
+
path = case options[:stream]
|
487
|
+
when nil
|
488
|
+
paths = agent.log_paths
|
489
|
+
|
490
|
+
unless paths.length == 1
|
491
|
+
raise Thor::RequiredArgumentMissingError.new binding.erb <<~END
|
492
|
+
Agent `<%= agent.label %>` has multiple log files.
|
493
|
+
|
494
|
+
out: <%= agent.out_path.to_s %>
|
495
|
+
err: <%= agent.err_path.to_s %>
|
496
|
+
|
497
|
+
Must specify one via the `--stream` option.
|
498
|
+
|
499
|
+
END
|
500
|
+
end
|
501
|
+
|
502
|
+
paths[0]
|
503
|
+
|
504
|
+
when 'out'
|
505
|
+
agent.out_path
|
506
|
+
|
507
|
+
when 'err'
|
508
|
+
agent.err_path
|
509
|
+
|
510
|
+
else
|
511
|
+
raise "WTF"
|
512
|
+
end
|
513
|
+
|
514
|
+
exec "tail", *tail_options, path.to_s
|
515
|
+
end # #tail
|
516
|
+
|
310
517
|
end # class Locd::CLI::Command::Agent
|