Module: LaunchAgentManagerInstanceMethods

Includes:
LaunchAgentManagerConstants
Included in:
LaunchAgentManager
Defined in:
lib/kanseishitsu/cron/launch_agent_manager_rexml.rb

Overview

Define module LaunchAgentManagerInstanceMethods

Constant Summary

Constants included from LaunchAgentManagerConstants

LaunchAgentManagerConstants::BOOTOUT_TEMPLATE, LaunchAgentManagerConstants::INTERVALS, LaunchAgentManagerConstants::LABEL_NAMESPACE, LaunchAgentManagerConstants::LAUNCHCTL_TEMPLATE, LaunchAgentManagerConstants::LAUNCH_AGENTS_DIR_PATH, LaunchAgentManagerConstants::REMOVE_TEMPLATE, LaunchAgentManagerConstants::SCHEDULE_PARTS_COUNT, LaunchAgentManagerConstants::SUCCESS_MESSAGE, LaunchAgentManagerConstants::VERSION

Instance Method Summary collapse

Instance Method Details

#create_launchd_job(options) ⇒ Object

Create the launchd job



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 160

def create_launchd_job(options)
  args = extract_program_path(options[:executable_path_with_args])
  label = derive_job_label_from_executable(args.first)
  calendar_interval = derive_calendar_interval(options[:cron_schedule])
  plist_doc = LaunchAgentPlist.new(label, args, calendar_interval).to_doc
  plist_path = save_plist(label, plist_doc)
  puts "Executing: cat #{plist_path}"
  puts `cat #{plist_path}`.strip
  load_launchd_job(plist_path)
  puts format(SUCCESS_MESSAGE, label: label)
end

#derive_calendar_interval(cron_schedule) ⇒ Object

Define cron settings for plist



79
80
81
82
83
84
85
86
87
88
89
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 79

def derive_calendar_interval(cron_schedule)
  cron_fields = cron_schedule.split
  calendar_interval = {}
  INTERVALS.each do |key|
    value = cron_fields.shift
    raise "Invalid cron string: #{cron_schedule}" if value.nil? || value.empty?

    calendar_interval[key] = value
  end
  calendar_interval
end

#derive_job_label_from_executable(exe_path) ⇒ Object

Create the job name based on the given executable file path



72
73
74
75
76
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 72

def derive_job_label_from_executable(exe_path)
  label = LABEL_NAMESPACE.dup
  label << File.basename(exe_path, '.*')
  label.join('.')
end

#executable?(exe) ⇒ Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 39

def executable?(exe)
  !exe.empty? && File.executable?(exe) && !File.directory?(exe)
end

#execute(command) ⇒ Object

rubocop: enable Metrics/MethodLength



110
111
112
113
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 110

def execute(command)
  puts "[DEBUG] Executing command: #{command}"
  system(command)
end

#explicit_which(cmd) ⇒ Object



43
44
45
46
47
48
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 43

def explicit_which(cmd)
  exe = `which #{cmd}`.chomp
  executable?(exe) ? exe : nil
rescue Errno::ENOENT => _e
  nil
end

#extract_program_path(executable_with_args) ⇒ Object

Extract program path and arguments, verifying executable rubocop: disable Metrics/MethodLength



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 56

def extract_program_path(executable_with_args)
  *args = executable_with_args.split
  exe = args.shift
  exe_path = File.exist?(exe) ? exe : portable_which(exe)
  if exe_path.nil? || !File.exist?(exe_path)
    abort "Cannot find executable in path: #{exe}"
  end
  if exe_path.nil? || !File.executable?(exe_path) || File.directory?(exe_path)
    abort "Given file is not executable: #{exe}"
  end
  args.unshift(exe_path)
  args
end

#find_executable_in_path(cmd) ⇒ Object



32
33
34
35
36
37
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 32

def find_executable_in_path(cmd)
  directory = ENV['PATH'].split(File::PATH_SEPARATOR).find do |dir|
    File.executable?(File.join(dir, cmd))
  end
  directory.nil? ? nil : File.join(directory, cmd)
end

#launch_agent_labelsObject

Return a list of all user launchd agent labels



129
130
131
132
133
134
135
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 129

def launch_agent_labels
  plist_file_paths = Dir.glob(File.join(LAUNCH_AGENTS_DIR_PATH, '*.plist'))
  plist_file_paths.each_with_object([]) do |file_path, labels|
    label = LaunchAgentPlist.parse(file_path)[:label]
    labels << label unless label.nil?
  end
end

#list_launch_agent_labelsObject

List labels of launchd agents



138
139
140
141
142
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 138

def list_launch_agent_labels
  launch_agent_labels.each do |label|
    puts label
  end
end

#load_launchd_job(plist_path) ⇒ Object

Load the launchd job



116
117
118
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 116

def load_launchd_job(plist_path)
  execute(format(LAUNCHCTL_TEMPLATE, uid: Process.uid, plist: plist_path))
end

#portable_which(cmd) ⇒ Object



50
51
52
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 50

def portable_which(cmd)
  explicit_which(cmd) || find_executable_in_path(cmd)
end

#remove_cron_job(label) ⇒ Object

Remove plist Launch Agents by label



145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 145

def remove_cron_job(label)
  # warn "[DEBUG] Removing launch agent: #{label}"
  plist_path = File.expand_path(File.join(LAUNCH_AGENTS_DIR_PATH, "#{label}.plist"))
  # warn "[DEBUG] Removing launch agent plist definition file: #{plist_path}"
  if File.exist?(plist_path)
    execute(format(BOOTOUT_TEMPLATE, uid: Process.uid, label: label))
    execute(format(REMOVE_TEMPLATE, uid: Process.uid, label: label))
    FileUtils.rm(plist_path)
    puts "Removed launch agent: #{label}"
  else
    warn "Not found; crontab or launch agent: #{label}"
  end
end

#save_plist(label, doc) ⇒ Object

Save plist file to LaunchAgents directory; do not overwrite an already existing file with the same name at the generated path rubocop: disable Metrics/MethodLength



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 94

def save_plist(label, doc)
  FileUtils.mkdir_p(LAUNCH_AGENTS_DIR_PATH)
  plist_path = File.join(LAUNCH_AGENTS_DIR_PATH, "#{label}.plist")
  puts "plist_path: #{plist_path}"
  return plist_path if File.exist?(plist_path)

  document = ''
  formatter = REXML::Formatters::Pretty.new(4)
  formatter.write(doc, document)
  puts '[DEBUG] Contents of plist xml document:'
  puts document
  File.write(plist_path, document)
  plist_path
end

#show_all_cron_jobsObject

Show the launchd agents as crontabs



121
122
123
124
125
126
# File 'lib/kanseishitsu/cron/launch_agent_manager_rexml.rb', line 121

def show_all_cron_jobs
  Dir.glob(File.join(LAUNCH_AGENTS_DIR_PATH, '*.plist')).map do |plist_path|
    job = parse_plist(plist_path)
    puts "#{job[:schedule]} #{job[:command]}"
  end
end