akaer 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,8 @@
1
+ language: ruby
1
2
  rvm:
2
3
  - 1.8.7
3
4
  - 1.9.2
4
5
  - 1.9.3
5
6
  script: bundle exec rake spec:coverage
7
+ notifications:
8
+ email: false
@@ -1,51 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- akaer (0.3.0)
5
- cowtech-extensions (~> 2.7.0)
6
- cowtech-lib (~> 2.0.0)
7
- hashie (~> 1.2.0)
8
- rainbow (~> 1.1.0)
4
+ akaer (1.0.0)
5
+ bovem (>= 0.5.0)
6
+ gli (~> 1.6.0)
9
7
 
10
8
  GEM
11
9
  remote: http://rubygems.org/
12
10
  specs:
13
- actionpack (3.2.6)
14
- activemodel (= 3.2.6)
15
- activesupport (= 3.2.6)
11
+ actionpack (3.2.7)
12
+ activemodel (= 3.2.7)
13
+ activesupport (= 3.2.7)
16
14
  builder (~> 3.0.0)
17
15
  erubis (~> 2.7.0)
18
- journey (~> 1.0.1)
16
+ journey (~> 1.0.4)
19
17
  rack (~> 1.4.0)
20
18
  rack-cache (~> 1.2)
21
19
  rack-test (~> 0.6.1)
22
20
  sprockets (~> 2.1.3)
23
- activemodel (3.2.6)
24
- activesupport (= 3.2.6)
21
+ activemodel (3.2.7)
22
+ activesupport (= 3.2.7)
25
23
  builder (~> 3.0.0)
26
- activesupport (3.2.6)
24
+ activesupport (3.2.7)
27
25
  i18n (~> 0.6)
28
26
  multi_json (~> 1.0)
27
+ bovem (0.6.0)
28
+ lazier (~> 1.0)
29
+ rainbow (~> 1.1.0)
29
30
  builder (3.0.0)
30
31
  coderay (1.0.7)
31
- cowtech-extensions (2.7.1)
32
- actionpack (~> 3.0)
33
- json (~> 1.7.0)
34
- tzinfo (~> 0.3.0)
35
- cowtech-lib (2.0.2)
36
- open4
37
32
  diff-lcs (1.1.3)
38
33
  erubis (2.7.0)
39
34
  github-markup (0.7.2)
40
- hashie (1.2.0)
35
+ gli (1.6.0)
41
36
  hike (1.2.1)
42
37
  i18n (0.6.0)
43
38
  journey (1.0.4)
44
- json (1.7.3)
39
+ json (1.7.4)
40
+ lazier (1.0.1)
41
+ actionpack (~> 3.0)
42
+ json (~> 1.7.0)
43
+ tzinfo (~> 0.3.0)
45
44
  method_source (0.8)
46
45
  multi_json (1.3.6)
47
- net-dns (0.7.1)
48
- open4 (1.3.0)
49
46
  pry (0.9.10)
50
47
  coderay (~> 1.0.5)
51
48
  method_source (~> 0.8)
@@ -85,8 +82,7 @@ PLATFORMS
85
82
  DEPENDENCIES
86
83
  akaer!
87
84
  github-markup (~> 0.7.0)
88
- net-dns (~> 0.7.0)
89
- pry (~> 0.9.10)
85
+ pry
90
86
  rake (~> 0.9.0)
91
87
  redcarpet (~> 2.1.0)
92
88
  rspec (~> 2.11.0)
data/README.md CHANGED
@@ -4,21 +4,26 @@
4
4
  [![Dependency Status](https://gemnasium.com/ShogunPanda/akaer.png?travis)](https://gemnasium.com/ShogunPanda/akaer)
5
5
 
6
6
  A small utility to add aliases to network interfaces.
7
+
7
8
  http://github.com/ShogunPanda/akaer
8
9
 
9
10
  ## Description
10
11
 
11
- Akaer is a small utility that adds and remove aliases to your network interfaces. This is useful in web development.
12
+ Akaer is a small utility that adds and removes aliases to your network interfaces. This is useful in web development.
12
13
 
13
14
  ## Basic usage
14
15
 
15
16
  1. Install the gem:
16
17
 
17
- `gem install akaer`
18
+ ```sh
19
+ gem install akaer
20
+ ```
18
21
 
19
22
  2. Run the application:
20
23
 
21
- `akaer`
24
+ ```sh
25
+ akaer
26
+ ```
22
27
 
23
28
  **You're done!**
24
29
 
@@ -33,23 +38,23 @@ By defaults, Akaer uses a configuration file in `~/.akaer_config`, but you can c
33
38
  The file is a plain Ruby file with a single `config` object that supports the following directives.
34
39
 
35
40
  * `interface`: The network interface to manage. `lo0` by default.
36
- * `address`: A specific list of aliases to manage.
37
- * `start-address`: The address to start sequential address. `10.0.0.1` by default. Not used if `addresses` is specified.
41
+ * `addresses`: A specific list of aliases to manage.
42
+ * `start_address`: The address to start sequential address. `10.0.0.1` by default. Not used if `addresses` is specified.
38
43
  * `aliases`: The number of sequential addresses to add. 5 by default.
44
+ * `add_command`: The command to run for adding an alias. `sudo ifconfig @INTERFACE@ alias @ALIAS@` by default.
45
+ * `remove_command`: The command to run for removing an alias. `sudo ifconfig @INTERFACE@ -alias @ALIAS@` by default.
39
46
  * `log_file`: The default log file. By default it logs to standard output.
40
47
  * `log_level`: The default log level. Valid values are from 0 to 5 where 0 means "all messages".
41
-
42
- ## Remarks
43
-
44
- Akaer is tightly coupled with the UNIX tools, so it won't work for Windows.
48
+ * `dry_run`: Only show which modifications will be done.
49
+ * `quiet`: Do not show any message.
45
50
 
46
51
  ## Contributing to akaer
47
52
 
48
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
49
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
50
- * Fork the project
51
- * Start a feature/bugfix branch
52
- * Commit and push until you are happy with your contribution
53
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
54
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
55
+ * Fork the project.
56
+ * Start a feature/bugfix branch.
57
+ * Commit and push until you are happy with your contribution.
53
58
  * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
54
59
  * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
55
60
 
@@ -21,16 +21,13 @@ Gem::Specification.new do |gem|
21
21
  gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  gem.require_paths = ["lib"]
23
23
 
24
- gem.add_dependency("cowtech-extensions", "~> 2.7.0")
25
- gem.add_dependency("cowtech-lib", "~> 2.0.0")
26
- gem.add_dependency("hashie", "~> 1.2.0")
27
- gem.add_dependency("rainbow", "~> 1.1.0")
24
+ gem.add_dependency("bovem", ">= 0.5.0")
25
+ gem.add_dependency("gli", "~> 1.6.0")
28
26
 
29
27
  gem.add_development_dependency("rspec", "~> 2.11.0")
30
28
  gem.add_development_dependency("rake", "~> 0.9.0")
31
29
  gem.add_development_dependency("simplecov", "~> 0.6.0")
32
- gem.add_development_dependency("pry", "~> 0.9.10")
33
- gem.add_development_dependency("net-dns", "~> 0.7.0")
30
+ gem.add_development_dependency("pry", ">= 0")
34
31
  gem.add_development_dependency("yard", "~> 0.8.0")
35
32
  gem.add_development_dependency("redcarpet", "~> 2.1.0")
36
33
  gem.add_development_dependency("github-markup", "~> 0.7.0")
data/bin/akaer CHANGED
@@ -6,4 +6,86 @@
6
6
 
7
7
  require "rubygems"
8
8
  require "akaer"
9
- Akaer::Application.start
9
+ require "gli"
10
+
11
+ include GLI
12
+
13
+ program_desc("A small utility to add aliases to network interfaces.")
14
+ version(Akaer::Version::STRING)
15
+
16
+ desc("The default interface to manage.")
17
+ default_value("lo0")
18
+ arg_name("INTERFACE")
19
+ flag(:i, :interface)
20
+
21
+ desc("The default list of aliases to add.")
22
+ default_value([])
23
+ arg_name("ADDRESSES")
24
+ flag(:A, :addresses)
25
+
26
+ desc("The starting address for sequential aliases.")
27
+ default_value("10.0.0.1")
28
+ arg_name("ADDRESS")
29
+ flag(:s, :"start-address")
30
+
31
+ desc("The number of aliases to add.")
32
+ default_value(5)
33
+ arg_name("ALIASES")
34
+ flag(:S, :aliases)
35
+
36
+ desc("The command to run for adding an alias.")
37
+ default_value("sudo ifconfig @INTERFACE@ alias @ALIAS@")
38
+ arg_name("COMMAND")
39
+ flag(:c, :"add-command")
40
+
41
+ desc("The command to run for adding an alias.")
42
+ default_value("sudo ifconfig @INTERFACE@ -alias @ALIAS@")
43
+ arg_name("COMMAND")
44
+ flag(:C, :"remove-command")
45
+
46
+ desc("The default log file.")
47
+ default_value("STDOUT")
48
+ arg_name("LOG")
49
+ flag([:l, :log])
50
+
51
+ desc("The default log level. Valid values are from 0 to 5 where 0 means \"all messages\".")
52
+ default_value(1)
53
+ arg_name("LEVEL")
54
+ flag([:L, :"log-level"])
55
+
56
+ desc("Only show which modifications will be done")
57
+ switch([:n, :"dry-run"])
58
+
59
+ desc("Do not show any message.")
60
+ switch([:q, :quiet])
61
+
62
+ desc("Add aliases.")
63
+ command [:a, :add] do |c|
64
+ c.action do |globals, locals, args|
65
+ Akaer::Application.instance(globals, locals, args).action_add()
66
+ end
67
+ end
68
+
69
+ desc("Remove aliases.")
70
+ command [:r, :remove] do |c|
71
+ c.action do |globals, locals, args|
72
+ Akaer::Application.instance(globals, locals, args).action_remove()
73
+ end
74
+ end
75
+
76
+ desc("Install the application for autolaunch.")
77
+ command [:i, :install] do |c|
78
+ c.action do |globals, locals, args|
79
+ Akaer::Application.instance(globals, locals, args).action_install()
80
+ end
81
+ end
82
+
83
+ desc("Uninstall the application from autolaunch.")
84
+ command [:u, :uninstall] do |c|
85
+ c.action do |globals, locals, args|
86
+ Akaer::Application.instance(globals, locals, args).action_uninstall()
87
+ end
88
+ end
89
+
90
+ ARGV << "help" if ARGV.length == 0
91
+ exit(GLI.run(ARGV))
@@ -4,16 +4,9 @@
4
4
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
5
  #
6
6
 
7
- require "cowtech-extensions"
8
- require "cowtech-lib"
7
+ require "bovem"
9
8
  require "ipaddr"
10
- require "hashie"
11
- require "rainbow"
12
- require "pathname"
13
9
 
14
10
  require "akaer/version" if !defined?(Akaer::Version)
15
- require "akaer/errors"
16
- require "akaer/logger"
17
11
  require "akaer/configuration"
18
- require "akaer/application"
19
-
12
+ require "akaer/application"
@@ -4,104 +4,312 @@
4
4
  # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
5
  #
6
6
 
7
- require "cowtech-lib"
8
- require "ipaddr"
7
+ # A small utility to add aliases to network interfaces.
8
+ module Akaer
9
+ # The main Akaer application.
10
+ class Application
11
+ # The {Configuration Configuration} of this application.
12
+ attr_reader :config
9
13
 
10
- class Fixnum
11
- def i(num = 3)
12
- self.to_s.rjust(num, "0")
13
- end
14
- end
14
+ # The arguments passed via command-line.
15
+ attr_reader :args
15
16
 
16
- module Akaer
17
- class Application < Cowtech::Lib::Script
18
- def self.start
19
- self.new
17
+ # The logger for this application.
18
+ attr_accessor :logger
19
+
20
+ # Creates a new application.
21
+ #
22
+ # @param globals [Hash] Global options.
23
+ # @param locals [Hash] Local command options.
24
+ # @param args [Array] Extra arguments.
25
+ def initialize(globals = {}, locals = {}, args = [])
26
+ @args = {
27
+ :global => globals,
28
+ :local => locals,
29
+ :args => args
30
+ }
31
+
32
+ # Setup logger
33
+ Bovem::Logger.start_time = Time.now
34
+ @logger = Bovem::Logger.create(Bovem::Logger.get_real_file(@args[:global][:log_file]) || Bovem::Logger.default_file, Logger::INFO)
35
+
36
+ # Open configuration
37
+ begin
38
+ overrides = {
39
+ :interface => @args[:global][:interface],
40
+ :addresses => @args[:global][:addresses],
41
+ :start_address => @args[:global][:"start-address"],
42
+ :aliases => @args[:global][:aliases],
43
+ :add_command => @args[:global][:"add-command"],
44
+ :remove_command => @args[:global][:"remove-command"],
45
+ :log_file => @args[:global][:"log-file"],
46
+ :log_level => @args[:global][:"log-level"],
47
+ :dry_run => @args[:global][:"dry-run"],
48
+ :quiet => @args[:global][:quiet]
49
+ }.reject {|k,v| v.nil? }
50
+
51
+ @config = Akaer::Configuration.new(@args[:global][:config], overrides, @logger)
52
+
53
+ @logger = nil
54
+ @logger = self.get_logger
55
+ rescue Bovem::Errors::InvalidConfiguration => e
56
+ @logger ? @logger.fatal(e.message) : Bovem::Logger.create("STDERR").fatal("Cannot log to #{config.log_file}. Exiting...")
57
+ raise ::SystemExit
58
+ end
59
+
60
+ self
20
61
  end
21
62
 
22
- def initialize
23
- super(:args => {:name => "Interface aliases", :version => 1.0, :description => "A small utility to add aliases to network interfaces.", :usage => "Usage: #{ARGV[0]} [OPTIONS] [add|remove]"})
63
+ # Checks if we are running on MacOS X.
64
+ # System services are only available on that platform.
65
+ #
66
+ # @return [Boolean] `true` if the current platform is MacOS X, `false` otherwise.
67
+ def is_osx?
68
+ ::Config::CONFIG['host_os'] =~ /^darwin/
24
69
  end
25
70
 
26
- def add_options
27
- @options_parser << [
28
- {:name => "configuration", :short => "-c", :long => "--configuration", :type => :string, :help => "Configuration file. By default is the standard output", :meta => "FILE", :required => false, :default => "~/.akaer_config"},
29
- {:name => "interface", :short => "-i", :long => "--interface", :type => :string, :help => "Interface", :meta => "INTERFACE", :required => false, :default => "lo0"},
30
- {:name => "addresses", :short => "-A", :long => "--addresses", :type => :list, :help => "Addresses to add", :required => false, :default => []},
31
- {:name => "start-address", :short => "-s", :long => "--start-address", :type => :string, :help => "Starting address (not used if --addresses is specified).", :meta => "ADDRESS", :required => false, :default => "10.0.0.1"},
32
- {:name => "aliases", :short => "-S", :long => "--aliases", :type => :int, :help => "Number of aliases to add", :meta => "NUMBER", :required => false, :default => 5},
33
- {:name => "log-file", :short => "-l", :long => "--log-file", :type => :string, :help => "Log file. By default is the standard output", :meta => "FILE", :required => false, :default => "STDOUT"},
34
- {:name => "log-level", :short => "-L", :long => "--log-level", :type => :int, :help => "The default log level. Valid values are from 0 to 5 where 0 means \"all messages\".", :meta => "NUMBER", :required => false, :default => Logger::INFO},
35
- {:name => "dry-run", :short => "-n", :long => "--dry-run", :type => :bool, :help => "Do not really execute actions."},
36
- {:name => "quiet", :short => "-q", :long => "--quiet", :type => :bool, :help => "Do not show any message", :required => false, :default => false}
37
- ]
71
+ # Checks if and address is a valid IPv4 address.
72
+ #
73
+ # @param address [String] The address to check.
74
+ # @return [Boolean] `true` if the address is a valid IPv4 address, `false` otherwise.
75
+ def is_ipv4?(address)
76
+ address = address.ensure_string
77
+
78
+ mo = /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/.match(address)
79
+ rv = (mo && mo.captures.all? {|i| i.to_i < 256}) ? true : false
38
80
  end
39
81
 
40
- def execute_command(interface, action, ip, prefix = "")
41
- prefix += " " if !prefix.blank?
42
- @logger.info("#{prefix}#{(action == "add" ? "Adding" : "Removing").bright} alias #{ip.bright} #{action == "add" ? "to" : "from"} interface #{interface.bright}.")
43
- system("sudo ifconfig #{interface} #{action == "add" ? "alias" : "-alias"} #{ip}")
82
+ # Checks if and address is a valid IPv4 address.
83
+ #
84
+ # @param address [String] The address to check.
85
+ # @return [Boolean] `true` if the address is a valid IPv4 address, `false` otherwise.
86
+ def is_ipv6?(address)
87
+ address = address.ensure_string
88
+
89
+ rv = catch(:valid) do
90
+ # IPv6 (normal)
91
+ throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ address
92
+ throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ address
93
+ throw(:valid, true) if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ address
94
+ # IPv6 (IPv4 compat)
95
+ throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ address && self.is_ipv4?($')
96
+ throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ address && self.is_ipv4?($')
97
+ throw(:valid, true) if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ address && self.is_ipv4?($')
98
+
99
+ false
100
+ end
44
101
  end
45
102
 
46
- def run
47
- @logger = Akaer::Logger.create(@options_parser["log-file"], @options_parser["log-level"])
48
103
 
49
- command = (@options_parser.args[0] || "add").downcase
50
- aliases = []
51
- target_address = ""
104
+ # Pads a number to make it print friendly.
105
+ #
106
+ # @param num [Fixnum] The number to pad.
107
+ # @param len [Fixnum] The minimum length of the padded string.
108
+ # @return [String] The padded number.
109
+ def pad_number(num, len = nil)
110
+ num.to_integer.to_s.rjust([len.to_integer, 2].max, "0")
111
+ end
52
112
 
53
- # Parse configuration file
54
- configuration = Akaer::Configuration.load(@options_parser["configuration"], @logger)
113
+ # Gets the current logger of the application.
114
+ #
115
+ # @return [Logger] The current logger of the application.
116
+ def get_logger
117
+ @logger ||= Bovem::Logger.create(Bovem::Logger.default_file, @config.log_level, @log_formatter)
118
+ end
55
119
 
56
- # Now merge with the options
57
- @options_parser[].each_pair do |option, value|
58
- key = option.to_s.gsub("-", "_")
59
- configuration[key] = value if configuration.has_key?(key) && @options_parser.provided?(option)
60
- end
120
+ # Gets the path for the launch agent file.
121
+ #
122
+ # @param name [String] The base name for the agent.
123
+ # @return [String] The path for the launch agent file.
124
+ def launch_agent_path(name = "it.cowtech.akaer")
125
+ ENV["HOME"] + "/Library/LaunchAgents/#{name}.plist"
126
+ end
61
127
 
62
- # Instantiate the logger
63
- logger = Akaer::Logger.create(configuration.log_file, configuration.log_level)
128
+ # Executes a shell command.
129
+ #
130
+ # @param command [String] The command to execute.
131
+ # @return [Boolean] `true` if command succeeded, `false` otherwise.
132
+ def execute_command(command)
133
+ Kernel.system(command)
134
+ end
64
135
 
65
- # Create address
66
- if !["add", "remove"].include?(command) then
67
- @logger.fatal("\"Please choose an action between \"add\" or \"remove\".")
68
- abort
69
- end
136
+ # Computes the list of address to manage.
137
+ #
138
+ # @param type [Symbol] The type of addresses to consider. Valid values are `:ipv4`, `:ipv6`, otherwise all addresses are considered.
139
+ # @return [Array] The list of addresses to add or remove from the interface.
140
+ def compute_addresses(type = :all)
141
+ rv = []
70
142
 
71
- begin
72
- if configuration.addresses.blank? then
73
- target_address = configuration.start_address
74
- temp = IPAddr.new(target_address)
75
-
76
- [configuration.aliases, 1].max.times do
77
- aliases << temp.to_s
78
- temp = temp.succ
79
- target_address = temp.to_s
80
- end
81
- else
82
- configuration.addresses.each do |t|
83
- target_address = t
84
- aliases << IPAddr.new(target_address)
143
+ if self.config.addresses.present? # We have an explicit list
144
+ rv = self.config.addresses
145
+
146
+ # Now filter the addresses
147
+ filters = [type != :ipv6 ? :ipv4 : nil, type != :ipv4 ? :ipv6 : nil].compact
148
+ rv = rv.select {|address|
149
+ filters.any? {|filter| self.send("is_#{filter}?", address) }
150
+ }.compact.uniq
151
+ else
152
+ begin
153
+ ip = IPAddr.new(self.config.start_address.ensure_string)
154
+ raise ArgumentError if (type == :ipv4 && !ip.ipv4?) || (type == :ipv6 && !ip.ipv6?)
155
+
156
+ (self.config.aliases > 0 ? self.config.aliases : 5).times do
157
+ rv << ip.to_s
158
+ ip = ip.succ
85
159
  end
160
+ rescue ArgumentError
86
161
  end
87
- rescue ArgumentError => e
88
- logger.fatal("\"#{target_address}\" is not a valid IP address.")
89
- abort
90
162
  end
91
163
 
92
- if !@options_parser["dry-run"] then
93
- total = aliases.length
94
- rj = total.to_s.length
95
- aliases.each_with_index do |a, i|
96
- prefix = "[#{(i + 1).to_s.rjust(rj, "0")}/#{total}]"
97
- if !self.execute_command(configuration.interface, command, a, prefix) then
98
- logger.fatal("#{command == "add" ? "Adding" : "Removing"} alias #{a} failed.")
99
- abort
100
- end
101
- end
164
+ rv
165
+ end
166
+
167
+ # Adds or removes an alias from the interface
168
+ #
169
+ # @param type [Symbol] The operation to execute. Can be `:add` or `:remove`.
170
+ # @param address [String] The address to manage.
171
+ # @return [Boolean] `true` if operation succedeed, `false` otherwise.
172
+ def manage(type, address)
173
+ rv = true
174
+
175
+ # Compute the command
176
+ command = (type == :remove) ? self.config.remove_command : self.config.add_command
177
+
178
+ # Interpolate
179
+ command = command.gsub("@INTERFACE@", self.config.interface).gsub("@ALIAS@", address) + " > /dev/null 2>&1"
180
+
181
+ # Compute the prefix
182
+ @addresses ||= self.compute_addresses
183
+ length = self.pad_number(@addresses.length)
184
+ index = (@addresses.index(address) || 0) + 1
185
+ prefix = ["[".color(:cyan), self.pad_number(index, length.length).bright, "/".color(:cyan), length.bright, "]".color(:cyan)].join("")
186
+
187
+ # Now execute
188
+ if !self.config.dry_run then
189
+ @logger.info("#{prefix} #{(type == :remove ? "Removing" : "Adding").bright} address #{address.bright} #{type != :remove ? "to" : "from"} interface #{self.config.interface.bright}...") if !self.config.quiet
190
+ rv = self.execute_command(command)
191
+
192
+ # TODO: The end badge.
193
+ else
194
+ @logger.info("#{prefix} I will #{(type == :remove ? "remove" : "add").bright} address #{address.bright} #{type != :remove ? "to" : "from"} interface #{self.config.interface.bright}.") if !self.config.quiet
195
+ end
196
+
197
+ rv
198
+ end
199
+
200
+ # Adds aliases to the interface.
201
+ #
202
+ # @return [Boolean] `true` if action succedeed, `false` otherwise.
203
+ def action_add
204
+ addresses = self.compute_addresses
205
+
206
+ if addresses.present? then
207
+ # Now, for every address, call the command
208
+ addresses.all? {|address|
209
+ self.manage(:add, address)
210
+ }
211
+ else
212
+ @logger.error("No valid addresses to add to the interface found.") if !self.config.quiet
213
+ end
214
+ end
215
+
216
+ # Removes aliases from the interface.
217
+ #
218
+ # @return [Boolean] `true` if action succedeed, `false` otherwise.
219
+ def action_remove
220
+ addresses = self.compute_addresses
221
+
222
+ if addresses.present? then
223
+ # Now, for every address, call the command
224
+ addresses.all? {|address|
225
+ self.manage(:remove, address)
226
+ }
102
227
  else
103
- @logger.info("I will #{command.bright} #{aliases.length == 1 ? "this alias" : "these aliases"} #{command == "add" ? "to" : "from"} interface #{configuration.interface.bright}: #{aliases.collect {|a| a.bright}.join(", ")}.")
228
+ @logger.error("No valid addresses to remove from the interface found.") if !self.config.quiet
229
+ end
230
+ end
231
+
232
+ # Installs the application into the autolaunch.
233
+ #
234
+ # @return [Boolean] `true` if action succedeed, `false` otherwise.
235
+ def action_install
236
+ logger = get_logger
237
+
238
+ if !self.is_osx? then
239
+ logger.fatal("Install akaer on autolaunch is only available on MacOSX.") if !self.config.quiet
240
+ return false
241
+ end
242
+
243
+ launch_agent = self.launch_agent_path
244
+
245
+ begin
246
+ logger.info("Creating the launch agent in #{launch_agent} ...") if !self.config.quiet
247
+
248
+ args = $ARGV ? $ARGV[0, $ARGV.length - 1] : []
249
+
250
+ plist = {"KeepAlive" => false, "Label" => "it.cowtech.akaer", "Program" => (::Pathname.new(Dir.pwd) + $0).to_s, "ProgramArguments" => args, "RunAtLoad" => true}
251
+ ::File.open(launch_agent, "w") {|f|
252
+ f.write(plist.to_json)
253
+ f.flush
254
+ }
255
+ self.execute_command("plutil -convert binary1 \"#{launch_agent}\"")
256
+ rescue => e
257
+ logger.error("Cannot create the launch agent.") if !self.config.quiet
258
+ return false
104
259
  end
260
+
261
+ begin
262
+ logger.info("Loading the launch agent ...") if !self.config.quiet
263
+ self.execute_command("launchctl load -w \"#{launch_agent}\" > /dev/null 2>&1")
264
+ rescue => e
265
+ logger.error("Cannot load the launch agent.") if !self.config.quiet
266
+ return false
267
+ end
268
+
269
+ true
270
+ end
271
+
272
+ # Uninstalls the application from the autolaunch.
273
+ #
274
+ # @return [Boolean] `true` if action succedeed, `false` otherwise.
275
+ def action_uninstall
276
+ logger = self.get_logger
277
+
278
+ if !self.is_osx? then
279
+ logger.fatal("Install akaer on autolaunch is only available on MacOSX.") if !self.config.quiet
280
+ return false
281
+ end
282
+
283
+ launch_agent = self.launch_agent_path
284
+
285
+ # Unload the launch agent.
286
+ begin
287
+ self.execute_command("launchctl unload -w \"#{launch_agent}\" > /dev/null 2>&1")
288
+ rescue => e
289
+ logger.warn("Cannot unload the launch agent.") if !self.config.quiet
290
+ end
291
+
292
+ # Delete the launch agent.
293
+ begin
294
+ logger.info("Deleting the launch agent #{launch_agent} ...")
295
+ ::File.delete(launch_agent)
296
+ rescue => e
297
+ logger.warn("Cannot delete the launch agent.") if !self.config.quiet
298
+ return false
299
+ end
300
+
301
+ true
302
+ end
303
+
304
+ # Returns a unique (singleton) instance of the application.
305
+ # @param globals [Hash] Global options.
306
+ # @param locals [Hash] Local command options.
307
+ # @param args [Array] Extra arguments.
308
+ # @param force [Boolean] If to force recreation of the instance.
309
+ # @return [Application] The unique (singleton) instance of the application.
310
+ def self.instance(globals = {}, locals = {}, args = [], force = false)
311
+ @instance = nil if force
312
+ @instance ||= Akaer::Application.new(globals, locals, args)
105
313
  end
106
314
  end
107
315
  end