irpack 0.1.0 → 0.2.1

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/bin/irpack CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ir
2
2
 
3
3
  =begin
4
- Copyright (c) 2010 Ryuichi Sakamoto.
4
+ Copyright (c) 2010-2011 Ryuichi Sakamoto.
5
5
 
6
6
  This software is provided 'as-is', without any express or implied
7
7
  warranty. In no event will the authors be held liable for any damages
@@ -23,34 +23,8 @@ freely, subject to the following restrictions:
23
23
  distribution.
24
24
  =end
25
25
 
26
- require 'irpack'
27
- require 'optparse'
28
-
29
- packdir = nil
30
- output_file = nil
31
- target = :exe
32
- compress = false
33
- stdlib = true
34
- opt = OptionParser.new
35
- opt.on('-d SOURCEDIR', 'Specify pack directory. [base of ENTRYFILE]') {|v| packdir = v }
36
- opt.on('-o OUTPUTFILE', 'Specify output file name.') {|v| output_file = v }
37
- opt.on('-w', 'Generate window app.') { target = :winexe }
38
- opt.on('-W', 'Generate console app.[default]') { target = :exe }
39
- opt.on('--compress', 'Compress package.') { compress = true }
40
- opt.on('--no-stdlib', 'Do not include IronRuby assemblies.') {|v| stdlib = v }
41
- opt.banner = "Usage: #{$0} [options] ENTRYFILE"
42
- opt.parse!(ARGV)
43
-
44
- if ARGV.size<1 then
45
- $stderr.puts opt.help
46
- exit 1
47
- end
48
-
49
- entry_file = ARGV[0]
50
- packdir ||= File.dirname(entry_file)
51
- output_file ||= File.join(File.dirname(entry_file), File.basename(entry_file, '.*')+'.exe')
52
- IRPack.pack_dir(packdir, entry_file, output_file,
53
- :target => target,
54
- :compress => compress,
55
- :stdlib => stdlib)
26
+ require 'irpack/application'
27
+
28
+ args = IRPack::Application::Arguments.parse!(ARGV)
29
+ exit(IRPack::Application.run(args))
56
30
 
@@ -1,5 +1,5 @@
1
1
  =begin
2
- Copyright (c) 2010 Ryuichi Sakamoto.
2
+ Copyright (c) 2010-2011 Ryuichi Sakamoto.
3
3
 
4
4
  This software is provided 'as-is', without any express or implied
5
5
  warranty. In no event will the authors be held liable for any damages
@@ -21,484 +21,72 @@ freely, subject to the following restrictions:
21
21
  distribution.
22
22
  =end
23
23
 
24
- require 'erb'
25
- require 'fileutils'
24
+ require 'irpack/cscompiler'
25
+ require 'irpack/bootloader'
26
+ require 'irpack/entrypoint'
27
+ require 'irpack/packager'
28
+ require 'irpack/missing'
26
29
  require 'tmpdir'
27
- require 'pathname'
28
- require 'WindowsBase'
29
-
30
- unless Dir.respond_to?(:mktmpdir) then
31
- def Dir.mktmpdir(prefix_suffix=['d',''], tmpdir=Dir.tmpdir, &block)
32
- if prefix_suffix.kind_of?(String) then
33
- prefix = prefix_suffix
34
- suffix = ''
35
- else
36
- prefix = prefix_suffix[0]
37
- suffix = prefix_suffix[1]
38
- end
39
- n = 0
40
- begin
41
- path = File.join(tmpdir, "#{prefix}-#{Time.now.to_i}-#{$$}-#{rand(0x100000000).to_s(36)}-#{suffix}-#{n}")
42
- Dir.mkdir(path, 0700)
43
- rescue Errno::EEXIST
44
- n += 1
45
- retry
46
- end
47
-
48
- if block then
49
- begin
50
- block.call(path)
51
- ensure
52
- FileUtils.remove_entry_secure(path)
53
- end
54
- else
55
- path
56
- end
57
- end
58
- end
59
-
60
- module IRPack
61
- include System
62
- include System::Reflection
63
-
64
- module CSCompiler
65
- include Microsoft::CSharp
66
- include System::CodeDom::Compiler
67
- include System::Reflection
68
-
69
- module_function
70
- def compiler_version
71
- case System::Environment.version.major
72
- when 4
73
- 'v4.0'
74
- when 2
75
- 'v3.5'
76
- end
77
- end
78
-
79
- def system_assemblies
80
- case compiler_version
81
- when 'v4.0'
82
- [
83
- 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
84
- 'WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
85
- 'System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
86
- ]
87
- when 'v3.5'
88
- [
89
- 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
90
- 'WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35',
91
- 'System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089',
92
- ]
93
- end
94
- end
95
-
96
- def system_assembly_files
97
- system_assemblies.collect {|name|
98
- Assembly.reflection_only_load(name.to_clr_string).location
99
- }
100
- end
101
-
102
- def find_assembly(paths, file)
103
- path = paths.find {|path| File.exist?(File.join(path, file)) }
104
- if path then
105
- File.join(path, file)
106
- else
107
- file
108
- end
109
- end
110
-
111
- class CompileError < RuntimeError; end
112
- def compile(target, srcs, references, resources, output_name)
113
- opts = System::Collections::Generic::Dictionary[System::String,System::String].new
114
- opts['CompilerVersion'] = compiler_version
115
- @compiler = CSharpCodeProvider.new(opts)
116
- srcs = srcs.kind_of?(Array) ? srcs : [srcs]
117
- refs = system_assembly_files + references
118
- refs = System::Array[System::String].new(refs.size) {|i| refs[i] }
119
- icon = resources.find {|rc| File.extname(rc)=='.ico' }
120
-
121
- params = CompilerParameters.new(refs, output_name, false)
122
- params.generate_in_memory = false
123
- compiler_options = ['/optimize+']
124
- case target
125
- when :exe, 'exe'
126
- params.generate_executable = true
127
- compiler_options << '/target:exe'
128
- compiler_options << "/win32icon:#{icon}" if icon
129
- when :winexe, 'winexe'
130
- params.generate_executable = true
131
- compiler_options << '/target:winexe'
132
- compiler_options << "/win32icon:#{icon}" if icon
133
- else
134
- params.generate_executable = false
135
- compiler_options << '/target:library'
136
- end
137
- params.compiler_options = compiler_options.join(' ')
138
- resources.each do |rc|
139
- params.embedded_resources.add(rc)
140
- end
141
- srcs = System::Array[System::String].new(srcs.size) {|i| srcs[i] }
142
- result = @compiler.compile_assembly_from_source(params, srcs)
143
- result.errors.each do |err|
144
- if err.is_warning then
145
- $stderr.puts(err.to_s)
146
- else
147
- raise CompileError, err.to_s
148
- end
149
- end
150
- result.path_to_assembly
151
- end
152
- end
153
- end
154
30
 
155
31
  module IRPack
156
- BootLoaderSource = <<CS
157
- using System;
158
- using System.IO;
159
- using System.IO.Packaging;
160
- using System.Reflection;
161
-
162
- namespace <%= module_name %> {
163
- public class BootLoader
164
- {
165
- private static Assembly LoadAssemblyFromPackage(AppDomain domain, Package package, string file)
166
- {
167
- var uri = PackUriHelper.CreatePartUri(new Uri(file, UriKind.Relative));
168
- if (package.PartExists(uri)) {
169
- var stream = package.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
170
- var raw = new byte[stream.Length];
171
- stream.Read(raw, 0, (int)stream.Length);
172
- stream.Close();
173
- return domain.Load(raw);
174
- }
175
- else {
176
- return null;
177
- }
178
- }
179
-
180
- private static Assembly LoadAssembly(AppDomain domain, Package package, string file)
181
- {
182
- try {
183
- return domain.Load(file);
184
- }
185
- catch (FileNotFoundException)
186
- {
187
- return LoadAssemblyFromPackage(domain, package, file);
188
- }
189
- }
190
-
191
- public static int Main(string[] args)
192
- {
193
- AppDomain domain = AppDomain.CurrentDomain;
194
- domain.AssemblyResolve += new ResolveEventHandler(delegate (object sender, ResolveEventArgs e) {
195
- foreach (var asm in domain.GetAssemblies()) {
196
- if (e.Name==asm.FullName) {
197
- return asm;
198
- }
199
- }
200
- throw new FileNotFoundException(e.Name);
201
- });
202
- var stream = Assembly.GetEntryAssembly().GetManifestResourceStream(@"<%= package_file %>");
203
- var package = Package.Open(stream, FileMode.Open, FileAccess.Read);
204
- <% preload_assemblies.each do |asm| %>
205
- LoadAssembly(domain, package, @"<%= asm %>");
206
- <% end %>
207
- var entry_point = LoadAssemblyFromPackage(domain, package, @"<%= module_name %>.EntryPoint.dll");
208
- var main = entry_point.GetType(@"<%= module_name %>.EntryPoint").GetMethod("Main");
209
- int result = (int)(main.Invoke(null, new object[] { package, args }));
210
- package.Close();
211
- return result;
212
- }
213
- }
214
- }
215
- CS
216
-
217
- EntryPointSource = <<CS
218
- using System;
219
- using System.IO;
220
- using System.IO.Packaging;
221
- using System.Reflection;
222
- using Microsoft.Scripting;
223
- using Microsoft.Scripting.Hosting;
224
-
225
- namespace <%= module_name %> {
226
- public class EntryPoint
227
- {
228
- public class PackagePAL : PlatformAdaptationLayer
229
- {
230
- public Package CurrentPackage { get; set; }
231
- public PackagePAL(Package pkg)
232
- {
233
- CurrentPackage = pkg;
234
- }
235
-
236
- private Uri ToPackageLoadPath(string path)
237
- {
238
- var domain = AppDomain.CurrentDomain;
239
- var fullpath = Path.GetFullPath(path);
240
- var searchpath = Path.GetFullPath(
241
- domain.RelativeSearchPath!=null ?
242
- Path.Combine(domain.BaseDirectory, domain.RelativeSearchPath) :
243
- domain.BaseDirectory);
244
- if (fullpath.StartsWith(searchpath)) {
245
- var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
246
- return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
247
- }
248
- else {
249
- return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
250
- }
251
- }
252
-
253
- private Uri ToPackagePath(string path)
254
- {
255
- var fullpath = Path.GetFullPath(path);
256
- var searchpath = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetEntryAssembly().Location));
257
- if (fullpath.StartsWith(searchpath)) {
258
- var relpath = fullpath.Substring(searchpath.Length, fullpath.Length-searchpath.Length);
259
- return PackUriHelper.CreatePartUri(new Uri(relpath, UriKind.Relative));
260
- }
261
- else {
262
- return PackUriHelper.CreatePartUri(new Uri(path, UriKind.Relative));
263
- }
264
- }
265
-
266
- public override Assembly LoadAssembly(string name)
267
- {
268
- foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
269
- if (asm.FullName==name) {
270
- return asm;
271
- }
272
- }
273
- return Assembly.Load(name);
274
- }
275
-
276
- public override Assembly LoadAssemblyFromPath(string path)
277
- {
278
- try {
279
- return Assembly.LoadFile(path);
280
- }
281
- catch (FileNotFoundException e) {
282
- var uri = ToPackageLoadPath(path);
283
- if (CurrentPackage.PartExists(uri)) {
284
- var stream = CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
285
- var raw = new byte[stream.Length];
286
- stream.Read(raw, 0, (int)stream.Length);
287
- stream.Close();
288
- return Assembly.Load(raw);
289
- }
290
- else {
291
- throw e;
292
- }
293
- }
294
- }
295
-
296
- public override bool FileExists(string path)
297
- {
298
- if (File.Exists(path)) {
299
- return true;
300
- }
301
- else {
302
- var uri = ToPackagePath(path);
303
- return CurrentPackage.PartExists(uri);
304
- }
305
- }
306
-
307
- public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share)
308
- {
309
- if (mode==FileMode.Open && access==FileAccess.Read) {
310
- var uri = ToPackagePath(path);
311
- if (CurrentPackage.PartExists(uri)) {
312
- return CurrentPackage.GetPart(uri).GetStream(mode, access);
313
- }
314
- else {
315
- return new FileStream(path, mode, access, share);
316
- }
317
- }
318
- else {
319
- return new FileStream(path, mode, access, share);
320
- }
321
- }
322
-
323
- public override Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
324
- {
325
- if (mode==FileMode.Open && access==FileAccess.Read) {
326
- var uri = ToPackagePath(path);
327
- if (CurrentPackage.PartExists(uri)) {
328
- return CurrentPackage.GetPart(uri).GetStream(mode, access);
329
- }
330
- else {
331
- return new FileStream(path, mode, access, share, bufferSize);
332
- }
333
- }
334
- else {
335
- return new FileStream(path, mode, access, share, bufferSize);
336
- }
337
- }
338
-
339
- public override Stream OpenInputFileStream(string path)
340
- {
341
- var uri = ToPackagePath(path);
342
- if (CurrentPackage.PartExists(uri)) {
343
- return CurrentPackage.GetPart(uri).GetStream(FileMode.Open, FileAccess.Read);
344
- }
345
- else {
346
- return new FileStream(path, FileMode.Open, FileAccess.Read);
347
- }
348
- }
349
- }
350
-
351
- public class IRHost : ScriptHost
352
- {
353
- private PlatformAdaptationLayer PAL_;
354
- public override PlatformAdaptationLayer PlatformAdaptationLayer { get { return PAL_; } }
355
- public IRHost(Package pkg)
356
- {
357
- PAL_ = new PackagePAL(pkg);
358
- }
359
- }
360
-
361
- public static int Main(Package package, string[] args)
362
- {
363
- var runtime_setup = new ScriptRuntimeSetup();
364
- runtime_setup.LanguageSetups.Add(IronRuby.Ruby.CreateRubySetup());
365
- runtime_setup.Options["MainFile"] = "<%= entry_file %>";
366
- runtime_setup.Options["Arguments"] = args;
367
- runtime_setup.HostType = typeof(IRHost);
368
- runtime_setup.HostArguments = new object[] { package };
369
- var engine = IronRuby.Ruby.GetEngine(IronRuby.Ruby.CreateRuntime(runtime_setup));
370
- try {
371
- engine.ExecuteFile("<%= entry_file %>");
372
- return 0;
373
- }
374
- catch (IronRuby.Builtins.SystemExit e) {
375
- return e.Status;
376
- }
377
- }
378
- }
379
- }
380
- CS
381
- module_function
382
- def bootloader_source(module_name, package_file, preload_assemblies)
383
- ERB.new(BootLoaderSource).result(binding)
384
- end
385
-
386
- def entrypoint_source(module_name, entry_file)
387
- ERB.new(EntryPointSource).result(binding)
388
- end
389
- end
390
-
391
- module IRPack
392
- module Packager
393
- include System
394
- include System::IO::Packaging
395
-
396
- RelType = 'http://schemas.openxmlformats.org/package/2006/relationships/meta data/core-properties'
397
- module_function
398
- def pack(files, package_file, compress=false)
399
- compress_option = compress ? CompressionOption.normal : CompressionOption.not_compressed
400
- package = Package.open(package_file, System::IO::FileMode.create)
401
- files.each do |src, dest|
402
- uri = PackUriHelper.create_part_uri(Uri.new(dest, UriKind.relative))
403
- part = package.create_part(uri, 'application/octet-stream', compress_option)
404
- stream = part.get_stream
405
- File.open(src, 'rb') do |f|
406
- data = f.read
407
- stream.write(data, 0, data.size)
408
- end
409
- stream.close
410
- package.create_relationship(uri, TargetMode.internal, RelType)
411
- end
412
- package.close
413
- end
414
-
415
- def pack_dir(dir_name, package_file)
416
- files = {}
417
- base = Pathname.new(dir_name)
418
- Dir.glob(base.join('**', '*')) do |fn|
419
- files[fn] = Pathname.new(fn).relative_path_from(base)
420
- end
421
- pack(files, package_file)
422
- end
423
- end
424
-
425
- AssemblyPath = ::File.dirname(Assembly.get_entry_assembly.location.to_s)
426
- PreloadAssemblies = %w[
427
- Microsoft.Dynamic.dll
428
- Microsoft.Scripting.dll
429
- Microsoft.Scripting.Core.dll
430
- IronRuby.dll
431
- IronRuby.Libraries.dll
432
- IronRuby.Libraries.Yaml.dll
32
+ IronRubyAssemblies = %w[
33
+ Microsoft.Dynamic
34
+ Microsoft.Scripting
35
+ Microsoft.Scripting.Core
36
+ IronRuby
37
+ IronRuby.Libraries
38
+ IronRuby.Libraries.Yaml
433
39
  ]
434
40
 
435
41
  module_function
436
42
  def path_to_module_name(filename)
437
43
  name = File.basename(filename, '.*')
438
44
  name.gsub!(/[^A-Za-z0-9_]/, '_')
439
- /^[A-Za-z]/=~name ? name : ('M'+name)
45
+ (/^[A-Za-z]/=~name ? name : ('M'+name)).upcase
46
+ end
47
+
48
+ def ironruby_assemblies
49
+ IronRubyAssemblies.each do |name|
50
+ begin
51
+ load_assembly name
52
+ rescue LoadError
53
+ end
54
+ end
55
+ System::AppDomain.current_domain.get_assemblies.select {|asm|
56
+ IronRubyAssemblies.include?(asm.get_name.name)
57
+ }.collect {|asm| asm.location }
440
58
  end
441
59
 
442
- def pack(files, entry_file, output_file, options={})
443
- preload_assemblies = PreloadAssemblies.collect {|fn|
444
- File.join(AssemblyPath, fn)
445
- }.select {|fn|
446
- File.exist?(fn)
447
- }
60
+ def pack(output_file, files, entry_file, opts={})
61
+ opts = {
62
+ :target => :exe,
63
+ :compress => false,
64
+ :embed_references => true,
65
+ :module_name => path_to_module_name(output_file)
66
+ }.update(opts)
448
67
  basename = File.basename(output_file, '.*')
449
- module_name = path_to_module_name(output_file)
450
- resources = options[:resources] || []
451
- target = options[:target] || :exe
452
- stdlib = options.include?(:stdlib) ? options[:stdlib] : true
453
- compress = options.include?(:compress) ? options[:compress] : false
454
- pack_files = files.dup
68
+ module_name = opts[:module_name]
69
+ target = opts[:target]
70
+ references = opts[:references] || ironruby_assemblies
71
+ compress = opts[:compress]
72
+ pack_files = {}.merge(files)
73
+ if opts[:embed_references] then
74
+ references.each do |asm|
75
+ pack_files[asm] = File.basename(asm)
76
+ end
77
+ end
455
78
 
456
79
  Dir.mktmpdir(File.basename($0,'.*')) do |tmp_path|
457
- entry_src = entrypoint_source(module_name, entry_file)
458
80
  entry_dll = File.join(tmp_path, module_name+'.EntryPoint.dll')
459
- CSCompiler.compile(:dll, entry_src, preload_assemblies, [], entry_dll)
81
+ EntryPoint.compile(entry_dll, module_name, entry_file, references)
460
82
  pack_files[entry_dll] = File.basename(entry_dll)
461
- if stdlib then
462
- preload_assemblies.each do |asm|
463
- pack_files[asm] = File.basename(asm)
464
- end
465
- end
83
+
466
84
  package_file = File.join(tmp_path, basename+'.pkg')
467
85
  Packager.pack(pack_files, package_file, compress)
468
86
 
469
- target_src = bootloader_source(
470
- module_name,
471
- File.basename(package_file),
472
- preload_assemblies.collect {|fn| File.basename(fn) }
473
- )
474
- Dir.chdir(tmp_path) do
475
- CSCompiler.compile(target, target_src, [], [File.basename(package_file)], output_file)
476
- end
477
- end
478
- end
479
-
480
- def pack_dir(pack_dir, entry_file, output_file, options={})
481
- output_file = File.expand_path(output_file)
482
- entry_packed = nil
483
- pack_files = {}
484
- resources = []
485
- base = Pathname.new(pack_dir).expand_path
486
- Dir.glob(base.join('**', '*')) do |fn|
487
- path = Pathname.new(File.expand_path(fn))
488
- next if path==output_file
489
- relpath = path.relative_path_from(base)
490
- pack_files[path] = relpath
491
- if not entry_packed and
492
- (path.to_s==File.expand_path(entry_file) or
493
- path.basename.to_s==entry_file or
494
- relpath.to_s==entry_file) then
495
- entry_packed = relpath
496
- end
497
- resources << path.to_s if path.extname=='.ico'
87
+ BootLoader.compile(target, output_file, module_name, references, package_file)
498
88
  end
499
- raise ArgumentError, "Entry file `#{entry_file}' is not in packed directory."unless entry_packed
500
- options = options.merge(:resources => resources)
501
- pack(pack_files, entry_packed, output_file, options)
89
+ output_file
502
90
  end
503
91
  end
504
92