puppet-module 0.3.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.
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