furoshiki 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Gemfile +9 -0
- data/README.rdoc +33 -28
- data/Rakefile +3 -1
- data/furoshiki.gemspec +2 -1
- data/lib/furoshiki/exceptions.rb +3 -0
- data/lib/furoshiki/shoes/configuration.rb +146 -0
- data/lib/furoshiki/shoes/swt_app.rb +217 -0
- data/lib/furoshiki/shoes/swt_jar.rb +62 -0
- data/lib/furoshiki/shoes.rb +15 -0
- data/lib/furoshiki/version.rb +1 -1
- data/lib/furoshiki/zip/directory.rb +19 -0
- data/lib/furoshiki/zip/directory_contents.rb +20 -0
- data/lib/furoshiki/zip/recursive.rb +58 -0
- data/lib/furoshiki/zip.rb +2 -0
- data/lib/furoshiki.rb +3 -1
- data/lib/warbler/traits/shoes.rb +51 -0
- data/spec/shoes/configuration_spec.rb +156 -0
- data/spec/shoes/spec_helper.rb +68 -0
- data/spec/shoes/support/shared_config.rb +6 -0
- data/spec/shoes/swt_app_spec.rb +119 -0
- data/spec/shoes/swt_jar_spec.rb +45 -0
- data/spec/shoes/test_app/app.yaml +17 -0
- data/spec/shoes/test_app/bin/hello_world +3 -0
- data/spec/shoes/test_app/dir_to_ignore/file_to_ignore.txt +1 -0
- data/spec/shoes/test_app/img/boots.icns +0 -0
- data/spec/shoes/test_app/img/boots.ico +0 -0
- data/spec/shoes/test_app/img/boots_512x512x32.png +0 -0
- data/spec/shoes/test_app/sibling.rb +1 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/shared_zip.rb +21 -0
- data/spec/support/zip/a/a.rb +3 -0
- data/spec/support/zip/a/b/b.png +0 -0
- data/spec/support/zip/a/b/c/c.rb +3 -0
- data/spec/zip/directory_contents_spec.rb +25 -0
- data/spec/zip/directory_spec.rb +30 -0
- data/vendor/appbundler-1.0.jar +0 -0
- metadata +103 -47
- data/.rvmrc +0 -1
- data/Gemfile.lock +0 -7
- data/lib/furoshiki/rake_task.rb +0 -19
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: de386c74229b401a317c15d3c8ddb5e2b0af9ab4
|
4
|
+
data.tar.gz: 9c590ec9777006a102a182f6ee5586b5c2ce5c3b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e8b5ab686470eb569929192edae4584c911edc8deac8c545d15780034b562e2d9a01fc6e37fa8d6863df07a895cb624cf0bc01ffa491aa58d68ea7cebce973e
|
7
|
+
data.tar.gz: 96eda86a72af8d7888eabc82863b748eca4aa673f6a51c3865522b6d6afb8295509f9d795f37d07cdf5202b6f7bc8adef80920aebeb3569c41991ec84d5ee0b3
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -1,50 +1,55 @@
|
|
1
1
|
= furoshiki
|
2
2
|
|
3
|
-
風呂敷 (Furoshiki) is a simple way to package your Ruby applications for
|
3
|
+
風呂敷 (Furoshiki) is a simple way to package your Ruby applications for
|
4
|
+
distribution on Windows, Linux, and OSX. A 風呂敷 is "a type of traditional
|
5
|
+
Japanese wrapping cloth that were frequently used to transport clothes, gifts,
|
6
|
+
or other goods."
|
4
7
|
|
5
|
-
|
8
|
+
== ALPHA WARNING
|
6
9
|
|
7
|
-
|
10
|
+
This is all super alpha, and is subject to change at any time.
|
8
11
|
|
9
|
-
|
12
|
+
== Packaging Shoes apps
|
10
13
|
|
11
|
-
|
14
|
+
For the moment, we only really package Shoes apps. See ALPHA WARNING above ;)
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
path = 'path/to/your/shoes-app' # See Furoshiki::Shoes::Configuration
|
17
|
+
config = Furoshiki::Shoes::Configuration.load(path)
|
18
|
+
packager = Furoshiki::Shoes.new(:swt, :app, config)
|
19
|
+
packager.package
|
16
20
|
|
17
|
-
|
21
|
+
Or use the shoes4 command line interface:
|
18
22
|
|
19
|
-
|
23
|
+
bin/shoes -p swt:app path/to/your/shoes-app
|
20
24
|
|
21
|
-
|
25
|
+
Eventually, we will be able to package non-Shoes apps too.
|
22
26
|
|
23
27
|
== Inspiration
|
24
28
|
|
25
|
-
The inspiriation for 風呂敷 came from Shoes[http://shoesrb.com]. One of Shoes'
|
29
|
+
The inspiriation for 風呂敷 came from Shoes[http://shoesrb.com]. One of Shoes'
|
30
|
+
best features is packaging up scripts made with Shoes into their own
|
31
|
+
executables. You could take any little script and make a .app, .exe, or .run
|
32
|
+
file. However, this code was really complicated, and made Shoes hard to
|
33
|
+
maintain. It was often the source of people's problems when trying to build
|
34
|
+
Shoes of their own. So, while working on Shoes 4, I decided to see if anyone
|
35
|
+
else was doing anything similar. I came across the .app for
|
36
|
+
libgosu[http://code.google.com/p/gosu/wiki/RubyPackagingOnOsx], which was doing
|
37
|
+
a similar thing. After emailing Julian, I decided that if this was useful for
|
38
|
+
Shoes, and useful for libgosu, it'd probably be useful for other projects, too.
|
39
|
+
So I've set out to figure out the Shoes packager, play with the libgosu
|
40
|
+
versions, and come up with an easy way for you to bundle and distribute GUI
|
41
|
+
programs written in Ruby.
|
26
42
|
|
27
43
|
== Helping out with 風呂敷
|
28
44
|
|
29
|
-
|
30
|
-
|
31
|
-
* Ruby 1.9.2
|
32
|
-
* Bundler
|
33
|
-
* git flow
|
34
|
-
|
35
|
-
I personally use rvm, so I also have a .rvmrc set up. It'll switch to the right Ruby when you cd into the directory, so you might see something about needing to create a gemset. If you use rvm, it's probably a good idea:
|
36
|
-
|
37
|
-
$ rvm gemset create furoshiki
|
38
|
-
|
39
|
-
Since you've made a new gemset, you'll probably need to install bundler:
|
45
|
+
It's easy! Just clone it down and do the usual bundler thing:
|
40
46
|
|
47
|
+
$ git clone https://github.com/shoes/furoshiki.git
|
48
|
+
$ cd furoshiki
|
41
49
|
$ gem install bundler
|
50
|
+
$ bundle
|
42
51
|
|
43
|
-
|
44
|
-
|
45
|
-
=== A note about git flow
|
46
|
-
|
47
|
-
git-flow[http://github.com/nvie/gitflow] is totally awesome, so I use it to manage my branches. I'm just using the default settings. What this means for you: you can use git-flow, but if you don't, master is just for stable stuff, develop is where all the action is happening. Patches and pull requests should be created off of develop.
|
52
|
+
Easy-peasy.
|
48
53
|
|
49
54
|
=== Note on Patches/Pull Requests
|
50
55
|
|
data/Rakefile
CHANGED
data/furoshiki.gemspec
CHANGED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Furoshiki
|
5
|
+
module Shoes
|
6
|
+
# Configuration for Shoes packagers.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# config_file = '/path/to/app.yaml'
|
10
|
+
# config = Shoes::Package::Configuration.load(config_file)
|
11
|
+
#
|
12
|
+
# If your configuration uses hashes, the keys will always be
|
13
|
+
# symbols, even if you have created it with string keys. It's just
|
14
|
+
# easier that way.
|
15
|
+
#
|
16
|
+
# This is a value object. If you need to modify your configuration
|
17
|
+
# after initialization, dump it with #to_hash, make your changes,
|
18
|
+
# and instantiate a new object.
|
19
|
+
class Configuration
|
20
|
+
# Convenience method for loading config from a file. Note that you
|
21
|
+
# can pass four kinds of paths to the loader. Given the following
|
22
|
+
# file structure:
|
23
|
+
#
|
24
|
+
# ├── a
|
25
|
+
# │ ├── app.yaml
|
26
|
+
# │ └── shoes-app-a.rb
|
27
|
+
# └── b
|
28
|
+
# └── shoes-app-b.rb
|
29
|
+
#
|
30
|
+
# To package an app that has an `app.yaml`, like `shoes-app-a.rb`,
|
31
|
+
# you can call the loader with any of:
|
32
|
+
#
|
33
|
+
# - a/app.yaml
|
34
|
+
# - a
|
35
|
+
# - a/shoes-app-a.rb
|
36
|
+
#
|
37
|
+
# These will all find and use your configuration in `a/app.yaml`.
|
38
|
+
# To package an app that does not have an `app.yaml`, like
|
39
|
+
# `b/shoes-app-b.rb`, you must call the loader with the path of
|
40
|
+
# the script itself. Note that without an `app.yaml`, you will
|
41
|
+
# only bundle a single file, and your app will simply use the
|
42
|
+
# Shoes app icon.
|
43
|
+
#
|
44
|
+
# @overload load(path)
|
45
|
+
# @param [String] path location of the app's 'app.yaml'
|
46
|
+
# @overload load(path)
|
47
|
+
# @param [String] path location of the directory that
|
48
|
+
# contains the app's 'app.yaml'
|
49
|
+
# @overload load(path)
|
50
|
+
# @param [String] path location of the app
|
51
|
+
def self.load(path = 'app.yaml')
|
52
|
+
pathname = Pathname.new(path)
|
53
|
+
app_yaml = Pathname.new('app.yaml')
|
54
|
+
|
55
|
+
dummy_file = Struct.new(:read)
|
56
|
+
|
57
|
+
if pathname.basename == app_yaml
|
58
|
+
file, dir = pathname, pathname.dirname
|
59
|
+
elsif pathname.directory?
|
60
|
+
file, dir = pathname.join(app_yaml), pathname
|
61
|
+
elsif pathname.file? && pathname.parent.children.include?(pathname.parent.join app_yaml)
|
62
|
+
file, dir = pathname.parent.join(app_yaml), pathname.parent
|
63
|
+
else
|
64
|
+
# Can't find any 'app.yaml', so assume we just want to wrap
|
65
|
+
# this file. If it exists, load default options. If not, let
|
66
|
+
# the filesystem raise an error.
|
67
|
+
default_options = {
|
68
|
+
run: pathname.basename.to_s,
|
69
|
+
name: pathname.basename(pathname.extname).to_s.gsub(/\W/, '-')
|
70
|
+
}.to_yaml
|
71
|
+
options = pathname.exist? ? default_options : pathname
|
72
|
+
file = dummy_file.new(options)
|
73
|
+
dir = pathname.parent
|
74
|
+
end
|
75
|
+
new YAML.load(file.read), dir
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param [Hash] config user options
|
79
|
+
# @param [String] working_dir directory in which do packaging work
|
80
|
+
def initialize(config = {}, working_dir = Dir.pwd)
|
81
|
+
defaults = {
|
82
|
+
name: 'Shoes App',
|
83
|
+
version: '0.0.0',
|
84
|
+
release: 'Rookie',
|
85
|
+
run: nil,
|
86
|
+
ignore: 'pkg',
|
87
|
+
icons: {
|
88
|
+
#osx: 'path/to/default/App.icns',
|
89
|
+
#gtk: 'path/to/default/app.png',
|
90
|
+
#win32: 'path/to/default/App.ico',
|
91
|
+
},
|
92
|
+
dmg: {
|
93
|
+
ds_store: 'path/to/default/.DS_Store',
|
94
|
+
background: 'path/to/default/background.png'
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
# Overwrite defaults with supplied config
|
99
|
+
@config = config.inject(defaults) { |c, (k, v)| set_symbol_key c, k, v }
|
100
|
+
|
101
|
+
# Ensure that we always have what we need
|
102
|
+
@config[:shortname] ||= @config[:name].downcase.gsub(/\W+/, '')
|
103
|
+
[:ignore, :gems].each { |k| @config[k] = Array(@config[k]) }
|
104
|
+
@config[:gems] << 'shoes'
|
105
|
+
|
106
|
+
# Define reader for each key
|
107
|
+
metaclass = class << self; self; end
|
108
|
+
@config.keys.each do |k|
|
109
|
+
metaclass.send(:define_method, k) do
|
110
|
+
@config[k]
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
@working_dir = Pathname.new(working_dir)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @return [Pathname] the current working directory
|
118
|
+
attr_reader :working_dir
|
119
|
+
|
120
|
+
def to_hash
|
121
|
+
@config
|
122
|
+
end
|
123
|
+
|
124
|
+
def ==(other)
|
125
|
+
super unless other.class == self.class && other.respond_to?(:to_hash)
|
126
|
+
@config == other.to_hash
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
# Ensure symbol keys, even in nested hashes
|
131
|
+
#
|
132
|
+
# @param [Hash] config the hash to set (key: value) on
|
133
|
+
# @param [#to_sym] k the key
|
134
|
+
# @param [Object] v the value
|
135
|
+
# @return [Hash] an updated hash
|
136
|
+
def set_symbol_key(config, k, v)
|
137
|
+
if v.kind_of? Hash
|
138
|
+
config[k.to_sym] = v.inject({}) { |hash, (k, v)| set_symbol_key(hash, k, v) }
|
139
|
+
else
|
140
|
+
config[k.to_sym] = v
|
141
|
+
end
|
142
|
+
config
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'furoshiki/exceptions'
|
2
|
+
require 'furoshiki/shoes/configuration'
|
3
|
+
require 'furoshiki/zip/directory'
|
4
|
+
require 'furoshiki/shoes/swt_jar'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'plist'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'net/http'
|
9
|
+
|
10
|
+
module Furoshiki
|
11
|
+
module Shoes
|
12
|
+
class SwtApp
|
13
|
+
include FileUtils
|
14
|
+
|
15
|
+
# @param [Shoes::Package::Configuration] config user configuration
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
home = ENV['FUROSHIKI_HOME'] || Dir.home
|
19
|
+
@cache_dir = Pathname.new(home).join('.furoshiki', 'cache')
|
20
|
+
@default_package_dir = working_dir.join('pkg')
|
21
|
+
@package_dir = default_package_dir
|
22
|
+
@default_template_path = cache_dir.join(template_filename)
|
23
|
+
@template_path = default_template_path
|
24
|
+
@tmp = @package_dir.join('tmp')
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Pathname] default package directory: ./pkg
|
28
|
+
attr_reader :default_package_dir
|
29
|
+
|
30
|
+
# @return [Pathname] package directory
|
31
|
+
attr_accessor :package_dir
|
32
|
+
|
33
|
+
# @return [Pathname] default path to .app template
|
34
|
+
attr_reader :default_template_path
|
35
|
+
|
36
|
+
# @return [Pathname] path to .app template
|
37
|
+
attr_accessor :template_path
|
38
|
+
|
39
|
+
# @return [Pathname] cache directory
|
40
|
+
attr_reader :cache_dir
|
41
|
+
|
42
|
+
attr_reader :config
|
43
|
+
|
44
|
+
attr_reader :tmp
|
45
|
+
|
46
|
+
def package
|
47
|
+
remove_tmp
|
48
|
+
create_tmp
|
49
|
+
cache_template
|
50
|
+
extract_template
|
51
|
+
inject_icon
|
52
|
+
inject_config
|
53
|
+
jar_path = ensure_jar_exists
|
54
|
+
inject_jar jar_path
|
55
|
+
move_to_package_dir tmp_app_path
|
56
|
+
tweak_permissions
|
57
|
+
rescue => e
|
58
|
+
raise e
|
59
|
+
ensure
|
60
|
+
remove_tmp
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_tmp
|
64
|
+
tmp.mkpath
|
65
|
+
end
|
66
|
+
|
67
|
+
def remove_tmp
|
68
|
+
tmp.rmtree if tmp.exist?
|
69
|
+
end
|
70
|
+
|
71
|
+
def cache_template
|
72
|
+
cache_dir.mkpath unless cache_dir.exist?
|
73
|
+
download_template unless template_path.size?
|
74
|
+
end
|
75
|
+
|
76
|
+
def template_basename
|
77
|
+
'shoes-app-template'
|
78
|
+
end
|
79
|
+
|
80
|
+
def template_extension
|
81
|
+
'.zip'
|
82
|
+
end
|
83
|
+
|
84
|
+
def template_filename
|
85
|
+
"#{template_basename}#{template_extension}"
|
86
|
+
end
|
87
|
+
|
88
|
+
def latest_template_version
|
89
|
+
'0.0.1'
|
90
|
+
end
|
91
|
+
|
92
|
+
def download_template
|
93
|
+
download remote_template_url, template_path
|
94
|
+
end
|
95
|
+
|
96
|
+
def download(remote_url, local_path)
|
97
|
+
download_following_redirects remote_url, local_path
|
98
|
+
end
|
99
|
+
|
100
|
+
def download_following_redirects(remote_url, local_path, redirect_limit = 5)
|
101
|
+
raise Furoshiki::DownloadError, "Too many redirects" if redirect_limit == 0
|
102
|
+
|
103
|
+
uri = URI(remote_url)
|
104
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
105
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
106
|
+
http.request request do |response|
|
107
|
+
case response
|
108
|
+
when Net::HTTPSuccess then
|
109
|
+
warn "Downloading #{remote_url} to #{local_path}"
|
110
|
+
open(local_path, 'wb') do |file|
|
111
|
+
response.read_body do |chunk|
|
112
|
+
file.write chunk
|
113
|
+
end
|
114
|
+
end
|
115
|
+
when Net::HTTPRedirection then
|
116
|
+
location = response['location']
|
117
|
+
warn "Redirected to #{location}"
|
118
|
+
download_following_redirects(location, local_path, redirect_limit - 1)
|
119
|
+
else
|
120
|
+
raise Furoshiki::DownloadError, "Couldn't download app template at #{remote_url}. #{response.value}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def downloads_url
|
127
|
+
"http://shoesrb.com/downloads"
|
128
|
+
end
|
129
|
+
|
130
|
+
def remote_template_url
|
131
|
+
"#{downloads_url}/#{template_basename}-#{latest_template_version}#{template_extension}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def move_to_package_dir(path)
|
135
|
+
dest = package_dir.join(path.basename)
|
136
|
+
dest.rmtree if dest.exist?
|
137
|
+
mv path.to_s, dest
|
138
|
+
end
|
139
|
+
|
140
|
+
def ensure_jar_exists
|
141
|
+
jar = SwtJar.new(@config)
|
142
|
+
path = tmp.join(jar.filename)
|
143
|
+
jar.package(tmp) unless File.exist?(path)
|
144
|
+
path
|
145
|
+
end
|
146
|
+
|
147
|
+
# Injects JAR into APP. The JAR should be the only item in the
|
148
|
+
# Contents/Java directory. If this directory contains more than one
|
149
|
+
# JAR, the "first" one gets run, which may not be what we want.
|
150
|
+
#
|
151
|
+
# @param [Pathname, String] jar_path the location of the JAR to inject
|
152
|
+
def inject_jar(jar_path)
|
153
|
+
jar_dir = tmp_app_path.join('Contents/Java')
|
154
|
+
jar_dir.rmtree
|
155
|
+
jar_dir.mkdir
|
156
|
+
cp Pathname.new(jar_path), jar_dir
|
157
|
+
end
|
158
|
+
|
159
|
+
def extract_template
|
160
|
+
raise IOError, "Couldn't find app template at #{template_path}." unless template_path.size?
|
161
|
+
extracted_app = nil
|
162
|
+
::Zip::ZipFile.new(template_path).each do |entry|
|
163
|
+
# Fragile hack
|
164
|
+
extracted_app = template_path.join(entry.name) if Pathname.new(entry.name).extname == '.app'
|
165
|
+
p = tmp.join(entry.name)
|
166
|
+
p.dirname.mkpath
|
167
|
+
entry.extract(p)
|
168
|
+
end
|
169
|
+
mv tmp.join(extracted_app.basename.to_s), tmp_app_path
|
170
|
+
end
|
171
|
+
|
172
|
+
def inject_config
|
173
|
+
plist = tmp_app_path.join 'Contents/Info.plist'
|
174
|
+
template = Plist.parse_xml(plist)
|
175
|
+
template['CFBundleIdentifier'] = "com.hackety.shoes.#{config.shortname}"
|
176
|
+
template['CFBundleDisplayName'] = config.name
|
177
|
+
template['CFBundleName'] = config.name
|
178
|
+
template['CFBundleVersion'] = config.version
|
179
|
+
template['CFBundleIconFile'] = Pathname.new(config.icons[:osx]).basename.to_s if config.icons[:osx]
|
180
|
+
File.open(plist, 'w') { |f| f.write template.to_plist }
|
181
|
+
end
|
182
|
+
|
183
|
+
def inject_icon
|
184
|
+
if config.icons[:osx]
|
185
|
+
icon_path = working_dir.join(config.icons[:osx])
|
186
|
+
raise IOError, "Couldn't find app icon at #{icon_path}" unless icon_path.exist?
|
187
|
+
resources_dir = tmp_app_path.join('Contents/Resources')
|
188
|
+
cp icon_path, resources_dir.join(icon_path.basename)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def tweak_permissions
|
193
|
+
executable_path.chmod 0755
|
194
|
+
end
|
195
|
+
|
196
|
+
def app_name
|
197
|
+
"#{config.name}.app"
|
198
|
+
end
|
199
|
+
|
200
|
+
def tmp_app_path
|
201
|
+
tmp.join app_name
|
202
|
+
end
|
203
|
+
|
204
|
+
def app_path
|
205
|
+
package_dir.join app_name
|
206
|
+
end
|
207
|
+
|
208
|
+
def executable_path
|
209
|
+
app_path.join('Contents/MacOS/JavaAppLauncher')
|
210
|
+
end
|
211
|
+
|
212
|
+
def working_dir
|
213
|
+
config.working_dir
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'furoshiki/shoes/configuration'
|
2
|
+
require 'warbler'
|
3
|
+
require 'warbler/traits/shoes'
|
4
|
+
|
5
|
+
module Furoshiki
|
6
|
+
module Shoes
|
7
|
+
class SwtJar
|
8
|
+
# @param [Furoshiki::Shoes::Configuration] config user configuration
|
9
|
+
def initialize(config = nil)
|
10
|
+
@shoes_config = config || Furoshiki::Shoes::Configuration.load
|
11
|
+
Dir.chdir working_dir do
|
12
|
+
@config = Warbler::Config.new do |config|
|
13
|
+
config.jar_name = @shoes_config.shortname
|
14
|
+
config.pathmaps.application = ['shoes-app/%p']
|
15
|
+
specs = @shoes_config.gems.map { |g| Gem::Specification.find_by_name(g) }
|
16
|
+
dependencies = specs.map { |s| s.runtime_dependencies }.flatten
|
17
|
+
(specs + dependencies).uniq.each { |g| config.gems << g }
|
18
|
+
ignore = @shoes_config.ignore.map do |f|
|
19
|
+
path = f.to_s
|
20
|
+
children = Dir.glob("#{path}/**/*") if File.directory?(path)
|
21
|
+
[path, *children]
|
22
|
+
end.flatten
|
23
|
+
config.excludes.add FileList.new(ignore.flatten).pathmap(config.pathmaps.application.first)
|
24
|
+
config.gem_excludes += [/^samples/, /^examples/, /^test/, /^spec/]
|
25
|
+
end
|
26
|
+
@config.extend ShoesWarblerConfig
|
27
|
+
@config.run = @shoes_config.run.split(/\s/).first
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def package(dir = default_dir)
|
32
|
+
Dir.chdir working_dir do
|
33
|
+
jar = Warbler::Jar.new
|
34
|
+
jar.apply @config
|
35
|
+
package_dir = dir.relative_path_from(working_dir)
|
36
|
+
package_dir.mkpath
|
37
|
+
path = package_dir.join(filename).to_s
|
38
|
+
jar.create path
|
39
|
+
File.expand_path path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def default_dir
|
44
|
+
working_dir.join 'pkg'
|
45
|
+
end
|
46
|
+
|
47
|
+
def filename
|
48
|
+
"#{@config.jar_name}.#{@config.jar_extension}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def working_dir
|
52
|
+
@shoes_config.working_dir
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
# Adds Shoes-specific functionality to the Warbler Config
|
57
|
+
module ShoesWarblerConfig
|
58
|
+
attr_accessor :run
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'furoshiki/shoes/swt_jar'
|
2
|
+
require 'furoshiki/shoes/swt_app'
|
3
|
+
|
4
|
+
module Furoshiki
|
5
|
+
module Shoes
|
6
|
+
def self.new(backend, wrapper, config)
|
7
|
+
class_name = class_name_for(backend, wrapper)
|
8
|
+
self.const_get(class_name).new(config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.class_name_for(backend, wrapper)
|
12
|
+
[backend, wrapper].map { |name| name.to_s.capitalize }.join
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/furoshiki/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'furoshiki/zip/recursive'
|
2
|
+
|
3
|
+
module Furoshiki
|
4
|
+
module Zip
|
5
|
+
class Directory
|
6
|
+
# @param [#to_s] input_dir the directory to zip
|
7
|
+
# @param [#to_s] output_file the location of the output archive
|
8
|
+
def initialize(input_dir, output_file)
|
9
|
+
@input_dir = Pathname.new(input_dir)
|
10
|
+
@zip = Recursive.new(output_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Zip the whole input directory, including the root
|
14
|
+
def write
|
15
|
+
@zip.write [@input_dir.basename], @input_dir.parent, ''
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'furoshiki/zip/recursive'
|
2
|
+
|
3
|
+
module Furoshiki
|
4
|
+
module Zip
|
5
|
+
class DirectoryContents
|
6
|
+
# @param [#to_s] input_dir the directory to zip
|
7
|
+
# @param [#to_s] output_file the location of the output archive
|
8
|
+
def initialize(input_dir, output_file)
|
9
|
+
@input_dir = Pathname.new(input_dir)
|
10
|
+
@zip = Recursive.new(output_file)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Zip the contents of the input directory, without the root.
|
14
|
+
def write
|
15
|
+
entries = @input_dir.children(false)
|
16
|
+
@zip.write entries, @input_dir, ''
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|