mac-wifi 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +51 -17
- data/bin/mac-wifi +174 -151
- data/mac-wifi.gemspec +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ad551f63f23b9370fc52e8206e4b7314efd99e3
|
4
|
+
data.tar.gz: b2d4b85d37dc5e964f2dd7fe054233fcd54f66c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef70403c2cbd5731e2835a79ea6334278c34746c06970cf074e3a6006e520d343d90d91db070007b7cfd7c96b065ee9e942b3f495c308cb3f56dbeee24bb7a47
|
7
|
+
data.tar.gz: 5a8ccde48e2cf1e28b9f4cdaaaa02f97ef39b4657988fd318e3f9fbc75a67e0e0f824e189eaba72de2c608c53aa65d5733c3f2d00f3bc178433608d8768fc7b4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# mac-wifi
|
2
2
|
|
3
|
-
|
3
|
+
The script installed by this gem (or otherwise copied) enables the query and management of wifi configuration and environment on a Mac.
|
4
|
+
The code encapsulates the Mac OS specific logic in a minimal class to more easily add support for other operating systems,
|
5
|
+
but as of now, only Mac OS is supported. (Feel free to add an OS!)
|
4
6
|
|
5
7
|
It can be run in single-command or interactive mode. Interactive mode uses the `pry` gem,
|
6
8
|
providing an interface familiar to Rubyists and other
|
7
9
|
[REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) users.
|
8
10
|
|
9
|
-
It is not necessary to download this repo
|
11
|
+
It is not necessary to download this repo or even install this gem; the `bin/mac-wifi` script file is all you need to run the application.
|
12
|
+
|
10
13
|
|
11
14
|
### Usage
|
12
15
|
|
@@ -48,6 +51,7 @@ Internally, it uses several Mac command line utilities. This is not ideal,
|
|
48
51
|
I would have preferred OS system calls, but the current approach enabled me to develop
|
49
52
|
this script quickly and simply.
|
50
53
|
|
54
|
+
|
51
55
|
### Pretty Output
|
52
56
|
|
53
57
|
For nicely formatted output of the `info` command in non-interactive mode,
|
@@ -83,7 +87,7 @@ of stale data.
|
|
83
87
|
|
84
88
|
If you try to run the shell, the script will require the `pry` gem, so that will need to be installed.
|
85
89
|
`pry` in turn requires access to a `readline` library. If you encounter an error relating to finding a
|
86
|
-
`readline` library, this can be fixed by installing the `pry-coolline` gem: `gem install pry-coolline`.
|
90
|
+
`readline` library, this can probably be fixed by installing the `pry-coolline` gem: `gem install pry-coolline`.
|
87
91
|
If you are using the Ruby packaged with Mac OS, or for some other reason require root access to install
|
88
92
|
gems, you will need to precede those commands with `sudo`:
|
89
93
|
|
@@ -105,6 +109,7 @@ session. It can be useful when:
|
|
105
109
|
* you want to combine the results of commands with other OS commands
|
106
110
|
(you can shell out to run other command line programs by preceding the command with a period (`.`).
|
107
111
|
|
112
|
+
|
108
113
|
### Using Variables in the Shell
|
109
114
|
|
110
115
|
There are a couple of things (that may be surprising) to keep in mind
|
@@ -123,12 +128,12 @@ may override this app's commands. For example:
|
|
123
128
|
=> 123
|
124
129
|
[3] pry(#<MacWifiView>)> n # 'n' no longer calls the method
|
125
130
|
=> 123
|
126
|
-
[4] pry(#<MacWifiView>)> ne # but any other name
|
131
|
+
[4] pry(#<MacWifiView>)> ne # but any other name that `network_name starts with will still call the method
|
127
132
|
=> ".@ AIS SUPER WiFi"
|
128
133
|
[5] pry(#<MacWifiView>)> network_name
|
129
134
|
=> ".@ AIS SUPER WiFi"
|
130
135
|
[6] pry(#<MacWifiView>)> ne_xzy123
|
131
|
-
|
136
|
+
"ne_xyz123" is not a valid command or option. If you intend for this to be a string literal, use quotes.
|
132
137
|
```
|
133
138
|
|
134
139
|
If you don't want to deal with this, you could use global variables, instance variables,
|
@@ -150,7 +155,6 @@ or constants, which will _not_ hide the methods:
|
|
150
155
|
the result may be mysterious. For example, if I were write the wifi information
|
151
156
|
to a file, this would work:
|
152
157
|
|
153
|
-
|
154
158
|
```
|
155
159
|
[1] pry(#<MacWifiView>)> File.write('x.txt', info)
|
156
160
|
=> 431
|
@@ -210,8 +214,12 @@ You are connected on port en0 to .@ AIS SUPER WiFi on IP address 172.27.145.225.
|
|
210
214
|
> puts "There are #{lsp.size} preferred networks."
|
211
215
|
There are 341 preferred networks.
|
212
216
|
|
213
|
-
# Delete all preferred networks whose names begin with "TOTTGUEST":
|
214
|
-
> lsp.grep(/^TOTTGUEST/).each { |n|
|
217
|
+
# Delete all preferred networks whose names begin with "TOTTGUEST", the hard way:
|
218
|
+
> lsp.grep(/^TOTTGUEST/).each { |n| rm(n) }
|
219
|
+
|
220
|
+
# Delete all preferred networks whose names begin with "TOTTGUEST", the easy way.
|
221
|
+
# rm can take multiple network names, but they must be specified as separate parameters; thus the '*'.
|
222
|
+
> rm(*lsp.grep(/^TOTTGUEST/))
|
215
223
|
|
216
224
|
# Define a method to wait for the Internet connection to be active.
|
217
225
|
# (This functionality is included in the `till` command.)
|
@@ -227,15 +235,34 @@ Connected!
|
|
227
235
|
Connected!
|
228
236
|
```
|
229
237
|
|
230
|
-
### Cautions
|
231
238
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
239
|
+
### Distribution, or Why All The Code is in One Humongous File
|
240
|
+
|
241
|
+
This code would be neater and easier to read if each class were in a file of its own.
|
242
|
+
The reason everything is in one file is to simplify distribution for some users.
|
243
|
+
Although installation as a gem is simple, being able to download a single file may work better when:
|
244
|
+
|
245
|
+
* the user wants to install the script once, rather than once per Ruby version and/or gemset.
|
246
|
+
* the user needs or wants to specify the exact location of the script (e.g. `~/bin`),
|
247
|
+
and/or does not want it buried in the gem directory tree (e.g. `/Users/kbennett/.rvm/gems/ruby-2.4.0/bin/mac-wifi`).
|
248
|
+
* the user is not familiar with Ruby and does not want to use the `gem` command
|
249
|
+
* the user is concerned about security and would prefer to install a single file to a known location
|
250
|
+
rather than run the gem installation
|
251
|
+
* installing gems is controlled by the user's organization, and getting authorization is not practical
|
252
|
+
* installing gems requires root access, and the user does not have root access
|
237
253
|
|
254
|
+
That said, installation as a gem is highly recommended, since:
|
238
255
|
|
256
|
+
* this will greatly simplify acquiring future fixes and enhancements
|
257
|
+
* if the user wants to use the shell mode, they will need to `gem install pry` anyway
|
258
|
+
|
259
|
+
Currently, the only gems used by the program are:
|
260
|
+
|
261
|
+
* `pry`, to provide the interactive shell
|
262
|
+
* `awesome_print` (optional), to more nicely format output in non-interactive mode
|
263
|
+
|
264
|
+
So the user can avoid installing gems altogether as long as they don't need to use the interactive shell,
|
265
|
+
and as long as they are comfortable with the less pretty output.
|
239
266
|
|
240
267
|
### Password Lookup Oddity
|
241
268
|
|
@@ -244,10 +271,17 @@ You may find it odd (I did, anyway) that even if you issue the password command
|
|
244
271
|
with a graphical dialog for both a user id and password. This is no doubt
|
245
272
|
for better security, but it's unfortunate in that it makes it impossible to fully automate this task.
|
246
273
|
|
247
|
-
In particular, it would be nice for the `cycle` command to be able to
|
248
|
-
|
274
|
+
In particular, it would be nice for the `cycle` command to be able to fetch the current network's
|
275
|
+
password, cycle the network, and then reconnect to the original network with it after turning the network on.
|
276
|
+
However, since fetching the password without user intervention is not possible, this cannot be automated.
|
277
|
+
|
249
278
|
If you don't mind storing the network password in plain text somewhere, then you could easily
|
250
|
-
automate it (e.g. `mac-wifi cycle && mac-wifi connect a-network a-password`).
|
279
|
+
automate it (e.g. `mac-wifi cycle && mac-wifi connect a-network a-password`). Also, you might find it handy
|
280
|
+
to create a script for your most commonly used networks containing something like this:
|
281
|
+
|
282
|
+
```
|
283
|
+
mac-wifi connect my-usual-network its-password
|
284
|
+
```
|
251
285
|
|
252
286
|
|
253
287
|
### License
|
data/bin/mac-wifi
CHANGED
@@ -26,40 +26,34 @@ require 'tempfile'
|
|
26
26
|
module MacWifi
|
27
27
|
|
28
28
|
# This version must be kept in sync with the version in the gemspec file.
|
29
|
-
VERSION = '0.0
|
29
|
+
VERSION = '1.0.0'
|
30
30
|
|
31
|
-
class Model
|
32
|
-
|
33
|
-
AIRPORT_CMD = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport'
|
34
31
|
|
32
|
+
class BaseModel
|
35
33
|
|
36
34
|
def initialize(verbose = false)
|
37
35
|
@verbose_mode = verbose
|
38
36
|
end
|
39
37
|
|
40
38
|
|
41
|
-
def connected_to_internet_curl_unused?
|
42
|
-
|
43
|
-
connected = false
|
44
|
-
|
45
|
-
begin
|
46
|
-
run_os_command('curl --silent --head http://www.google.com/')
|
47
|
-
connected = true
|
48
|
-
rescue OsCommandError => e
|
49
|
-
if e.exitstatus == 6
|
50
|
-
connected = false
|
51
|
-
else
|
52
|
-
raise
|
53
|
-
end
|
54
|
-
end
|
55
|
-
connected
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
39
|
# This method returns whether or not there is a working Internet connection.
|
60
40
|
# Because of a Mac issue which causes a request to hang if the network is turned
|
61
41
|
# off during its lifetime, we give it only 5 seconds per try,
|
62
42
|
# and limit the number of tries to 3.
|
43
|
+
#
|
44
|
+
# This implementation will probably strike you as overly complex. The following
|
45
|
+
# code looks like it is all that should be necessary, but unfortunately
|
46
|
+
# this implementation often hangs when wifi is turned off while curl is active
|
47
|
+
#
|
48
|
+
# def connected_to_internet?
|
49
|
+
# script = "curl --silent --head http://www.google.com/ > /dev/null ; echo $?"
|
50
|
+
# result = `#{script}`.chomp
|
51
|
+
# puts result
|
52
|
+
# result == '0'
|
53
|
+
# end
|
54
|
+
|
55
|
+
# TODO Investigate using Curl options: --connect-timeout 1 --max-time 2 --retry 0
|
56
|
+
# to greatly simplify this method.
|
63
57
|
def connected_to_internet?
|
64
58
|
|
65
59
|
tempfile = Tempfile.open('mac-wifi-')
|
@@ -94,7 +88,7 @@ class Model
|
|
94
88
|
return get_connected_state_from_curl.()
|
95
89
|
end
|
96
90
|
end
|
97
|
-
Process.kill('KILL', pid)
|
91
|
+
Process.kill('KILL', pid) if process_is_running.(pid)
|
98
92
|
:hung
|
99
93
|
end
|
100
94
|
|
@@ -111,13 +105,109 @@ class Model
|
|
111
105
|
|
112
106
|
end
|
113
107
|
|
114
|
-
|
115
|
-
#
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
108
|
+
|
109
|
+
# Turns wifi off and then on, reconnecting to the originally connecting network.
|
110
|
+
def cycle_network
|
111
|
+
# TODO: Make this network name saving and restoring conditional on it not having a password.
|
112
|
+
# If the disabled code below is enabled, an error will be raised if a password is required,
|
113
|
+
# even though it is stored.
|
114
|
+
# network_name = current_network
|
115
|
+
wifi_off
|
116
|
+
wifi_on
|
117
|
+
# connect(network_name) if network_name
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def connected_to?(network_name)
|
122
|
+
network_name == connected_network_name
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# Connects to the passed network name, optionally with password.
|
127
|
+
# Turns wifi on first, in case it was turned off.
|
128
|
+
# Relies on subclass implementation of simple_connect().
|
129
|
+
def connect(network_name, password = nil)
|
130
|
+
if network_name.nil? || network_name.empty?
|
131
|
+
raise "A network name is required but was not provided."
|
132
|
+
end
|
133
|
+
wifi_on
|
134
|
+
simple_connect(network_name, password)
|
135
|
+
|
136
|
+
# Verify that the network is now connected:
|
137
|
+
actual_network_name = connected_network_name
|
138
|
+
unless actual_network_name == network_name
|
139
|
+
message = %Q{Expected to connect to "#{network_name}" but }
|
140
|
+
if actual_network_name
|
141
|
+
message << %Q{connected to "#{connected_network_name}" instead.}
|
142
|
+
else
|
143
|
+
message << "unable to connect to any network. Did you "
|
144
|
+
end
|
145
|
+
message << (password ? "provide the correct password?" : "need to provide a password?")
|
146
|
+
raise message
|
147
|
+
end
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
# Removes the specified network(s) from the preferred network list.
|
153
|
+
# @param network_names names of networks to remove; may be empty or contain nonexistent networks
|
154
|
+
# @return names of the networks that were removed (excludes non-preexisting networks)
|
155
|
+
def remove_preferred_networks(*network_names)
|
156
|
+
networks_to_remove = network_names & preferred_networks # exclude any nonexistent networks
|
157
|
+
networks_to_remove.each do |name|
|
158
|
+
run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
|
159
|
+
"#{wifi_hardware_port} #{Shellwords.shellescape(name)}")
|
160
|
+
end
|
161
|
+
networks_to_remove
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
def preferred_network_password(preferred_network_name)
|
166
|
+
if preferred_networks.include?(preferred_network_name)
|
167
|
+
simple_preferred_network_password(preferred_network_name)
|
168
|
+
else
|
169
|
+
raise "Network #{preferred_network_name} not in preferred networks list."
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
# Waits for the Internet connection to be in the desired state.
|
175
|
+
# @param status must be in [:conn, :disc, :off, :on]; waits for that state
|
176
|
+
# @param wait_interval_in_secs sleeps this interval between retries
|
177
|
+
#
|
178
|
+
def till(status, wait_interval_in_secs = nil)
|
179
|
+
|
180
|
+
wait_interval_in_secs ||= 0.5
|
181
|
+
|
182
|
+
exit_when = case status
|
183
|
+
when :conn
|
184
|
+
-> { connected_to_internet? }
|
185
|
+
when :disc
|
186
|
+
-> { ! connected_to_internet? }
|
187
|
+
when :on
|
188
|
+
-> { wifi_on? }
|
189
|
+
when :off
|
190
|
+
-> { ! wifi_on? }
|
191
|
+
else
|
192
|
+
raise ArgumentError.new("Option must be one of [:conn, :disc, :off, :on]. Was: #{status.inspect}")
|
193
|
+
end
|
194
|
+
|
195
|
+
loop do
|
196
|
+
return if exit_when.()
|
197
|
+
sleep(wait_interval_in_secs)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
class MacOsModel < BaseModel
|
205
|
+
|
206
|
+
AIRPORT_CMD = '/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport'
|
207
|
+
|
208
|
+
def initialize(verbose)
|
209
|
+
super
|
210
|
+
end
|
121
211
|
|
122
212
|
|
123
213
|
# This is determined by whether or not a line like the following appears in the output of `netstat -nr`:
|
@@ -205,54 +295,18 @@ class Model
|
|
205
295
|
end
|
206
296
|
|
207
297
|
|
208
|
-
# Turns wifi off and then on, reconnecting to the originally connecting network.
|
209
|
-
def cycle_network
|
210
|
-
# TODO: Make this network name saving and restoring conditional on it not having a password.
|
211
|
-
# If the disabled code below is enabled, an error will be raised if a password is required,
|
212
|
-
# even though it is stored.
|
213
|
-
# network_name = current_network
|
214
|
-
wifi_off
|
215
|
-
wifi_on
|
216
|
-
# connect(network_name) if network_name
|
217
|
-
end
|
218
|
-
|
219
|
-
|
220
298
|
def connected_network_name
|
221
299
|
wifi_info['SSID']
|
222
300
|
end
|
223
301
|
|
224
302
|
|
225
|
-
|
226
|
-
|
227
|
-
end
|
228
|
-
|
229
|
-
|
230
|
-
# Connects to the passed network name, optionally with password.
|
231
|
-
# Turns wifi on first, in case it was turned off.
|
232
|
-
def connect(network_name, password = nil)
|
233
|
-
if network_name.nil? || network_name.empty?
|
234
|
-
raise "A network name is required but was not provided."
|
235
|
-
end
|
236
|
-
wifi_on
|
303
|
+
# This method is called by BaseModel#connect to do the OS-specific connection logic.
|
304
|
+
def simple_connect(network_name, password = nil)
|
237
305
|
command = "networksetup -setairportnetwork #{wifi_hardware_port} " + "#{Shellwords.shellescape(network_name)}"
|
238
306
|
if password
|
239
307
|
command << ' ' << Shellwords.shellescape(password)
|
240
308
|
end
|
241
309
|
run_os_command(command)
|
242
|
-
|
243
|
-
# Verify that the network is now connected:
|
244
|
-
actual_network_name = connected_network_name
|
245
|
-
unless actual_network_name == network_name
|
246
|
-
message = %Q{Expected to connect to "#{network_name}" but }
|
247
|
-
if actual_network_name
|
248
|
-
message << %Q{connected to "#{connected_network_name}" instead.}
|
249
|
-
else
|
250
|
-
message << "unable to connect to any network. Did you "
|
251
|
-
end
|
252
|
-
message << (password ? "provide the correct password?" : "need to provide a password?")
|
253
|
-
raise message
|
254
|
-
end
|
255
|
-
nil
|
256
310
|
end
|
257
311
|
|
258
312
|
|
@@ -262,20 +316,16 @@ class Model
|
|
262
316
|
# If not, return nil
|
263
317
|
# else
|
264
318
|
# raise an error
|
265
|
-
def
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
raise
|
275
|
-
end
|
319
|
+
def simple_preferred_network_password(preferred_network_name)
|
320
|
+
command = %Q{security find-generic-password -D "AirPort network password" -a "#{preferred_network_name}" -w 2>&1}
|
321
|
+
begin
|
322
|
+
return run_os_command(command).chomp
|
323
|
+
rescue OsCommandError => error
|
324
|
+
if error.exitstatus == 44 # network has no password stored
|
325
|
+
nil
|
326
|
+
else
|
327
|
+
raise
|
276
328
|
end
|
277
|
-
else
|
278
|
-
raise "Network #{preferred_network_name} not in preferred networks list."
|
279
329
|
end
|
280
330
|
end
|
281
331
|
|
@@ -294,16 +344,9 @@ class Model
|
|
294
344
|
end
|
295
345
|
|
296
346
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
def remove_preferred_networks(*network_names)
|
301
|
-
networks_to_remove = network_names & preferred_networks # exclude any nonexistent networks
|
302
|
-
networks_to_remove.each do |name|
|
303
|
-
run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
|
304
|
-
"#{wifi_hardware_port} #{Shellwords.shellescape(name)}")
|
305
|
-
end
|
306
|
-
networks_to_remove
|
347
|
+
def remove_preferred_network(network_name)
|
348
|
+
run_os_command("sudo networksetup -removepreferredwirelessnetwork " +
|
349
|
+
"#{wifi_hardware_port} #{Shellwords.shellescape(network_name)}")
|
307
350
|
end
|
308
351
|
|
309
352
|
|
@@ -342,46 +385,17 @@ class Model
|
|
342
385
|
end
|
343
386
|
|
344
387
|
|
345
|
-
|
346
|
-
|
347
|
-
# @param wait_interval_in_secs sleeps this interval between retries
|
348
|
-
#
|
349
|
-
# NOTE!: This is experimental and sometimes hangs.
|
350
|
-
def till(status, wait_interval_in_secs = nil)
|
351
|
-
|
352
|
-
wait_interval_in_secs ||= 0.5
|
353
|
-
|
354
|
-
exit_when = case status
|
355
|
-
when :conn
|
356
|
-
-> { connected_to_internet? }
|
357
|
-
when :disc
|
358
|
-
-> { ! connected_to_internet? }
|
359
|
-
when :on
|
360
|
-
-> { wifi_on? }
|
361
|
-
when :off
|
362
|
-
-> { ! wifi_on? }
|
363
|
-
else
|
364
|
-
raise ArgumentError.new("Option must be one of [:conn, :disc, :off, :on]. Was: #{status.inspect}")
|
365
|
-
end
|
388
|
+
class OsCommandError < RuntimeError
|
389
|
+
attr_reader :exitstatus, :command, :text
|
366
390
|
|
367
|
-
|
368
|
-
|
369
|
-
|
391
|
+
def initialize(exitstatus, command, text)
|
392
|
+
@exitstatus = exitstatus
|
393
|
+
@command = command
|
394
|
+
@text = text
|
370
395
|
end
|
371
396
|
end
|
372
397
|
|
373
398
|
|
374
|
-
class OsCommandError < RuntimeError
|
375
|
-
attr_reader :exitstatus, :command, :text
|
376
|
-
|
377
|
-
def initialize(exitstatus, command, text)
|
378
|
-
@exitstatus = exitstatus
|
379
|
-
@command = command
|
380
|
-
@text = text
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
|
385
399
|
def run_os_command(command)
|
386
400
|
output = `#{command} 2>&1` # join stderr with stdout
|
387
401
|
if $?.exitstatus != 0
|
@@ -435,7 +449,7 @@ pa[ssword] network-name - shows password for preferred network-name
|
|
435
449
|
q[uit] - exits this program (interactive shell mode only)
|
436
450
|
r[m] network-name - removes network-name from the preferred networks list
|
437
451
|
s[hell] - opens an interactive pry shell (command line only)
|
438
|
-
t[ill] -
|
452
|
+
t[ill] - returns when the desired Internet connection state is true. Options:
|
439
453
|
'on'/:on or 'off'/:off
|
440
454
|
wait interval, in seconds (optional, defaults to 0.5 seconds)
|
441
455
|
w[ifion] - is the wifi on?
|
@@ -449,12 +463,12 @@ When in interactive shell mode:
|
|
449
463
|
|
450
464
|
|
451
465
|
def initialize
|
452
|
-
@model =
|
466
|
+
@model = MacOsModel.new(verbose_mode)
|
453
467
|
@interactive_mode = false # will be true if/when user selects shell option on command line
|
454
468
|
end
|
455
469
|
|
456
470
|
|
457
|
-
class Command < Struct.new(:
|
471
|
+
class Command < Struct.new(:min_string, :max_string, :action); end
|
458
472
|
|
459
473
|
|
460
474
|
class BadCommandError < RuntimeError
|
@@ -557,7 +571,8 @@ When in interactive shell mode:
|
|
557
571
|
|
558
572
|
# For use by the shell; when typing a command and options, it is passed to process_command_line
|
559
573
|
def method_missing(method_name, *options)
|
560
|
-
|
574
|
+
method_name = method_name.to_s
|
575
|
+
method_valid = !! find_command_action(method_name)
|
561
576
|
if method_valid
|
562
577
|
process_command_line(method_name, options)
|
563
578
|
else
|
@@ -703,30 +718,30 @@ When in interactive shell mode:
|
|
703
718
|
|
704
719
|
def commands
|
705
720
|
@commands_ ||= [
|
706
|
-
Command.new(
|
707
|
-
Command.new(
|
708
|
-
Command.new(
|
709
|
-
Command.new(
|
710
|
-
Command.new(
|
711
|
-
Command.new(
|
712
|
-
Command.new(
|
713
|
-
Command.new(
|
714
|
-
Command.new(
|
715
|
-
Command.new(
|
716
|
-
Command.new(
|
717
|
-
Command.new(
|
718
|
-
Command.new(
|
719
|
-
Command.new(
|
720
|
-
Command.new(
|
721
|
-
Command.new(
|
722
|
-
Command.new(
|
723
|
-
Command.new(
|
721
|
+
Command.new('ci', 'ci', -> (*_options) { cmd_ci }),
|
722
|
+
Command.new('co', 'connect', -> (*options) { cmd_co(*options) }),
|
723
|
+
Command.new('cy', 'cycle', -> (*_options) { cmd_cy }),
|
724
|
+
Command.new('d', 'disconnect', -> (*_options) { cmd_d }),
|
725
|
+
Command.new('h', 'help', -> (*_options) { cmd_h }),
|
726
|
+
Command.new('i', 'info', -> (*_options) { cmd_i }),
|
727
|
+
Command.new('lsa', 'lsavailable', -> (*_options) { cmd_lsa }),
|
728
|
+
Command.new('lsp', 'lspreferred', -> (*_options) { cmd_lsp }),
|
729
|
+
Command.new('n', 'network_name', -> (*_options) { cmd_n }),
|
730
|
+
Command.new('of', 'off', -> (*_options) { cmd_of }),
|
731
|
+
Command.new('on', 'on', -> (*_options) { cmd_on }),
|
732
|
+
Command.new('pa', 'password', -> (*options) { cmd_pa(*options) }),
|
733
|
+
Command.new('q', 'quit', -> (*_options) { cmd_q }),
|
734
|
+
Command.new('r', 'rm', -> (*options) { cmd_r(*options) }),
|
735
|
+
Command.new('s', 'shell', -> (*_options) { cmd_s }),
|
736
|
+
Command.new('t', 'till', -> (*options) { cmd_t(*options) }),
|
737
|
+
Command.new('w', 'wifion', -> (*_options) { cmd_w }),
|
738
|
+
Command.new('x', 'xit', -> (*_options) { cmd_x })
|
724
739
|
]
|
725
740
|
end
|
726
741
|
|
727
742
|
|
728
743
|
def find_command_action(command_string)
|
729
|
-
result = commands.detect { |cmd| cmd.
|
744
|
+
result = commands.detect { |cmd| cmd.max_string.start_with?(command_string) }
|
730
745
|
result ? result.action : nil
|
731
746
|
end
|
732
747
|
|
@@ -741,12 +756,11 @@ When in interactive shell mode:
|
|
741
756
|
exit(-1)
|
742
757
|
end
|
743
758
|
end
|
744
|
-
|
745
759
|
end
|
746
|
-
|
747
760
|
end
|
748
761
|
|
749
762
|
|
763
|
+
|
750
764
|
# @return true if this file is being run as a script, else false
|
751
765
|
#
|
752
766
|
# This file could be called as a script in either of these two ways:
|
@@ -763,6 +777,15 @@ def running_as_script?
|
|
763
777
|
end
|
764
778
|
|
765
779
|
|
780
|
+
def assert_os_is_mac_os
|
781
|
+
uname = `uname`.chomp
|
782
|
+
unless uname == 'Darwin'
|
783
|
+
raise "This program currently works only on Mac OS. Platform is '#{uname}'."
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
assert_os_is_mac_os
|
788
|
+
|
766
789
|
# If this file is being called as a script, run it.
|
767
790
|
# Else, it may be loaded to use the model in a different way.
|
768
791
|
if running_as_script?
|
data/mac-wifi.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mac-wifi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Keith Bennett
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A command line interface for managing wifi on a Mac.
|
14
14
|
email:
|
@@ -29,7 +29,7 @@ homepage: https://github.com/keithrbennett/mac-wifi
|
|
29
29
|
licenses:
|
30
30
|
- MIT
|
31
31
|
metadata: {}
|
32
|
-
post_install_message:
|
32
|
+
post_install_message:
|
33
33
|
rdoc_options: []
|
34
34
|
require_paths:
|
35
35
|
- lib
|
@@ -44,9 +44,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
requirements: []
|
47
|
-
rubyforge_project:
|
47
|
+
rubyforge_project:
|
48
48
|
rubygems_version: 2.6.13
|
49
|
-
signing_key:
|
49
|
+
signing_key:
|
50
50
|
specification_version: 4
|
51
51
|
summary: Mac wifi utility
|
52
52
|
test_files:
|