macinbox 3.2.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +1 -1
- data/README.md +6 -0
- data/lib/macinbox/actions/check_macos_versions.rb +2 -3
- data/lib/macinbox/actions/create_box_from_hdd.rb +1 -2
- data/lib/macinbox/actions/create_box_from_vdi.rb +1 -2
- data/lib/macinbox/actions/create_box_from_vmdk.rb +0 -1
- data/lib/macinbox/actions/create_hdd_from_image.rb +3 -4
- data/lib/macinbox/actions/create_image_from_installer.rb +15 -7
- data/lib/macinbox/actions/create_vdi_from_image.rb +2 -3
- data/lib/macinbox/actions/create_vmdk_from_image.rb +21 -13
- data/lib/macinbox/actions/install_box.rb +0 -1
- data/lib/macinbox/cli.rb +2 -2
- data/lib/macinbox/cli/options.rb +8 -5
- data/lib/macinbox/task.rb +15 -4
- data/lib/macinbox/version.rb +1 -1
- data/lib/macinbox/virtual_disk.rb +7 -13
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36bd1285647b90d338e5519ba42e429e6bb8ea12
|
4
|
+
data.tar.gz: 65c6e91a11e43bed2921f006fe1469542d716205
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e08c547e56e15487b2d22cdc492aeaa7b3b78dd13b4df4ebdd77daa09537237b18413daa63bd3e473e2b67d4fb4e83137cf493cca63452e54fb994e5ced8953a
|
7
|
+
data.tar.gz: 1d4dbf5faac11e49922894e001ea1a32988a11dc85a9327f2f78a6708e9769c18ef32286fbb888273e74183b23e971cf3962328d77d0f443c798bb4df4c235cf
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 3.3.0 (February 26, 2019)
|
2
|
+
|
3
|
+
FEATURES:
|
4
|
+
|
5
|
+
- Add --verbose option to show the commands being run. [GH-28]
|
6
|
+
- Add --user-script option to support running user-provided customizations. [GH-24]
|
7
|
+
|
8
|
+
BUG FIXES:
|
9
|
+
|
10
|
+
- Only display the animated progress bar when stderr is a tty. [GH-25]
|
11
|
+
|
1
12
|
## 3.2.0 (February 2, 2019)
|
2
13
|
|
3
14
|
FEATURES:
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -106,6 +106,7 @@ Usage: macinbox [options]
|
|
106
106
|
--installer-dmg PATH Path to a macOS installer app disk image
|
107
107
|
--vmware PATH Path to the VMware Fusion app
|
108
108
|
--parallels PATH Path to the Parallels Desktop app
|
109
|
+
--user-script PATH Path to user script
|
109
110
|
|
110
111
|
--no-auto-login Disable auto login
|
111
112
|
--no-skip-mini-buddy Show the mini buddy on first login
|
@@ -115,6 +116,7 @@ Usage: macinbox [options]
|
|
115
116
|
|
116
117
|
--use-qemu Use qemu-img (vmware_desktop only)
|
117
118
|
|
119
|
+
--verbose Enable verbose mode
|
118
120
|
--debug Enable debug mode
|
119
121
|
|
120
122
|
-v, --version
|
@@ -143,6 +145,10 @@ When the box format is set to 'parallels' using the `--box-format` option then t
|
|
143
145
|
|
144
146
|
When the box format is set to 'virtualbox' no guest extensions are installed. Note that some features behave differently with VirtualBox. The screen resolution is set to 1280x800 and HiDPI resolutions are not supported. The GUI scale factor is set to 2.0 (so that the VM displays properly on a host with a retina display) unless the `--no-hidpi` option is used. Lastly, ssh port-forwarding is enabled by default so that the host can connect to the guest.
|
145
147
|
|
148
|
+
## User scripts
|
149
|
+
|
150
|
+
If additional box customization is required a user script may be specified using the `--user-script` option. The script is run after the OS has been installed and will be provided with the path to the install location as its first and only argument. The script must be executable and exit with code zero or the box creation will be aborted.
|
151
|
+
|
146
152
|
## Installer Disk Image Support
|
147
153
|
|
148
154
|
The `--installer-dmg` option allows you to indicate the path to a disk image containing a macOS installer, and overrides the `--installer` option. The specified disk image should not already be mounted; `macinbox` will mount and unmount it as needed. This feature allows you to use the installer disk images created by [installinstallmacos.py](https://github.com/munki/macadmin-scripts/blob/master/installinstallmacos.py) as part of the `macinbox` workflow.
|
@@ -8,7 +8,6 @@ module Macinbox
|
|
8
8
|
@installer_app = opts[:installer_path] or raise ArgumentError.new(":installer_path not specified")
|
9
9
|
|
10
10
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
11
|
-
@debug = opts[:debug]
|
12
11
|
|
13
12
|
raise Macinbox::Error.new("Installer app not found") unless File.exist? @installer_app
|
14
13
|
end
|
@@ -21,13 +20,13 @@ module Macinbox
|
|
21
20
|
installer_os_version_components = installer_os_version.split(".") rescue [0, 0, 0]
|
22
21
|
installer_os_version_major = installer_os_version_components[0]
|
23
22
|
installer_os_version_minor = installer_os_version_components[1]
|
24
|
-
Logger.info "Installer macOS version detected: #{installer_os_version}" if
|
23
|
+
Logger.info "Installer macOS version detected: #{installer_os_version}" if $verbose
|
25
24
|
|
26
25
|
host_os_version = Task.backtick %W[ /usr/bin/sw_vers -productVersion ]
|
27
26
|
host_os_version_components = host_os_version.split(".") rescue [0, 0, 0]
|
28
27
|
host_os_version_major = host_os_version_components[0]
|
29
28
|
host_os_version_minor = host_os_version_components[1]
|
30
|
-
Logger.info "Host macOS version detected: #{host_os_version}" if
|
29
|
+
Logger.info "Host macOS version detected: #{host_os_version}" if $verbose
|
31
30
|
|
32
31
|
if installer_os_version_major != host_os_version_major || installer_os_version_minor != host_os_version_minor
|
33
32
|
Logger.error "Warning: host OS version (#{host_os_version}) and installer OS version (#{installer_os_version}) do not match"
|
@@ -25,7 +25,6 @@ module Macinbox
|
|
25
25
|
@hidpi = opts[:hidpi]
|
26
26
|
|
27
27
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
28
|
-
@debug = opts[:debug]
|
29
28
|
|
30
29
|
raise Macinbox::Error.new("HDD not found") unless File.exist? @input_hdd
|
31
30
|
end
|
@@ -55,7 +54,7 @@ module Macinbox
|
|
55
54
|
end
|
56
55
|
EOF
|
57
56
|
|
58
|
-
task_opts =
|
57
|
+
task_opts = $verbose ? {} : { :out => File::NULL }
|
59
58
|
|
60
59
|
Task.run %W[ prlctl create macinbox -o macos --no-hdd --dst #{@box_dir} ] + [task_opts]
|
61
60
|
|
@@ -24,7 +24,6 @@ module Macinbox
|
|
24
24
|
@hidpi = opts[:hidpi]
|
25
25
|
|
26
26
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
27
|
-
@debug = opts[:debug]
|
28
27
|
|
29
28
|
raise Macinbox::Error.new("VDI not found") unless File.exist? @input_vdi
|
30
29
|
end
|
@@ -53,7 +52,7 @@ module Macinbox
|
|
53
52
|
end
|
54
53
|
EOF
|
55
54
|
|
56
|
-
task_opts =
|
55
|
+
task_opts = $verbose ? {} : { :out => File::NULL }
|
57
56
|
|
58
57
|
Task.run %W[ VBoxManage createvm --register --name macinbox --ostype MacOS1013_64 ] + [task_opts]
|
59
58
|
|
@@ -26,7 +26,6 @@ module Macinbox
|
|
26
26
|
@hidpi = opts[:hidpi]
|
27
27
|
|
28
28
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
29
|
-
@debug = opts[:debug]
|
30
29
|
|
31
30
|
raise Macinbox::Error.new("VMDK not found") unless File.exist? @input_vmdk
|
32
31
|
raise Macinbox::Error.new("Box format not supported: #{@box_format}") unless ["vmware_fusion", "vmware_desktop"].include? @box_format
|
@@ -19,7 +19,6 @@ module Macinbox
|
|
19
19
|
@parallels_app = opts[:parallels_path] or raise ArgumentError.new(":parallels_path not specified")
|
20
20
|
|
21
21
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
22
|
-
@debug = opts[:debug]
|
23
22
|
|
24
23
|
raise Macinbox::Error.new("input image not found") unless File.exist? @input_image
|
25
24
|
raise Macinbox::Error.new("Parallels Desktop not found") unless File.exist? @parallels_app
|
@@ -49,7 +48,7 @@ module Macinbox
|
|
49
48
|
|
50
49
|
def attach_image
|
51
50
|
Logger.info "Attaching the image..." do
|
52
|
-
@disk = VirtualDisk.new(@image
|
51
|
+
@disk = VirtualDisk.new(@image)
|
53
52
|
@collector.on_cleanup { @disk.detach! }
|
54
53
|
@image_mountpoint = "#{@temp_dir}/image_mountpoint"
|
55
54
|
FileUtils.mkdir @image_mountpoint
|
@@ -64,7 +63,7 @@ module Macinbox
|
|
64
63
|
|
65
64
|
tools_image = "#{@parallels_app}/Contents/Resources/Tools/prl-tools-mac.iso"
|
66
65
|
|
67
|
-
tools_disk = VirtualDisk.new(tools_image
|
66
|
+
tools_disk = VirtualDisk.new(tools_image)
|
68
67
|
|
69
68
|
@collector.on_cleanup { tools_disk.detach! }
|
70
69
|
|
@@ -171,7 +170,7 @@ module Macinbox
|
|
171
170
|
EOF
|
172
171
|
|
173
172
|
prl_convert = "#{@parallels_app}/Contents/MacOS/prl_convert"
|
174
|
-
task_opts =
|
173
|
+
task_opts = $verbose ? {} : { :out => File::NULL }
|
175
174
|
Task.run %W[ #{prl_convert} #{@temp_dir}/macinbox.vmdk --allow-no-os --dst=#{@temp_dir} ] + [task_opts]
|
176
175
|
@disk.eject
|
177
176
|
end
|
@@ -18,6 +18,7 @@ module Macinbox
|
|
18
18
|
@output_path = opts[:image_path] or raise ArgumentError.new(":image_path not specified")
|
19
19
|
@vmware_fusion_app = opts[:vmware_path]
|
20
20
|
@parallels_app = opts[:parallels_path]
|
21
|
+
@user_script = opts[:user_script]
|
21
22
|
|
22
23
|
@disk_size = opts[:disk_size] or raise ArgumentError.new(":disk_size not specified")
|
23
24
|
@fstype = opts[:fstype] or raise ArgumentError.new(":fstype not specified")
|
@@ -31,7 +32,6 @@ module Macinbox
|
|
31
32
|
@hidpi = opts[:hidpi]
|
32
33
|
|
33
34
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
34
|
-
@debug = opts[:debug]
|
35
35
|
|
36
36
|
raise Macinbox::Error.new("Installer app not found") unless File.exist? @installer_app
|
37
37
|
|
@@ -52,6 +52,7 @@ module Macinbox
|
|
52
52
|
enable_passwordless_sudo
|
53
53
|
enable_sshd
|
54
54
|
enable_hidpi
|
55
|
+
run_user_script
|
55
56
|
save_image
|
56
57
|
end
|
57
58
|
|
@@ -69,7 +70,7 @@ module Macinbox
|
|
69
70
|
def create_wrapper_image
|
70
71
|
Logger.info "Creating and attaching wrapper disk image..." do
|
71
72
|
@wrapper_image = "#{@temp_dir}/wrapper.dmg"
|
72
|
-
@wrapper_disk = VirtualDisk.new(@wrapper_image
|
73
|
+
@wrapper_disk = VirtualDisk.new(@wrapper_image)
|
73
74
|
@collector.on_cleanup { @wrapper_disk.detach! }
|
74
75
|
@wrapper_disk.create_from_folder(@installer_app)
|
75
76
|
@wrapper_disk.attach
|
@@ -81,7 +82,7 @@ module Macinbox
|
|
81
82
|
def create_scratch_image
|
82
83
|
Logger.info "Creating and attaching a new blank disk image..." do
|
83
84
|
@scratch_image = "#{@temp_dir}/scratch.sparseimage"
|
84
|
-
@scratch_disk = VirtualDisk.new(@scratch_image
|
85
|
+
@scratch_disk = VirtualDisk.new(@scratch_image)
|
85
86
|
@collector.on_cleanup { @scratch_disk.detach! }
|
86
87
|
@scratch_mountpoint = "#{@temp_dir}/scratch_mountpoint"
|
87
88
|
FileUtils.mkdir @scratch_mountpoint
|
@@ -97,7 +98,7 @@ module Macinbox
|
|
97
98
|
install_info_plist = "#{@installer_app}/Contents/SharedSupport/InstallInfo.plist"
|
98
99
|
Task.run %W[ /usr/bin/touch #{@scratch_mountpoint}/.macinbox ]
|
99
100
|
cmd = %W[ /usr/sbin/installer -verboseR -dumplog -pkg #{install_info_plist} -target #{@scratch_mountpoint} ]
|
100
|
-
opts =
|
101
|
+
opts = $verbose ? {} : { :err => [:child, :out] }
|
101
102
|
Task.run_with_progress activity, cmd, opts do |line|
|
102
103
|
/^installer:%(.*)$/.match(line)[1].to_f rescue nil
|
103
104
|
end
|
@@ -190,12 +191,11 @@ module Macinbox
|
|
190
191
|
def enable_sshd
|
191
192
|
Logger.info "Enabling sshd..." do
|
192
193
|
scratch_launchd_disabled_plist = "#{@scratch_mountpoint}/private/var/db/com.apple.xpc.launchd/disabled.plist"
|
193
|
-
opts =
|
194
|
+
opts = $verbose ? {} : { :out => File::NULL }
|
194
195
|
Task.run %W[ /usr/libexec/PlistBuddy -c #{'Add :com.openssh.sshd bool False'} #{scratch_launchd_disabled_plist} ] + [opts]
|
195
196
|
end
|
196
197
|
end
|
197
198
|
|
198
|
-
|
199
199
|
def enable_hidpi
|
200
200
|
if @hidpi
|
201
201
|
Logger.info "Enabling HiDPI resolutions..." do
|
@@ -214,9 +214,17 @@ module Macinbox
|
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
|
+
def run_user_script
|
218
|
+
if @user_script
|
219
|
+
Logger.info "Running user script..." do
|
220
|
+
Task.run %W[ #{@user_script} #{@scratch_mountpoint} ]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
217
225
|
def save_image
|
218
226
|
Logger.info "Saving the image..." do
|
219
|
-
@scratch_disk.
|
227
|
+
@scratch_disk.eject
|
220
228
|
FileUtils.chown ENV["SUDO_USER"], nil, @scratch_image
|
221
229
|
FileUtils.mv @scratch_image, @output_path
|
222
230
|
end
|
@@ -18,7 +18,6 @@ module Macinbox
|
|
18
18
|
@output_path = opts[:vdi_path] or raise ArgumentError.new(":vdi_path not specified")
|
19
19
|
|
20
20
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
21
|
-
@debug = opts[:debug]
|
22
21
|
|
23
22
|
raise Macinbox::Error.new("input image not found") unless File.exist? @input_image
|
24
23
|
end
|
@@ -46,7 +45,7 @@ module Macinbox
|
|
46
45
|
|
47
46
|
def attach_image
|
48
47
|
Logger.info "Attaching the image..." do
|
49
|
-
@disk = VirtualDisk.new(@image
|
48
|
+
@disk = VirtualDisk.new(@image)
|
50
49
|
@collector.on_cleanup { @disk.detach! }
|
51
50
|
@disk.attach
|
52
51
|
end
|
@@ -80,7 +79,7 @@ module Macinbox
|
|
80
79
|
|
81
80
|
def convert_image
|
82
81
|
Logger.info "Converting the image to VDI format..." do
|
83
|
-
task_opts =
|
82
|
+
task_opts = $verbose ? {} : { :out => File::NULL }
|
84
83
|
Task.run %W[ VBoxManage convertfromraw #{@disk.device} #{@temp_dir}/macinbox.vdi --format VDI ] + [task_opts]
|
85
84
|
end
|
86
85
|
end
|
@@ -20,7 +20,6 @@ module Macinbox
|
|
20
20
|
@use_qemu = opts[:use_qemu]
|
21
21
|
|
22
22
|
@collector = opts[:collector] or raise ArgumentError.new(":collector not specified")
|
23
|
-
@debug = opts[:debug]
|
24
23
|
|
25
24
|
raise Macinbox::Error.new("input image not found") unless File.exist? @input_image
|
26
25
|
raise Macinbox::Error.new("VMware Fusion not found") unless File.exist? @vmware_fusion_app
|
@@ -55,7 +54,7 @@ module Macinbox
|
|
55
54
|
|
56
55
|
def attach_image
|
57
56
|
Logger.info "Attaching the image..." do
|
58
|
-
@disk = VirtualDisk.new(@image
|
57
|
+
@disk = VirtualDisk.new(@image)
|
59
58
|
@collector.on_cleanup { @disk.detach! }
|
60
59
|
@image_mountpoint = "#{@temp_dir}/image_mountpoint"
|
61
60
|
FileUtils.mkdir @image_mountpoint
|
@@ -73,16 +72,16 @@ module Macinbox
|
|
73
72
|
bundle_short_version = Task.backtick %W[ defaults read #{"/Applications/VMware Fusion.app/Contents/Info.plist"} CFBundleShortVersionString ]
|
74
73
|
darwin_iso_url = "http://softwareupdate.vmware.com/cds/vmw-desktop/fusion/#{bundle_short_version}/#{bundle_version}/packages/com.vmware.fusion.tools.darwin.zip.tar"
|
75
74
|
Dir.chdir(@temp_dir) do
|
76
|
-
Task.run %W[ /usr/bin/curl #{darwin_iso_url} -O ] + (
|
75
|
+
Task.run %W[ /usr/bin/curl #{darwin_iso_url} -O ] + ($verbose ? [] : %W[ -s -S ])
|
77
76
|
Task.run %W[ /usr/bin/tar -xf com.vmware.fusion.tools.darwin.zip.tar com.vmware.fusion.tools.darwin.zip ]
|
78
|
-
Task.run %W[ /usr/bin/unzip ] + (
|
77
|
+
Task.run %W[ /usr/bin/unzip ] + ($verbose ? [] : %W[ -qq ]) + %W[ com.vmware.fusion.tools.darwin.zip payload/darwin.iso ]
|
79
78
|
end
|
80
79
|
tools_image = "#{@temp_dir}/payload/darwin.iso"
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
84
83
|
Logger.info "Installing the VMware Tools..." do
|
85
|
-
tools_disk = VirtualDisk.new(tools_image
|
84
|
+
tools_disk = VirtualDisk.new(tools_image)
|
86
85
|
@collector.on_cleanup { tools_disk.detach! }
|
87
86
|
tools_mountpoint = "#{@temp_dir}/tools_mountpoint"
|
88
87
|
FileUtils.mkdir tools_mountpoint
|
@@ -102,17 +101,26 @@ module Macinbox
|
|
102
101
|
def set_spc_kextpolicy
|
103
102
|
Logger.info "Setting the KextPolicy to allow loading the VMware kernel extensions..." do
|
104
103
|
image_spc_kextpolicy = "#{@image_mountpoint}/private/var/db/SystemPolicyConfiguration/KextPolicy"
|
104
|
+
unless File.exist? image_spc_kextpolicy
|
105
|
+
Task.run_with_input %W[ /usr/bin/sqlite3 #{image_spc_kextpolicy} ] do |pipe|
|
106
|
+
pipe.write <<~EOF
|
107
|
+
PRAGMA foreign_keys=OFF;
|
108
|
+
BEGIN TRANSACTION;
|
109
|
+
CREATE TABLE kext_load_history_v3 ( path TEXT PRIMARY KEY, team_id TEXT, bundle_id TEXT, boot_uuid TEXT, created_at TEXT, last_seen TEXT, flags INTEGER );
|
110
|
+
CREATE TABLE kext_policy ( team_id TEXT, bundle_id TEXT, allowed BOOLEAN, developer_name TEXT, flags INTEGER, PRIMARY KEY (team_id, bundle_id) );
|
111
|
+
CREATE TABLE kext_policy_mdm ( team_id TEXT, bundle_id TEXT, allowed BOOLEAN, payload_uuid TEXT, PRIMARY KEY (team_id, bundle_id) );
|
112
|
+
CREATE TABLE settings ( name TEXT, value TEXT, PRIMARY KEY (name) );
|
113
|
+
COMMIT;
|
114
|
+
EOF
|
115
|
+
end
|
116
|
+
end
|
105
117
|
Task.run_with_input %W[ /usr/bin/sqlite3 #{image_spc_kextpolicy} ] do |pipe|
|
106
118
|
pipe.write <<~EOF
|
107
119
|
PRAGMA foreign_keys=OFF;
|
108
120
|
BEGIN TRANSACTION;
|
109
|
-
|
110
|
-
|
111
|
-
INSERT INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.
|
112
|
-
INSERT INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.vmmemctl',1,'VMware, Inc.',1);
|
113
|
-
INSERT INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.vmhgfs',1,'VMware, Inc.',1);
|
114
|
-
CREATE TABLE kext_policy_mdm ( team_id TEXT, bundle_id TEXT, allowed BOOLEAN, payload_uuid TEXT, PRIMARY KEY (team_id, bundle_id) );
|
115
|
-
CREATE TABLE settings ( name TEXT, value TEXT, PRIMARY KEY (name) );
|
121
|
+
INSERT OR REPLACE INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.VMwareGfx',1,'VMware, Inc.',1);
|
122
|
+
INSERT OR REPLACE INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.vmmemctl',1,'VMware, Inc.',1);
|
123
|
+
INSERT OR REPLACE INTO kext_policy VALUES('EG7KH642X6','com.vmware.kext.vmhgfs',1,'VMware, Inc.',1);
|
116
124
|
COMMIT;
|
117
125
|
EOF
|
118
126
|
end
|
@@ -130,7 +138,7 @@ module Macinbox
|
|
130
138
|
Task.run %W[ /usr/local/bin/qemu-img convert -f dmg -O vmdk #{@temp_dir}/macinbox.dmg #{@temp_dir}/macinbox.vmdk ]
|
131
139
|
else
|
132
140
|
@disk.attach
|
133
|
-
task_opts =
|
141
|
+
task_opts = $verbose ? {} : { :out => File::NULL }
|
134
142
|
rawdiskCreator = "#{@vmware_fusion_app}/Contents/Library/vmware-rawdiskCreator"
|
135
143
|
vdiskmanager = "#{@vmware_fusion_app}/Contents/Library/vmware-vdiskmanager"
|
136
144
|
Dir.chdir(@temp_dir) do
|
@@ -18,7 +18,6 @@ module Macinbox
|
|
18
18
|
@boxes_dir = opts[:boxes_dir] or raise ArgumentError.new(":boxes_dir not specified")
|
19
19
|
|
20
20
|
@box_version = opts[:macos_version]
|
21
|
-
@debug = opts[:debug]
|
22
21
|
|
23
22
|
raise Macinbox::Error.new("box not found: #{@input_box}") unless File.exist? @input_box
|
24
23
|
raise Macinbox::Error.new("boxes directory not found: #{@boxes_dir}") unless File.exist? @boxes_dir
|
data/lib/macinbox/cli.rb
CHANGED
@@ -30,7 +30,7 @@ module Macinbox
|
|
30
30
|
|
31
31
|
check_for_sudo_root
|
32
32
|
|
33
|
-
collector = Collector.new(preserve_temp_dirs:
|
33
|
+
collector = Collector.new(preserve_temp_dirs: $debug)
|
34
34
|
|
35
35
|
collector.on_cleanup do
|
36
36
|
STDERR.print TTY::Color::RESET
|
@@ -42,7 +42,7 @@ module Macinbox
|
|
42
42
|
raise Macinbox::Error.new("Installer disk image not found: #{@options[:installer_dmg]}")
|
43
43
|
end
|
44
44
|
Logger.info "Attaching installer disk image..."
|
45
|
-
installer_disk = VirtualDisk.new(@options[:installer_dmg]
|
45
|
+
installer_disk = VirtualDisk.new(@options[:installer_dmg])
|
46
46
|
collector.on_cleanup { installer_disk.detach! }
|
47
47
|
installer_disk.attach
|
48
48
|
installer_disk.mount
|
data/lib/macinbox/cli/options.rb
CHANGED
@@ -24,6 +24,7 @@ module Macinbox
|
|
24
24
|
:fullscreen => true,
|
25
25
|
:gui => true,
|
26
26
|
:use_qemu => false,
|
27
|
+
:verbose => false,
|
27
28
|
:debug => false,
|
28
29
|
}
|
29
30
|
|
@@ -45,10 +46,11 @@ module Macinbox
|
|
45
46
|
o.on('-f', '--full NAME', 'Full name of the user (default: Vagrant)') { |v| @options[:full_name] = v }
|
46
47
|
o.on('-p', '--password PASSWORD', 'Password of the user (default: vagrant)') { |v| @options[:password] = v }
|
47
48
|
o.separator ''
|
48
|
-
o.on( '--installer PATH', 'Path to the macOS installer app') { |v| @options[:installer_path] = v }
|
49
|
-
o.on( '--installer-dmg PATH', 'Path to a macOS installer app disk image') { |v| @options[:installer_dmg] = v }
|
50
|
-
o.on( '--vmware PATH', 'Path to the VMware Fusion app') { |v| @options[:vmware_path] = v }
|
51
|
-
o.on( '--parallels PATH', 'Path to the Parallels Desktop app') { |v| @options[:parallels_path] = v }
|
49
|
+
o.on( '--installer PATH', 'Path to the macOS installer app') { |v| @options[:installer_path] = File.absolute_path(v) }
|
50
|
+
o.on( '--installer-dmg PATH', 'Path to a macOS installer app disk image') { |v| @options[:installer_dmg] = File.absolute_path(v) }
|
51
|
+
o.on( '--vmware PATH', 'Path to the VMware Fusion app') { |v| @options[:vmware_path] = File.absolute_path(v) }
|
52
|
+
o.on( '--parallels PATH', 'Path to the Parallels Desktop app') { |v| @options[:parallels_path] = File.absolute_path(v) }
|
53
|
+
o.on( '--user-script PATH', 'Path to user script') { |v| @options[:user_script] = File.absolute_path(v) }
|
52
54
|
o.separator ''
|
53
55
|
o.on( '--no-auto-login', 'Disable auto login') { |v| @options[:auto_login] = v }
|
54
56
|
o.on( '--no-skip-mini-buddy', 'Show the mini buddy on first login') { |v| @options[:skip_mini_buddy] = v }
|
@@ -58,7 +60,8 @@ module Macinbox
|
|
58
60
|
o.separator ''
|
59
61
|
o.on( '--use-qemu', 'Use qemu-img (vmware_desktop only)') { |v| @options[:use_qemu] = v }
|
60
62
|
o.separator ''
|
61
|
-
o.on( '--
|
63
|
+
o.on( '--verbose', 'Enable verbose mode') { |v| $verbose = v }
|
64
|
+
o.on( '--debug', 'Enable debug mode') { |v| $debug = $verbose = v }
|
62
65
|
o.separator ''
|
63
66
|
o.on('-v', '--version') { puts "macinbox #{Macinbox::VERSION}"; exit }
|
64
67
|
o.on('-h', '--help') { puts o; exit }
|
data/lib/macinbox/task.rb
CHANGED
@@ -2,15 +2,19 @@ require 'macinbox/error'
|
|
2
2
|
require 'macinbox/logger'
|
3
3
|
require 'macinbox/tty'
|
4
4
|
|
5
|
+
require 'shellwords'
|
6
|
+
|
5
7
|
module Macinbox
|
6
8
|
|
7
9
|
class Task
|
8
10
|
|
9
11
|
def self.run(cmd)
|
12
|
+
Logger.info "Running command: #{Shellwords.join(cmd)}" if $verbose
|
10
13
|
system(*cmd) or raise Macinbox::Error.new("#{cmd.slice(0)} failed with non-zero exit code: #{$? >> 8}")
|
11
14
|
end
|
12
15
|
|
13
16
|
def self.run_as_sudo_user(cmd)
|
17
|
+
Logger.info "Running command: sudo -u #{ENV["SUDO_USER"]} #{Shellwords.join(cmd)}" if $verbose
|
14
18
|
system "sudo", "-u", ENV["SUDO_USER"], *cmd or raise Macinbox::Error.new("#{cmd.slice(0)} failed with non-zero exit code: #{$?.to_i}")
|
15
19
|
end
|
16
20
|
|
@@ -30,13 +34,18 @@ module Macinbox
|
|
30
34
|
header + bar
|
31
35
|
end
|
32
36
|
|
37
|
+
def self.print_progress_bar(io, activity, percent_done)
|
38
|
+
io.print TTY::Line::CLEAR + TTY::Color::GREEN + progress_bar(activity, percent_done) + TTY::Color::RESET if io.isatty
|
39
|
+
end
|
40
|
+
|
33
41
|
def self.run_with_progress(activity, cmd, opts={})
|
34
42
|
STDERR.print TTY::Cursor::INVISIBLE
|
35
|
-
STDERR
|
43
|
+
print_progress_bar(STDERR, activity, 0.0)
|
44
|
+
Logger.info "Running command: #{Shellwords.join(cmd)}" if $verbose
|
36
45
|
IO.popen cmd, opts do |pipe|
|
37
46
|
pipe.each_line do |line|
|
38
47
|
percent = yield line
|
39
|
-
STDERR
|
48
|
+
print_progress_bar(STDERR, activity, percent) if percent
|
40
49
|
end
|
41
50
|
end
|
42
51
|
STDERR.puts TTY::Cursor::NORMAL
|
@@ -49,14 +58,14 @@ module Macinbox
|
|
49
58
|
total_size = File.size(source)
|
50
59
|
last_percent_done = -1
|
51
60
|
STDERR.print TTY::Cursor::INVISIBLE
|
52
|
-
STDERR
|
61
|
+
print_progress_bar(STDERR, activity, 0.0)
|
53
62
|
File.open(source) do |file|
|
54
63
|
until eof
|
55
64
|
begin
|
56
65
|
bytes_written += destination.write(file.readpartial(1024*1024))
|
57
66
|
percent_done = ((bytes_written.to_f / total_size.to_f) * 100).round(1)
|
58
67
|
last_percent_done = percent_done
|
59
|
-
STDERR
|
68
|
+
print_progress_bar(STDERR, activity, percent_done)
|
60
69
|
rescue EOFError
|
61
70
|
eof = true
|
62
71
|
end
|
@@ -66,10 +75,12 @@ module Macinbox
|
|
66
75
|
end
|
67
76
|
|
68
77
|
def self.backtick(cmd)
|
78
|
+
Logger.info "Running command: #{Shellwords.join(cmd)}" if $verbose
|
69
79
|
IO.popen(cmd).read.chomp
|
70
80
|
end
|
71
81
|
|
72
82
|
def self.run_with_input(cmd)
|
83
|
+
Logger.info "Running command: #{Shellwords.join(cmd)}" if $verbose
|
73
84
|
IO.popen(cmd, "w") do |pipe|
|
74
85
|
yield pipe
|
75
86
|
end
|
data/lib/macinbox/version.rb
CHANGED
@@ -6,11 +6,10 @@ module Macinbox
|
|
6
6
|
|
7
7
|
class VirtualDisk
|
8
8
|
|
9
|
-
def initialize(image
|
9
|
+
def initialize(image)
|
10
10
|
@image = image
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@task_opts = @debug ? [] : [{ :out => File::NULL }]
|
11
|
+
@quiet_flag = $verbose ? [] : %W[ -quiet ]
|
12
|
+
@task_opts = $verbose ? [] : [{ :out => File::NULL }]
|
14
13
|
end
|
15
14
|
|
16
15
|
def device
|
@@ -65,27 +64,22 @@ module Macinbox
|
|
65
64
|
Task.run %W[ /usr/sbin/diskutil unmount #{@efi_device} ] + @task_opts
|
66
65
|
end
|
67
66
|
|
68
|
-
def
|
67
|
+
def eject
|
69
68
|
max_attempts = 5
|
70
69
|
for attempt in 1..max_attempts
|
71
70
|
begin
|
72
|
-
|
73
|
-
Task.run %W[ /usr/
|
71
|
+
quiet = $verbose ? [] : %W[ quiet ]
|
72
|
+
Task.run %W[ /usr/sbin/diskutil ] + quiet + %W[ eject #{@disk_device} ] + @task_opts
|
74
73
|
unset_devices
|
75
74
|
break
|
76
75
|
rescue Macinbox::Error => error
|
77
76
|
raise if attempt == max_attempts
|
78
|
-
Logger.info "#{error.message}. Sleeping and retrying..." if
|
77
|
+
Logger.info "Eject failed: #{error.message}. Sleeping and retrying..." if $verbose
|
79
78
|
sleep 15
|
80
79
|
end
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
84
|
-
def eject
|
85
|
-
Task.run %W[ /usr/sbin/diskutil eject #{@disk_device} ] + @task_opts
|
86
|
-
unset_devices
|
87
|
-
end
|
88
|
-
|
89
83
|
def detach!
|
90
84
|
return unless @disk_device
|
91
85
|
%x( /usr/bin/hdiutil detach -quiet -force #{@disk_device.shellescape} > /dev/null 2>&1 )
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: macinbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Kramer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|