furoshiki 0.0.2 → 0.1.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.
- 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
|