Update comments in the executable and factor out the make_header() function.
[mailshears.git] / bin / mailshears
1 #!/usr/bin/ruby -wU
2 #
3 # mailshears, to prune unused mail directories (and more).
4 #
5
6 # Load all of our lib/ code.
7 require 'mailshears'
8
9 # Define a usage string using the program name.
10 exe = File.basename($PROGRAM_NAME)
11 usage = "#{exe} [prune | rm <target> | mv <src> <dst>]"
12
13 # Defaults
14 mode_name = 'prune'
15 mode = :prune
16
17 # If a mode was supplied, it should be in ARGV[0].
18 if ARGV.length() > 0
19 mode_names = ['prune', 'rm', 'mv']
20 if mode_names.include?(ARGV.first().downcase()) then
21 # Peel the mode name off the head of the list.
22 mode_name = ARGV.shift()
23 end
24 end
25
26 # Determine the mode from its name.
27 if mode_name == 'rm' then
28 mode = :rm
29 elsif mode_name == 'mv' then
30 mode = :mv
31 end
32
33 # Since we removed the mode name (if it existed) from ARGV, what
34 # remains should be the required arguments. Figure out if we have the
35 # wrong number of arguments, and store the associated error message in
36 # args_error_message if necessary.
37 args_error_message = nil
38
39 if mode == :prune and ARGV.length() != 0 then
40 args_error_message = "ERROR: prune mode takes no additional arguments."
41 elsif mode == :rm and ARGV.length() < 1 then
42 args_error_message = "ERROR: rm mode takes two or more user arguments."
43 elsif mode == :mv and ARGV.length() != 2 then
44 args_error_message = "ERROR: mv mode takes exactly two user arguments."
45 end
46
47 # If we got the wrong number of arguments, we'll have an error message
48 # here. Report it and exit with a failure code.
49 if not args_error_message.nil? then
50 STDERR.puts args_error_message
51 puts "Usage: #{usage}"
52 Kernel.exit(ExitCodes::BAD_COMMAND_LINE)
53 end
54
55
56 # Load each of the plugins that we'll need.
57 cfg = Configuration.new()
58
59 cfg.plugins.each do |plugin_file|
60 require "#{mode_name}/plugins/#{plugin_file}"
61 end
62
63 # And the runners.
64 require "#{mode_name}/#{mode_name}_runner"
65 require "#{mode_name}/#{mode_name}_dummy_runner"
66
67 # Now we figure out which plugin module to use based on our mode.
68 plugin_module = nil
69
70 if mode == :rm then
71 plugin_module = RmPlugin
72 elsif mode == :mv then
73 plugin_module = MvPlugin
74 else
75 # Safe, catch-all default
76 plugin_module = PrunePlugin
77 end
78
79 # Parse the remaining arguments as User/Domain objects. If we get some
80 # other argument that isn't one of those, it's an error.
81 parsed_args = []
82
83 ARGV.each do |arg|
84 begin
85 u = User.new(arg)
86 parsed_args << u
87 rescue InvalidUserError
88 begin
89 d = Domain.new(arg)
90 parsed_args << d
91 rescue InvalidDomainError
92 STDERR.puts "ERROR: invalid user/domain argument #{arg}"
93 Kernel.exit(ExitCodes::BAD_COMMAND_LINE)
94 end
95 end
96 end
97
98
99 # Buffer the output so that we can avoid printing the informational
100 # header when no plugins produce output.
101 require 'stringio'
102 output_buffer = StringIO.new()
103 $stdout = output_buffer
104
105 begin
106 plugin_module.run(cfg, *parsed_args)
107 ensure
108 # Now restore stdout, and print the header plus whatever the plugins
109 # produced (if they produced anything). If they didn't produce any
110 # output, then we avoid printing the header.
111 #
112 # This gets wrapped in an "ensure" block because otherwise, if
113 # plugin_module.run() crashes, the traceback will get stored in
114 # output_buffer and never get printed.
115 $stdout = STDOUT
116
117 if output_buffer.size > 0 then
118 puts make_header(exe, plugin_module.to_s())
119 puts output_buffer.string()
120 end
121 end
122
123 # If we made it here without crashing, well that sounds pretty
124 # successful to me.
125 Kernel.exit(ExitCodes::SUCCESS)