wrapp 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +12 -18
- data/bin/wrapp +1 -1
- data/features/step_definitions/wrapp_steps.rb +51 -37
- data/features/support/app.rb +44 -0
- data/features/wrap_app.feature +7 -5
- data/lib/wrapp/cli.rb +23 -0
- data/lib/wrapp/dmg_builder.rb +5 -14
- data/lib/wrapp/version.rb +1 -1
- data/lib/wrapp.rb +2 -0
- data/spec/wrapp/cli_spec.rb +47 -0
- data/spec/wrapp/dmg_builder_spec.rb +19 -23
- data/wrapp.gemspec +2 -1
- metadata +30 -9
data/README.md
CHANGED
@@ -6,11 +6,11 @@ Wrap an App... in a disk image (DMG).
|
|
6
6
|
## Prologue
|
7
7
|
|
8
8
|
Say you wanna put your nice Mac OS X application in a handy disk image
|
9
|
-
(DMG) for
|
10
|
-
Why not use
|
9
|
+
(DMG) for distribution.
|
10
|
+
Why not use *wrapp* for this?
|
11
11
|
It is even shorter to type then `hdiutil` ;-)
|
12
12
|
|
13
|
-
**NOTE: This
|
13
|
+
**NOTE: This runs on Mac OS X only!**
|
14
14
|
|
15
15
|
|
16
16
|
## Installation
|
@@ -30,32 +30,26 @@ Or install it yourself as:
|
|
30
30
|
|
31
31
|
## Usage
|
32
32
|
|
33
|
+
Try `wrapp --help`!
|
34
|
+
|
33
35
|
Some examples...
|
34
36
|
|
35
|
-
|
37
|
+
Wrap the *Chunky Bacon* App:
|
36
38
|
|
37
39
|
```
|
38
40
|
wrapp /Applications/Chunky\ Bacon.app
|
39
|
-
created chunky_bacon_1.2.3.dmg with SHA-1 deadbeef...
|
40
41
|
```
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
43
|
+
Wrap the *Chunky Bacon* App and include the parent directory (some stuff
|
44
|
+
like *TeamViewer* or *FileMaker* reside in sub-directories of
|
45
|
+
`/Applications` rather then the top-level):
|
45
46
|
|
46
47
|
```
|
47
|
-
wrapp --
|
48
|
-
created bacon_1.2.3.dmg with SHA-1 deadbeef...
|
48
|
+
wrapp --include-parent-dir /Applications/why/Chunky Bacon.app
|
49
49
|
```
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
```
|
55
|
-
wrapp --outdir /tmp/dmgs /Applications/Chunky\ Bacon.app
|
56
|
-
...
|
57
|
-
created chunky_bacon_1.2.3.dmg with SHA-1 deadbeef...
|
58
|
-
```
|
51
|
+
The commands create a DMG like `chunky_bacon_1.2.3.dmg` (named after the
|
52
|
+
App + Version) that contains the given App.
|
59
53
|
|
60
54
|
Thats it.
|
61
55
|
|
data/bin/wrapp
CHANGED
@@ -1,58 +1,72 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Helpers
|
2
|
+
|
3
|
+
def create_app(*opts)
|
4
|
+
app = App.new(*opts)
|
5
|
+
FileUtils.rm_f(app.dmg_filename)
|
6
|
+
write_file(app.plist_path, app.plist_content)
|
7
|
+
app
|
4
8
|
end
|
5
9
|
|
6
|
-
|
7
|
-
|
10
|
+
|
11
|
+
def attach_dmg
|
12
|
+
assert_dmg_exists
|
13
|
+
create_dir(volumes_dir)
|
14
|
+
cmd = "hdiutil attach '#{@app.dmg_filename}' -nobrowse -mountroot '#{volumes_dir}'"
|
15
|
+
run_simple(cmd, true)
|
8
16
|
end
|
9
17
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
<string>#{app_name}</string>
|
17
|
-
<key>CFBundleShortVersionString</key>
|
18
|
-
<string>#{app_version}</string>
|
19
|
-
</dict>
|
20
|
-
</plist>
|
21
|
-
}
|
18
|
+
def detach_dmg
|
19
|
+
in_current_dir do
|
20
|
+
Dir.glob("#{volumes_dir}/*") do |dir|
|
21
|
+
system("hdiutil detach '#{dir}' -force >/dev/null")
|
22
|
+
end
|
23
|
+
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
-
run_simple(unescape(cmd))
|
26
|
+
def assert_dmg_exists
|
27
|
+
check_file_presence([@app.dmg_filename], true)
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
'
|
30
|
+
def volumes_dir
|
31
|
+
'Volumes' # We don't want to attach to '/Volumes' in our tests.
|
31
32
|
end
|
32
33
|
|
33
|
-
|
34
|
-
|
34
|
+
|
35
|
+
# Hooks
|
36
|
+
|
37
|
+
After do
|
38
|
+
detach_dmg
|
35
39
|
end
|
36
40
|
|
37
|
-
|
38
|
-
|
41
|
+
|
42
|
+
# Step definitions
|
43
|
+
|
44
|
+
Given(/^an App$/) do
|
45
|
+
@app = create_app
|
39
46
|
end
|
40
47
|
|
41
|
-
|
42
|
-
|
48
|
+
Given(/^an App in a directory$/) do
|
49
|
+
@app = create_app(:prefix => 'Stuff')
|
43
50
|
end
|
44
51
|
|
45
|
-
|
46
|
-
|
52
|
+
When(/^I wrap the App$/) do
|
53
|
+
cmd = "wrapp '#{@app.app_path}'"
|
54
|
+
run_simple(unescape(cmd))
|
55
|
+
end
|
56
|
+
|
57
|
+
When(/^I wrap the App including the parent directory$/) do
|
58
|
+
cmd = "wrapp --include-parent-dir '#{@app.app_path}'"
|
59
|
+
run_simple(unescape(cmd))
|
47
60
|
end
|
48
61
|
|
49
|
-
|
50
|
-
|
62
|
+
Then(/^the App should be wrapped$/) do
|
63
|
+
attach_dmg
|
64
|
+
attached_app_path = File.join(volumes_dir, @app.app_name)
|
65
|
+
check_directory_presence([attached_app_path], true)
|
51
66
|
end
|
52
67
|
|
53
|
-
Then(/^the App should be wrapped
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
# detach dmg
|
68
|
+
Then(/^the App should be wrapped including the parent directory$/) do
|
69
|
+
attach_dmg
|
70
|
+
attached_app_path = File.join(volumes_dir, @app.prefix)
|
71
|
+
check_directory_presence([attached_app_path], true)
|
58
72
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class App
|
2
|
+
def initialize(opts = {})
|
3
|
+
@opts = opts
|
4
|
+
end
|
5
|
+
|
6
|
+
def plist_path
|
7
|
+
File.join(app_path, 'Contents', 'Info.plist')
|
8
|
+
end
|
9
|
+
|
10
|
+
def plist_content
|
11
|
+
%Q{<?xml version="1.0" encoding="UTF-8"?>
|
12
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
13
|
+
<plist version="1.0">
|
14
|
+
<dict>
|
15
|
+
<key>CFBundleName</key>
|
16
|
+
<string>#{app_name}</string>
|
17
|
+
<key>CFBundleShortVersionString</key>
|
18
|
+
<string>#{app_version}</string>
|
19
|
+
</dict>
|
20
|
+
</plist>
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def dmg_filename
|
25
|
+
'chunky_bacon_1.2.3.dmg'
|
26
|
+
end
|
27
|
+
|
28
|
+
def app_version
|
29
|
+
'1.2.3'
|
30
|
+
end
|
31
|
+
|
32
|
+
def app_name
|
33
|
+
'Chunky Bacon'
|
34
|
+
end
|
35
|
+
|
36
|
+
def prefix
|
37
|
+
@opts[:prefix]
|
38
|
+
end
|
39
|
+
|
40
|
+
def app_path
|
41
|
+
basedir = "#{app_name}.app"
|
42
|
+
(prefix && File.join(prefix, basedir)) || basedir
|
43
|
+
end
|
44
|
+
end
|
data/features/wrap_app.feature
CHANGED
@@ -4,10 +4,12 @@ Feature: Wrap App
|
|
4
4
|
As as user
|
5
5
|
I want wrap my App in a DMG
|
6
6
|
|
7
|
-
Scenario:
|
7
|
+
Scenario: Wrap App
|
8
8
|
Given an App
|
9
|
-
When I
|
10
|
-
Then the App should be wrapped
|
9
|
+
When I wrap the App
|
10
|
+
Then the App should be wrapped
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
Scenario: Wrap App including the parent directory
|
13
|
+
Given an App in a directory
|
14
|
+
When I wrap the App including the parent directory
|
15
|
+
Then the App should be wrapped including the parent directory
|
data/lib/wrapp/cli.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Wrapp
|
2
|
+
class CLI
|
3
|
+
include Mixlib::CLI
|
4
|
+
|
5
|
+
option :include_parent_dir,
|
6
|
+
:long => '--include-parent-dir'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def run
|
10
|
+
new.run(ARGV)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(argv)
|
15
|
+
app_path = parse_options(argv).first
|
16
|
+
wrapp(app_path, config)
|
17
|
+
end
|
18
|
+
|
19
|
+
def wrapp(*opts)
|
20
|
+
DMGBuilder.new(*opts).create
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/wrapp/dmg_builder.rb
CHANGED
@@ -2,28 +2,19 @@ module Wrapp
|
|
2
2
|
class DMGBuilder
|
3
3
|
attr_reader :app_path
|
4
4
|
|
5
|
-
|
6
|
-
def run
|
7
|
-
new(ARGV.first).create #TODO: Test this!
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize(app_path)
|
5
|
+
def initialize(app_path, opts = {})
|
12
6
|
@app_path = app_path
|
7
|
+
@opts = opts
|
13
8
|
end
|
14
9
|
|
15
10
|
def create
|
16
|
-
|
11
|
+
system("hdiutil create '#{dmg_filename}' -srcfolder '#{source_path}'")
|
17
12
|
end
|
18
13
|
|
19
14
|
private
|
20
15
|
|
21
|
-
def
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def dmg_path
|
26
|
-
dmg_filename
|
16
|
+
def source_path
|
17
|
+
@opts[:include_parent_dir] ? File.dirname(app_path) : app_path
|
27
18
|
end
|
28
19
|
|
29
20
|
def dmg_filename
|
data/lib/wrapp/version.rb
CHANGED
data/lib/wrapp.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Wrapp
|
4
|
+
describe CLI do
|
5
|
+
let(:cli) { CLI.new }
|
6
|
+
let(:app_path) { '/Applications/Chunky Bacon.app' }
|
7
|
+
|
8
|
+
describe '.run' do
|
9
|
+
it 'runs an instance with ARGV' do
|
10
|
+
cli.should_receive(:run).with(ARGV)
|
11
|
+
CLI.stub(:new).and_return(cli)
|
12
|
+
CLI.run
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#run' do
|
17
|
+
let(:argv) { [app_path] }
|
18
|
+
|
19
|
+
it 'wraps the app' do
|
20
|
+
cli.should_receive(:wrapp).with(app_path, {})
|
21
|
+
cli.run(argv)
|
22
|
+
end
|
23
|
+
|
24
|
+
%w(--include-parent-dir -i).each do |opt|
|
25
|
+
context "with #{opt}" do
|
26
|
+
let(:argv) { [app_path, opt] }
|
27
|
+
|
28
|
+
it 'wraps the app including the parent directory' do
|
29
|
+
cli.should_receive(:wrapp).
|
30
|
+
with(app_path, :include_parent_dir => true)
|
31
|
+
cli.run(argv)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#wrapp' do
|
38
|
+
it 'creates the dmg via dmg builder' do
|
39
|
+
opts = %(some options and arguments)
|
40
|
+
dmg = double('dmg_builder')
|
41
|
+
dmg.should_receive(:create)
|
42
|
+
DMGBuilder.should_receive(:new).with(*opts).and_return(dmg)
|
43
|
+
cli.wrapp(*opts)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -9,41 +9,37 @@ module Wrapp
|
|
9
9
|
DMGBuilder.any_instance.stub(:system)
|
10
10
|
end
|
11
11
|
|
12
|
-
describe '.run' do
|
13
|
-
it 'creates the dmg' do
|
14
|
-
DMGBuilder.stub(:new).and_return(dmg)
|
15
|
-
dmg.should_receive(:create) #TODO: Fix nil warning!
|
16
|
-
DMGBuilder.run
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
12
|
describe '#create' do
|
21
|
-
it 'creates the dmg and directory' do
|
22
|
-
dmg.should_receive(:create_dmg)
|
23
|
-
dmg.create
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe '#create_dmg' do
|
28
13
|
it 'creates the dmg by hdiutil' do
|
29
|
-
dmg.should_receive(:
|
30
|
-
dmg.should_receive(:
|
14
|
+
dmg.should_receive(:source_path).and_return('Chunky.app')
|
15
|
+
dmg.should_receive(:dmg_filename).and_return('bacon.dmg')
|
31
16
|
dmg.should_receive(:system).
|
32
17
|
with("hdiutil create 'bacon.dmg' -srcfolder 'Chunky.app'")
|
33
|
-
dmg.
|
18
|
+
dmg.create
|
34
19
|
end
|
35
20
|
end
|
36
21
|
|
37
22
|
describe '#app_path' do
|
38
|
-
it 'returns the path
|
23
|
+
it 'returns the app path' do
|
39
24
|
expect(dmg.app_path).to eq('Chunky Bacon.app')
|
40
25
|
end
|
41
26
|
end
|
42
27
|
|
43
|
-
describe '#
|
44
|
-
|
45
|
-
dmg.should_receive(:
|
46
|
-
|
28
|
+
describe '#source_path' do
|
29
|
+
before do
|
30
|
+
dmg.should_receive(:app_path).and_return('Chunky/Bacon.app')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns the path of the app dir' do
|
34
|
+
expect(dmg.send(:source_path)).to eq('Chunky/Bacon.app')
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'with :include_parent_dir => true' do
|
38
|
+
let(:dmg) { DMGBuilder.new('...', :include_parent_dir => true) }
|
39
|
+
|
40
|
+
it 'returns the path of the app parent dir' do
|
41
|
+
expect(dmg.send(:source_path)).to eq('Chunky')
|
42
|
+
end
|
47
43
|
end
|
48
44
|
end
|
49
45
|
|
data/wrapp.gemspec
CHANGED
@@ -19,10 +19,11 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_dependency 'plist', '~> 3.1'
|
22
|
+
spec.add_dependency 'mixlib-cli', '~> 1.3'
|
22
23
|
|
23
24
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
25
|
spec.add_development_dependency 'rake'
|
25
|
-
spec.add_development_dependency 'guard'
|
26
|
+
spec.add_development_dependency 'guard'
|
26
27
|
spec.add_development_dependency 'guard-cucumber'
|
27
28
|
spec.add_development_dependency 'guard-rspec'
|
28
29
|
spec.add_development_dependency 'aruba'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wrapp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-10-
|
12
|
+
date: 2013-10-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: plist
|
@@ -27,6 +27,22 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '3.1'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mixlib-cli
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
47
|
name: bundler
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,17 +80,17 @@ dependencies:
|
|
64
80
|
requirement: !ruby/object:Gem::Requirement
|
65
81
|
none: false
|
66
82
|
requirements:
|
67
|
-
- -
|
83
|
+
- - ! '>='
|
68
84
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
85
|
+
version: '0'
|
70
86
|
type: :development
|
71
87
|
prerelease: false
|
72
88
|
version_requirements: !ruby/object:Gem::Requirement
|
73
89
|
none: false
|
74
90
|
requirements:
|
75
|
-
- -
|
91
|
+
- - ! '>='
|
76
92
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
93
|
+
version: '0'
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: guard-cucumber
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,14 +155,17 @@ files:
|
|
139
155
|
- Rakefile
|
140
156
|
- bin/wrapp
|
141
157
|
- features/step_definitions/wrapp_steps.rb
|
158
|
+
- features/support/app.rb
|
142
159
|
- features/support/env.rb
|
143
160
|
- features/wrap_app.feature
|
144
161
|
- lib/wrapp.rb
|
145
162
|
- lib/wrapp/app_info.rb
|
163
|
+
- lib/wrapp/cli.rb
|
146
164
|
- lib/wrapp/dmg_builder.rb
|
147
165
|
- lib/wrapp/version.rb
|
148
166
|
- spec/spec_helper.rb
|
149
167
|
- spec/wrapp/app_info_spec.rb
|
168
|
+
- spec/wrapp/cli_spec.rb
|
150
169
|
- spec/wrapp/dmg_builder_spec.rb
|
151
170
|
- wrapp.gemspec
|
152
171
|
homepage: https://github.com/bjoernalbers/wrapp
|
@@ -164,7 +183,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
164
183
|
version: '0'
|
165
184
|
segments:
|
166
185
|
- 0
|
167
|
-
hash:
|
186
|
+
hash: 983932024076404850
|
168
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
188
|
none: false
|
170
189
|
requirements:
|
@@ -173,17 +192,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
192
|
version: '0'
|
174
193
|
segments:
|
175
194
|
- 0
|
176
|
-
hash:
|
195
|
+
hash: 983932024076404850
|
177
196
|
requirements: []
|
178
197
|
rubyforge_project:
|
179
198
|
rubygems_version: 1.8.23
|
180
199
|
signing_key:
|
181
200
|
specification_version: 3
|
182
|
-
summary: wrapp-0.
|
201
|
+
summary: wrapp-0.2.0
|
183
202
|
test_files:
|
184
203
|
- features/step_definitions/wrapp_steps.rb
|
204
|
+
- features/support/app.rb
|
185
205
|
- features/support/env.rb
|
186
206
|
- features/wrap_app.feature
|
187
207
|
- spec/spec_helper.rb
|
188
208
|
- spec/wrapp/app_info_spec.rb
|
209
|
+
- spec/wrapp/cli_spec.rb
|
189
210
|
- spec/wrapp/dmg_builder_spec.rb
|