puppet-module 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. data/CHANGES.markdown +91 -0
  2. data/LICENSE +17 -0
  3. data/README.markdown +221 -0
  4. data/Rakefile +87 -0
  5. data/VERSION +1 -0
  6. data/bin/puppet-module +7 -0
  7. data/lib/puppet/module/tool.rb +124 -0
  8. data/lib/puppet/module/tool/applications.rb +18 -0
  9. data/lib/puppet/module/tool/applications/application.rb +83 -0
  10. data/lib/puppet/module/tool/applications/builder.rb +88 -0
  11. data/lib/puppet/module/tool/applications/checksummer.rb +38 -0
  12. data/lib/puppet/module/tool/applications/cleaner.rb +14 -0
  13. data/lib/puppet/module/tool/applications/freezer.rb +20 -0
  14. data/lib/puppet/module/tool/applications/generator.rb +117 -0
  15. data/lib/puppet/module/tool/applications/installer.rb +83 -0
  16. data/lib/puppet/module/tool/applications/registrar.rb +34 -0
  17. data/lib/puppet/module/tool/applications/releaser.rb +48 -0
  18. data/lib/puppet/module/tool/applications/searcher.rb +34 -0
  19. data/lib/puppet/module/tool/applications/unpacker.rb +69 -0
  20. data/lib/puppet/module/tool/applications/unreleaser.rb +42 -0
  21. data/lib/puppet/module/tool/cache.rb +56 -0
  22. data/lib/puppet/module/tool/checksums.rb +52 -0
  23. data/lib/puppet/module/tool/cli.rb +127 -0
  24. data/lib/puppet/module/tool/contents_description.rb +84 -0
  25. data/lib/puppet/module/tool/dependency.rb +26 -0
  26. data/lib/puppet/module/tool/metadata.rb +80 -0
  27. data/lib/puppet/module/tool/modulefile.rb +47 -0
  28. data/lib/puppet/module/tool/repository.rb +74 -0
  29. data/lib/puppet/module/tool/skeleton.rb +39 -0
  30. data/lib/puppet/module/tool/utils.rb +9 -0
  31. data/lib/puppet/module/tool/utils/interrogation.rb +39 -0
  32. data/lib/puppet/module/tool/utils/settings.rb +36 -0
  33. data/lib/puppet/module/tool/utils/uri.rb +16 -0
  34. data/spec/fixtures/releases/jamtur01-apache/Modulefile +2 -0
  35. data/spec/fixtures/releases/jamtur01-apache/files/httpd +24 -0
  36. data/spec/fixtures/releases/jamtur01-apache/files/test.vhost +18 -0
  37. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb +21 -0
  38. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb +12 -0
  39. data/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp +5 -0
  40. data/spec/fixtures/releases/jamtur01-apache/manifests/init.pp +34 -0
  41. data/spec/fixtures/releases/jamtur01-apache/manifests/params.pp +17 -0
  42. data/spec/fixtures/releases/jamtur01-apache/manifests/php.pp +5 -0
  43. data/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp +15 -0
  44. data/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp +15 -0
  45. data/spec/fixtures/releases/jamtur01-apache/metadata.json +1 -0
  46. data/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb +20 -0
  47. data/spec/fixtures/releases/jamtur01-apache/tests/apache.pp +1 -0
  48. data/spec/fixtures/releases/jamtur01-apache/tests/dev.pp +1 -0
  49. data/spec/fixtures/releases/jamtur01-apache/tests/init.pp +1 -0
  50. data/spec/fixtures/releases/jamtur01-apache/tests/php.pp +1 -0
  51. data/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp +1 -0
  52. data/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp +2 -0
  53. data/spec/integration/cli_spec.rb +373 -0
  54. data/spec/spec.opts +1 -0
  55. data/spec/spec_helper.rb +15 -0
  56. data/spec/support/output_support.rb +19 -0
  57. data/spec/support/stub_http_support.rb +14 -0
  58. data/spec/support/testdir_support.rb +26 -0
  59. data/spec/unit/application_spec.rb +25 -0
  60. data/spec/unit/repository_spec.rb +51 -0
  61. data/templates/generator/Modulefile.erb +5 -0
  62. data/templates/generator/README.erb +3 -0
  63. data/templates/generator/files/README.markdown +22 -0
  64. data/templates/generator/lib/puppet/facter/README.markdown +22 -0
  65. data/templates/generator/lib/puppet/parser/functions/README.markdown +17 -0
  66. data/templates/generator/lib/puppet/provider/README.markdown +14 -0
  67. data/templates/generator/lib/puppet/type/README.markdown +14 -0
  68. data/templates/generator/manifests/README.markdown +28 -0
  69. data/templates/generator/manifests/init.pp.erb +17 -0
  70. data/templates/generator/metadata.json +12 -0
  71. data/templates/generator/spec/README.markdown +7 -0
  72. data/templates/generator/spec/spec.opts +6 -0
  73. data/templates/generator/spec/spec_helper.rb +18 -0
  74. data/templates/generator/spec/unit/puppet/provider/README.markdown +4 -0
  75. data/templates/generator/spec/unit/puppet/type/README.markdown +4 -0
  76. data/templates/generator/templates/README.markdown +23 -0
  77. data/templates/generator/tests/init.pp.erb +1 -0
  78. data/vendor/facets-2.8.2-partial/lib/facets/kernel/returning.rb +23 -0
  79. data/vendor/facets-2.8.2-partial/lib/facets/kernel/tap.rb +39 -0
  80. data/vendor/multipart-post-1.0/Manifest.txt +9 -0
  81. data/vendor/multipart-post-1.0/README.txt +61 -0
  82. data/vendor/multipart-post-1.0/Rakefile +21 -0
  83. data/vendor/multipart-post-1.0/lib/composite_io.rb +89 -0
  84. data/vendor/multipart-post-1.0/lib/multipartable.rb +13 -0
  85. data/vendor/multipart-post-1.0/lib/net/http/post/multipart.rb +27 -0
  86. data/vendor/multipart-post-1.0/lib/parts.rb +66 -0
  87. data/vendor/multipart-post-1.0/test/net/http/post/test_multipart.rb +55 -0
  88. data/vendor/multipart-post-1.0/test/test_composite_io.rb +50 -0
  89. data/vendor/thor-852190ae/CHANGELOG.rdoc +89 -0
  90. data/vendor/thor-852190ae/LICENSE +20 -0
  91. data/vendor/thor-852190ae/README.rdoc +297 -0
  92. data/vendor/thor-852190ae/REVISION +1 -0
  93. data/vendor/thor-852190ae/Thorfile +69 -0
  94. data/vendor/thor-852190ae/bin/rake2thor +86 -0
  95. data/vendor/thor-852190ae/bin/thor +6 -0
  96. data/vendor/thor-852190ae/lib/thor.rb +244 -0
  97. data/vendor/thor-852190ae/lib/thor/actions.rb +275 -0
  98. data/vendor/thor-852190ae/lib/thor/actions/create_file.rb +103 -0
  99. data/vendor/thor-852190ae/lib/thor/actions/directory.rb +91 -0
  100. data/vendor/thor-852190ae/lib/thor/actions/empty_directory.rb +134 -0
  101. data/vendor/thor-852190ae/lib/thor/actions/file_manipulation.rb +223 -0
  102. data/vendor/thor-852190ae/lib/thor/actions/inject_into_file.rb +104 -0
  103. data/vendor/thor-852190ae/lib/thor/base.rb +540 -0
  104. data/vendor/thor-852190ae/lib/thor/core_ext/file_binary_read.rb +9 -0
  105. data/vendor/thor-852190ae/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  106. data/vendor/thor-852190ae/lib/thor/core_ext/ordered_hash.rb +100 -0
  107. data/vendor/thor-852190ae/lib/thor/error.rb +30 -0
  108. data/vendor/thor-852190ae/lib/thor/group.rb +271 -0
  109. data/vendor/thor-852190ae/lib/thor/invocation.rb +180 -0
  110. data/vendor/thor-852190ae/lib/thor/parser.rb +4 -0
  111. data/vendor/thor-852190ae/lib/thor/parser/argument.rb +67 -0
  112. data/vendor/thor-852190ae/lib/thor/parser/arguments.rb +150 -0
  113. data/vendor/thor-852190ae/lib/thor/parser/option.rb +128 -0
  114. data/vendor/thor-852190ae/lib/thor/parser/options.rb +169 -0
  115. data/vendor/thor-852190ae/lib/thor/rake_compat.rb +66 -0
  116. data/vendor/thor-852190ae/lib/thor/runner.rb +314 -0
  117. data/vendor/thor-852190ae/lib/thor/shell.rb +83 -0
  118. data/vendor/thor-852190ae/lib/thor/shell/basic.rb +239 -0
  119. data/vendor/thor-852190ae/lib/thor/shell/color.rb +108 -0
  120. data/vendor/thor-852190ae/lib/thor/task.rb +102 -0
  121. data/vendor/thor-852190ae/lib/thor/util.rb +230 -0
  122. data/vendor/thor-852190ae/lib/thor/version.rb +3 -0
  123. data/vendor/thor-852190ae/spec/actions/create_file_spec.rb +170 -0
  124. data/vendor/thor-852190ae/spec/actions/directory_spec.rb +131 -0
  125. data/vendor/thor-852190ae/spec/actions/empty_directory_spec.rb +91 -0
  126. data/vendor/thor-852190ae/spec/actions/file_manipulation_spec.rb +271 -0
  127. data/vendor/thor-852190ae/spec/actions/inject_into_file_spec.rb +135 -0
  128. data/vendor/thor-852190ae/spec/actions_spec.rb +292 -0
  129. data/vendor/thor-852190ae/spec/base_spec.rb +263 -0
  130. data/vendor/thor-852190ae/spec/core_ext/hash_with_indifferent_access_spec.rb +43 -0
  131. data/vendor/thor-852190ae/spec/core_ext/ordered_hash_spec.rb +115 -0
  132. data/vendor/thor-852190ae/spec/fixtures/application.rb +2 -0
  133. data/vendor/thor-852190ae/spec/fixtures/bundle/execute.rb +6 -0
  134. data/vendor/thor-852190ae/spec/fixtures/bundle/main.thor +1 -0
  135. data/vendor/thor-852190ae/spec/fixtures/doc/%file_name%.rb.tt +1 -0
  136. data/vendor/thor-852190ae/spec/fixtures/doc/README +3 -0
  137. data/vendor/thor-852190ae/spec/fixtures/doc/config.rb +1 -0
  138. data/vendor/thor-852190ae/spec/fixtures/group.thor +83 -0
  139. data/vendor/thor-852190ae/spec/fixtures/invoke.thor +112 -0
  140. data/vendor/thor-852190ae/spec/fixtures/script.thor +140 -0
  141. data/vendor/thor-852190ae/spec/fixtures/task.thor +10 -0
  142. data/vendor/thor-852190ae/spec/group_spec.rb +171 -0
  143. data/vendor/thor-852190ae/spec/invocation_spec.rb +107 -0
  144. data/vendor/thor-852190ae/spec/parser/argument_spec.rb +47 -0
  145. data/vendor/thor-852190ae/spec/parser/arguments_spec.rb +64 -0
  146. data/vendor/thor-852190ae/spec/parser/option_spec.rb +202 -0
  147. data/vendor/thor-852190ae/spec/parser/options_spec.rb +292 -0
  148. data/vendor/thor-852190ae/spec/rake_compat_spec.rb +68 -0
  149. data/vendor/thor-852190ae/spec/runner_spec.rb +202 -0
  150. data/vendor/thor-852190ae/spec/shell/basic_spec.rb +205 -0
  151. data/vendor/thor-852190ae/spec/shell/color_spec.rb +41 -0
  152. data/vendor/thor-852190ae/spec/shell_spec.rb +34 -0
  153. data/vendor/thor-852190ae/spec/spec.opts +1 -0
  154. data/vendor/thor-852190ae/spec/spec_helper.rb +54 -0
  155. data/vendor/thor-852190ae/spec/task_spec.rb +69 -0
  156. data/vendor/thor-852190ae/spec/thor_spec.rb +237 -0
  157. data/vendor/thor-852190ae/spec/util_spec.rb +167 -0
  158. data/vendor/thor-852190ae/thor.gemspec +120 -0
  159. metadata +229 -0
@@ -0,0 +1,18 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+
4
+ require 'puppet/module/tool/applications/application'
5
+ require 'puppet/module/tool/applications/builder'
6
+ require 'puppet/module/tool/applications/checksummer'
7
+ require 'puppet/module/tool/applications/cleaner'
8
+ require 'puppet/module/tool/applications/freezer'
9
+ require 'puppet/module/tool/applications/generator'
10
+ require 'puppet/module/tool/applications/installer'
11
+ require 'puppet/module/tool/applications/registrar'
12
+ require 'puppet/module/tool/applications/releaser'
13
+ require 'puppet/module/tool/applications/searcher'
14
+ require 'puppet/module/tool/applications/unpacker'
15
+ require 'puppet/module/tool/applications/unreleaser'
16
+
17
+ end
18
+ end
@@ -0,0 +1,83 @@
1
+ require 'net/http'
2
+
3
+ module Puppet::Module::Tool
4
+ module Applications
5
+
6
+ class Application
7
+ include Utils::Interrogation
8
+
9
+ def self.run(*args)
10
+ new(*args).run
11
+ end
12
+
13
+ attr_accessor :options
14
+
15
+ def initialize(options = {})
16
+ @options = options
17
+ Puppet::Module::Tool.prepare_settings(options)
18
+ end
19
+
20
+ def repository
21
+ @repository ||= Repository.new(Puppet.settings[:puppet_module_repository])
22
+ end
23
+
24
+ def run
25
+ raise NotImplementedError, "Should be implemented in child classes."
26
+ end
27
+
28
+ def discuss(response, success, failure)
29
+ case response
30
+ when Net::HTTPOK, Net::HTTPCreated
31
+ say success
32
+ else
33
+ errors = PSON.parse(response.body)['error'] rescue "HTTP #{response.code}, #{response.body}"
34
+ say "#{failure} (#{errors})"
35
+ end
36
+ end
37
+
38
+ def metadata(require_modulefile = false)
39
+ unless @metadata
40
+ unless @path
41
+ abort "Could not determine module path"
42
+ end
43
+ @metadata = Metadata.new
44
+ contents = ContentsDescription.new(@path)
45
+ contents.annotate(@metadata)
46
+ checksums = Checksums.new(@path)
47
+ checksums.annotate(@metadata)
48
+ modulefile_path = File.join(@path, 'Modulefile')
49
+ if File.file?(modulefile_path)
50
+ Modulefile.evaluate(@metadata, modulefile_path)
51
+ elsif require_modulefile
52
+ abort "No Modulefile found."
53
+ end
54
+ end
55
+ @metadata
56
+ end
57
+
58
+ def load_modulefile!
59
+ @metadata = nil
60
+ metadata(true)
61
+ end
62
+
63
+ # Use to extract and validate a module name and version from a
64
+ #filename
65
+ # Note: Must have @filename set to use this
66
+ def parse_filename!
67
+ @release_name = File.basename(@filename,'.tar.gz')
68
+ @username, @module_name, @version = @release_name.split('-', 3)
69
+ @full_name = [@username, @module_name].join('-')
70
+ unless @username && @module_name
71
+ abort "Username and Module name not provided"
72
+ end
73
+ begin
74
+ Gem::Version.new(@version)
75
+ rescue ArgumentError => e
76
+ abort "Invalid version format: #{@version}"
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end
@@ -0,0 +1,88 @@
1
+ require 'fileutils'
2
+
3
+ module Puppet::Module::Tool
4
+
5
+ module Applications
6
+
7
+ class Builder < Application
8
+
9
+ def initialize(path, options)
10
+ @path = File.expand_path(path)
11
+ @pkg_path = File.join(@path, 'pkg')
12
+ super(options)
13
+ end
14
+
15
+ def run
16
+ load_modulefile!
17
+ create_directory
18
+ copy_contents
19
+ add_metadata
20
+ header "Building #{@path} for release"
21
+ tar
22
+ gzip
23
+ relative = Pathname.new(File.join(@pkg_path, filename('tar.gz'))).relative_path_from(Pathname.new(Dir.pwd))
24
+ # TODO Implement "release" feature.
25
+ ### say "Done. Now you probably want to:\n $ puppet-module release #{relative}"
26
+ say "Done. Built: #{relative}"
27
+ end
28
+
29
+ private
30
+
31
+ def filename(ext)
32
+ ext.sub!(/^\./, '')
33
+ "#{metadata.release_name}.#{ext}"
34
+ end
35
+
36
+ def tar
37
+ tar_name = filename('tar')
38
+ Dir.chdir(@pkg_path) do
39
+ FileUtils.rm tar_name rescue nil
40
+ unless system "tar -cf #{tar_name} #{metadata.release_name}"
41
+ abort "Could not create #{tar_name}"
42
+ end
43
+ end
44
+ end
45
+
46
+ def gzip
47
+ Dir.chdir(@pkg_path) do
48
+ FileUtils.rm filename('tar.gz') rescue nil
49
+ unless system "gzip #{filename('tar')}"
50
+ abort "Could not compress #{filename('tar')}"
51
+ end
52
+ end
53
+ end
54
+
55
+ def create_directory
56
+ FileUtils.mkdir(@pkg_path) rescue nil
57
+ if File.directory?(build_path)
58
+ FileUtils.rm_rf(build_path)
59
+ end
60
+ FileUtils.mkdir(build_path)
61
+ end
62
+
63
+ def copy_contents
64
+ Dir[File.join(@path, '*')].each do |path|
65
+ case File.basename(path)
66
+ when *Puppet::Module::Tool::ARTIFACTS
67
+ next
68
+ else
69
+ FileUtils.cp_r path, build_path
70
+ end
71
+ end
72
+ end
73
+
74
+ def add_metadata
75
+ File.open(File.join(build_path, 'metadata.json'), 'w') do |f|
76
+ f.write(PSON.pretty_generate(metadata))
77
+ end
78
+ end
79
+
80
+ def build_path
81
+ @build_path ||= File.join(@pkg_path, metadata.release_name)
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,38 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+
4
+ class Checksummer < Application
5
+
6
+ def initialize(path, options = {})
7
+ @path = Pathname.new(path)
8
+ super(options)
9
+ end
10
+
11
+ def run
12
+ if metadata_file.exist?
13
+ sums = Checksums.new(@path)
14
+ (metadata['checksums'] || {}).each do |child_path, canonical_checksum|
15
+ path = @path + child_path
16
+ if canonical_checksum != sums.checksum(path)
17
+ say child_path
18
+ end
19
+ end
20
+ else
21
+ abort "No metadata.json found."
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def metadata
28
+ PSON.parse(metadata_file.read)
29
+ end
30
+
31
+ def metadata_file
32
+ (@path + 'metadata.json')
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,14 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+
4
+ class Cleaner < Application
5
+
6
+ def run
7
+ Puppet::Module::Tool::Cache.clean
8
+ puts "Cleaned module cache."
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+
4
+ class Freezer < Application
5
+ # TODO Review whether the 'freeze' feature should be fixed or deleted.
6
+ =begin
7
+ def skeleton
8
+ @skeleton ||= Skeleton.new
9
+ end
10
+
11
+ def run
12
+ header "Freezing in #{skeleton.custom_path}"
13
+ skeleton.freeze!
14
+ say "Done. Modify these files for the `generate` task."
15
+ end
16
+ =end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,117 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module Puppet::Module::Tool
6
+ module Applications
7
+
8
+ class Generator < Application
9
+
10
+ def initialize(full_name, options)
11
+ begin
12
+ @metadata = Metadata.new(:full_name => full_name)
13
+ rescue ArgumentError
14
+ abort "Could not generate directory #{full_name.inspect}, you must specify a dash-separated username and module name."
15
+ end
16
+ super(options)
17
+ end
18
+
19
+ def skeleton
20
+ @skeleton ||= Skeleton.new
21
+ end
22
+
23
+ def run
24
+ if destination.directory?
25
+ abort "#{destination} already exists."
26
+ end
27
+ header "Generating module at #{Dir.pwd}/#{@metadata.dashed_name}"
28
+ skeleton.path.find do |path|
29
+ if path == skeleton
30
+ destination.mkpath
31
+ else
32
+ node = Node.on(path, self)
33
+ if node
34
+ node.install!
35
+ say node.target
36
+ else
37
+ say "Could not generate from #{path}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def destination
44
+ @destination ||= Pathname.new(@metadata.dashed_name)
45
+ end
46
+
47
+ class Node
48
+ def self.types
49
+ @types ||= []
50
+ end
51
+ def self.inherited(klass)
52
+ types << klass
53
+ end
54
+ def self.on(path, generator)
55
+ klass = types.detect { |t| t.matches?(path) }
56
+ if klass
57
+ klass.new(path, generator)
58
+ end
59
+ end
60
+ def initialize(source, generator)
61
+ @generator = generator
62
+ @source = source
63
+ end
64
+ def read
65
+ @source.read
66
+ end
67
+ def target
68
+ target = @generator.destination + @source.relative_path_from(@generator.skeleton.path)
69
+ components = target.to_s.split(File::SEPARATOR).map do |part|
70
+ part == 'NAME' ? @generator.metadata.name : part
71
+ end
72
+ Pathname.new(components.join(File::SEPARATOR))
73
+ end
74
+ def install!
75
+ raise NotImplementedError, "Abstract"
76
+ end
77
+ end
78
+
79
+ class DirectoryNode < Node
80
+ def self.matches?(path)
81
+ path.directory?
82
+ end
83
+ def install!
84
+ target.mkpath
85
+ end
86
+ end
87
+
88
+ class ParsedFileNode < Node
89
+ def self.matches?(path)
90
+ path.file? && path.extname == '.erb'
91
+ end
92
+ def target
93
+ path = super
94
+ path.parent + path.basename('.erb')
95
+ end
96
+ def contents
97
+ template = ERB.new(read)
98
+ template.result(@generator.send(:binding))
99
+ end
100
+ def install!
101
+ target.open('w') { |f| f.write contents }
102
+ end
103
+ end
104
+
105
+ class FileNode < Node
106
+ def self.matches?(path)
107
+ path.file?
108
+ end
109
+ def install!
110
+ FileUtils.cp(@source, target)
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+ end
@@ -0,0 +1,83 @@
1
+ require 'open-uri'
2
+ require 'pathname'
3
+ require 'tmpdir'
4
+
5
+ module Puppet::Module::Tool
6
+
7
+ module Applications
8
+
9
+ class Installer < Application
10
+
11
+ def initialize(name, options = {})
12
+ if File.exist?(name)
13
+ if File.directory?(name)
14
+ # TODO Unify this handling with that of Unpacker#check_clobber!
15
+ abort "Module already installed: #{name}"
16
+ end
17
+ @source = :filesystem
18
+ @filename = File.expand_path(name)
19
+ parse_filename!
20
+ else
21
+ @source = :repository
22
+ begin
23
+ @username, @module_name = Puppet::Module::Tool::username_and_modname_from(name)
24
+ rescue ArgumentError
25
+ abort "Could not install module with invalid name: #{name}"
26
+ end
27
+ @version_requirement = options[:version]
28
+ end
29
+ super(options)
30
+ end
31
+
32
+ def force?
33
+ options[:force]
34
+ end
35
+
36
+ def run
37
+ case @source
38
+ when :repository
39
+ if match['file']
40
+ begin
41
+ cache_path = repository.retrieve(match['file'])
42
+ rescue OpenURI::HTTPError => e
43
+ abort "Could not install module: #{e.message}"
44
+ end
45
+ Unpacker.run(cache_path, Dir.pwd, options)
46
+ else
47
+ abort "Malformed response from module repository."
48
+ end
49
+ when :filesystem
50
+ repository = Repository.new('file:///')
51
+ uri = URI.parse("file://#{File.expand_path(@filename)}")
52
+ cache_path = repository.retrieve(uri)
53
+ Unpacker.run(cache_path, Dir.pwd, options)
54
+ else
55
+ abort "Could not determine installation source"
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def match
62
+ return @match ||= begin
63
+ url = repository.uri + "/users/#{@username}/modules/#{@module_name}/releases/find.json"
64
+ if @version_requirement
65
+ url.query = "version=#{URI.escape(@version_requirement)}"
66
+ end
67
+ begin
68
+ raw_result = read_match(url)
69
+ rescue => e
70
+ abort "Could not request version match (#{e.message})"
71
+ end
72
+ @match = PSON.parse(raw_result)
73
+ end
74
+ end
75
+
76
+ def read_match(url)
77
+ return url.read
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end