rubygems_snapshot 0.1.3 → 0.2.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.
data/README.textile CHANGED
@@ -1,25 +1,79 @@
1
- h1. rubygems_snapshot
1
+ h1. Snapshot: A Rubygems plugin
2
2
 
3
- Adds snapshot command to gem. This command allow import/export gems.
3
+ *Export and Import* your gems.
4
+ Snapshot, copy your current gems in a single file, providing a fast and secure way to import your gems anywhere.
4
5
 
5
- h2. Description
6
+ Tested with:
7
+ * ruby-1.8.6-p399 [ i386 ]
8
+ * ruby-1.8.7-p249 [ i386 ]
9
+ * 1.3.6 gem version
6
10
 
7
- This gem is a plugin for rubygems.
8
- Based on ["Import/Export Patch":http://rubyforge.org/tracker/?atid=577&group_id=126&func=browse] from ["Peer Allan":http://rubyforge.org/users/pallan].
11
+ Version 1 was based on ["Import/Export Patch":http://rubyforge.org/tracker/?atid=577&group_id=126&func=browse] from ["Peer Allan":http://rubyforge.org/users/pallan].
9
12
 
10
13
  h2. Install/Usage
11
14
 
12
15
  @gem install rubygems_snapshot@
13
- Hosted at ["Gemcutter":http://gemcutter.org/gems/rubygems_snapshot]
14
16
 
15
17
  After install, you can use:
16
18
 
17
- @gem snapshot export result_file.yml@ to export your gems
19
+ @gem snapshot export gems.tar@ to export your gems
18
20
 
19
- @gem snapshot import file_exported.yml@ to import (install) gems.
21
+ @gem snapshot import gems.tar@ to import (install) gems.
20
22
 
21
- *Important*: When importing, don't forget to use sudo if necessary.
22
- *Important(2)*: When importing, pay attention to errors relative to native build. I don't know how to deal with that. :X
23
+ *Important*: When importing, don't forget to use sudo if necessary *and* pay attention to errors relative to native build.
24
+ I don't know how to deal with that yet! :X
25
+ *Hosted* at ["Gemcutter":http://gemcutter.org/gems/rubygems_snapshot]
26
+
27
+ h3. Others formats
28
+
29
+ Nowadays, it supports two formats:
30
+ * tar (default)
31
+ * yml
32
+
33
+ You can chose the format, using -f parameter. For example:
34
+
35
+ @gem snapshot export gems.yml -f yml@
36
+ @gem snapshot import gems.yml -f yml@
37
+
38
+ For aditional help, execute:
39
+ @gem help snapshot@
40
+
41
+ h3. How it Works?
42
+
43
+ It's very simple.
44
+ *When exporting*, get all gems (like "gem list"), puts in a yml file.
45
+ If gem file exists at cache folder from rubygems, copy to tar file too. (tar format)
46
+
47
+ *When importing*, copy all gems to rubygems cache folder.
48
+ Read the yml file, install the gem file from cache folder or do a simple "gem install" if gem file does not exists.
49
+
50
+ h2. For Developers
51
+
52
+ h3. Using as API
53
+
54
+ <pre>
55
+ require "rubygems"
56
+ GemsSnapshot::Exporter.export("example.tar", :format => :tar)
57
+ </pre>
58
+
59
+ --
60
+
61
+ <pre>
62
+ require "rubygems"
63
+ GemsSnapshot::Importer.import("example.tar", :format => :tar)
64
+ </pre>
65
+
66
+
67
+ h3. Use the sources Luke!
68
+
69
+ If you want help to improve Snapshot, after git clone, you'll need the following gems:
70
+ * rake
71
+ * rspec
72
+ * cucumber
73
+
74
+ Use "rake -T" to see the available tasks.
75
+ I highly recomend using ["RVM":http://rvm.beginrescueend.com/] during development.
76
+ Anything, questions, suggestions etc., send me message or leave a issue.
23
77
 
24
78
  h2. License
25
79
 
@@ -1,17 +1,24 @@
1
1
  require 'rubygems/command'
2
- require 'yaml'
3
2
 
4
3
  class Gem::Commands::SnapshotCommand < Gem::Command
5
4
 
6
5
  def initialize
7
- super 'snapshot', 'Export/Import your installed gems'
6
+ super 'snapshot', 'Export/Import your gems.', :format => "tar"
7
+
8
+ add_option('-f', '--format FORMAT', 'Snapshot format. Default is "tar". Can be "yml" too.') do |value, options|
9
+ options[:format] = value
10
+ end
11
+
12
+ end
13
+
14
+ def defaults_str # :nodoc:
15
+ '--format "tar"'
8
16
  end
9
17
 
10
18
  def arguments # :nodoc:
11
19
  args = <<-EOF
12
- export export your installed gems to yml file
13
- import install allgems from yml file
14
- filename yml file used to export/import actions
20
+ ACTION 'export' or 'import' as action arguments
21
+ FILENAME file used to export/import actions
15
22
  EOF
16
23
  return args.gsub(/^\s+/, '')
17
24
  end
@@ -19,111 +26,51 @@ class Gem::Commands::SnapshotCommand < Gem::Command
19
26
  def description # :nodoc:
20
27
  <<-EOF
21
28
  Describe here what snapshot does.
29
+ Updated description at: http://github.com/rogerleite/rubygems_snapshot
22
30
  EOF
23
31
  end
24
32
 
25
33
  def usage # :nodoc:
26
- "#{program_name} action(export|import) filename"
34
+ "#{program_name} ACTION(export|import) FILENAME"
27
35
  end
28
36
 
29
37
  def execute
30
- action, filename = get_and_check_arguments(options[:args])
38
+ action, filename = extract_action(options[:args])
39
+ validate_options(options_without_args)
31
40
 
32
41
  if action == "export"
33
- export(action, filename)
42
+ export(filename)
34
43
  else
35
- import(action, filename)
44
+ import(filename)
36
45
  end
37
46
  end
38
47
 
39
48
  private
40
49
 
41
- def import(action, filename)
42
- #TODO: check if is a valid yml file
43
-
44
- require 'rubygems/dependency_installer'
45
-
46
- main_hash = nil
47
- File.open(filename, "r") do |file|
48
- main_hash = YAML.load(file)
49
- end
50
-
51
- main_hash['sources'].each do |source|
52
- Gem.sources << source unless Gem.sources.include?(source)
53
- end
54
-
55
- options = Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
56
- :generate_rdoc => true,
57
- :generate_ri => true,
58
- :format_executable => false,
59
- :test => false,
60
- :version => Gem::Requirement.default,
61
- #aditional default parameters
62
- :ignore_dependencies => true,
63
- :verbose => true
64
- })
65
-
66
- main_hash['gems'].each do |hash_gem|
67
- gem_name = hash_gem['name']
68
- hash_gem['versions'].each do |version|
69
-
70
- say "Going to install #{gem_name} -v#{version} ... wish me luck!"
71
- begin
72
- gem_install(options, gem_name, version)
73
-
74
- rescue Gem::InstallError => e
75
- alert_error("Error installing #{gem_name}:\n\t#{e.message}")
76
- rescue Gem::GemNotFoundException => e
77
- alert_error(e.message)
78
- end
79
-
80
- end
81
- end
82
-
50
+ def import(filename)
51
+ GemsSnapshot::Importer.import(filename, options_without_args)
52
+ say "Gems imported successfully."
83
53
  end
84
54
 
85
- def gem_install(options, gem_name, version)
86
- inst = Gem::DependencyInstaller.new(options)
87
- inst.install(gem_name, version)
88
-
89
- inst.installed_gems.each do |spec|
90
- say "Successfully installed #{spec.full_name}"
91
- end
55
+ def export(filename)
56
+ say "Say CHEESE to snapshot! :P"
57
+ filename = GemsSnapshot::Exporter.export(filename, options_without_args)
58
+ say "Gems exported to #{filename} successfully."
92
59
  end
93
60
 
94
- def list_installed_gems
95
- name = /^/i #get all local gems
96
- dep = Gem::Dependency.new(name, Gem::Requirement.default)
97
- specs = Gem.source_index.search(dep)
61
+ def options_without_args
62
+ options.reject { |key, value| key == :args }
98
63
  end
99
64
 
100
- def export(action, filename)
101
- say "Say CHEESE to snapshot! :P"
102
-
103
- specs = list_installed_gems
104
-
105
- hash_specs = {}
106
- specs.each do |spec|
107
- versions = hash_specs[spec.name.to_s] || []
108
- versions << spec.version.to_s
109
- hash_specs[spec.name.to_s] = versions
65
+ def validate_options(options)
66
+ format = options[:format]
67
+ format = format.downcase
68
+ unless %w(tar yml).include?(format)
69
+ raise Gem::CommandLineError, "invalid format \"#{format}\" argument.\nUsage:\n#{usage}"
110
70
  end
111
-
112
- gems = []
113
- hash_specs.each do |spec_name, versions|
114
- gems << {'name' => spec_name, 'versions' => versions}
115
- end
116
-
117
- main_hash = {'gems' => gems, 'sources' => Gem.sources}
118
- #say main_hash.to_yaml.to_s #for debug only :P
119
-
120
- File.open(filename, "w") do |file|
121
- file.puts(main_hash.to_yaml)
122
- end
123
- say "Gems exported to #{filename} successfully."
124
71
  end
125
72
 
126
- def get_and_check_arguments(args)
73
+ def extract_action(args)
127
74
  action = args[0]
128
75
  raise Gem::CommandLineError, "Snapshot needs an action argument.\nUsage:\n#{usage}" if action.nil? or action.empty?
129
76
 
@@ -132,24 +79,15 @@ Describe here what snapshot does.
132
79
  raise Gem::CommandLineError, "invalid action \"#{action}\" argument.\nUsage:\n#{usage}"
133
80
  end
134
81
 
135
- filename = nil
136
- if action == "export"
137
- filename = args[1] || "gems_#{Time.now.strftime("%Y%m%d_%H%M")}.yml"
138
- filename = filename.downcase
139
- filename.concat(".yml") unless end_with?(filename, ".yml")
140
- else
141
- filename = args[1]
142
- raise Gem::CommandLineError, "Snapshot needs an filename argument for import action.\nUsage:\n#{usage}" if filename.nil? or filename.empty?
82
+ filename = args[1]
83
+ raise Gem::CommandLineError, "Snapshot needs an filename argument for #{action} action.\nUsage:\n#{usage}" if filename.nil? or filename.empty?
84
+
85
+ if action == "import"
143
86
  raise Gem::Exception, "File not found. :( \nUsage:\n#{usage}" unless File.exist?(filename)
144
87
  end
145
88
 
146
89
  [action, filename]
147
90
  end
148
91
 
149
- def end_with?(target, suffix)
150
- suffix = suffix.to_s
151
- target[-suffix.length, suffix.length] == suffix
152
- end
153
-
154
92
  end
155
93
 
@@ -0,0 +1,37 @@
1
+
2
+ module GemsSnapshot
3
+
4
+ module ExporterHelper
5
+
6
+ # List all installed gems
7
+ def installed_gems
8
+ dep = Gem::Dependency.new(/^/i, Gem::Requirement.default) #get all local gems
9
+ Gem.source_index.search(dep)
10
+ end
11
+
12
+ end
13
+
14
+ #require all "exporters" from exporter folder
15
+ Dir["#{File.dirname(__FILE__)}/exporter/*_exporter.rb"].each do |file|
16
+ require "gems_snapshot/exporter/#{File.basename(file, ".rb")}"
17
+ end
18
+
19
+ class Exporter
20
+
21
+ def self.export(filename, options = {})
22
+ options = {:format => :tar}.merge(options)
23
+ format = options.delete(:format)
24
+
25
+ begin
26
+ exporter = GemsSnapshot.const_get("#{format.to_s.capitalize}Exporter").send(:new)
27
+ result = exporter.export(filename)
28
+ rescue => ex
29
+ raise Gem::Exception, "Ops! An unexpected error occurred: #{ex.message}"
30
+ end
31
+
32
+ result
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,55 @@
1
+ require "tmpdir" #necessary to use Dir.tmp
2
+ require "rubygems/package" #necessary to use Gem::Package::TarWriter
3
+
4
+ module GemsSnapshot
5
+
6
+ class TarExporter
7
+
8
+ include ExporterHelper
9
+
10
+ def export(filename)
11
+ filename = "snapshot.gems" if filename.nil?
12
+
13
+ files = []
14
+ installed_gems.each do |gem|
15
+ files << {:name => "gems/#{gem.full_name}.gem", :path => "#{gem.installation_path}/cache/#{gem.full_name}.gem"}
16
+ end
17
+ files << {:name => "gems.yml", :path => export_to_yml("#{Dir.tmpdir}/gems.yml")}
18
+
19
+ create_tar_file(filename, files)
20
+ filename
21
+ end
22
+
23
+ def export_to_yml(filename)
24
+ yml_exporter = GemsSnapshot::YmlExporter.new
25
+ yml_exporter.export("#{Dir.tmpdir}/gems.yml")
26
+ end
27
+
28
+ # Create a tar file with Gem::Package::TarWriter from Rubygems.
29
+ # +filename+ file destination.
30
+ # +files+ Array of Hash. Each hash have to be +:name+ and +:path+ keys.
31
+ def create_tar_file(filename, files)
32
+ File.open(filename, "w+") do |file|
33
+ Gem::Package::TarWriter.new(file) do |tar_file|
34
+
35
+ files.each do |hash|
36
+ next unless File.exists?(hash[:path])
37
+
38
+ filepath = hash[:path]
39
+ filename = hash[:name]
40
+
41
+ stat = File.stat(filepath)
42
+ tar_file.add_file_simple(filename, stat.mode, stat.size) do |tar_io|
43
+ File.open(filepath, "rb") do |file_io|
44
+ tar_io.write(file_io.read(4096)) until file_io.eof?
45
+ end
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,29 @@
1
+ module GemsSnapshot
2
+
3
+ class YmlExporter
4
+
5
+ include ExporterHelper
6
+
7
+ def export(filename)
8
+ hash_specs = {}
9
+ installed_gems.each do |spec|
10
+ versions = hash_specs[spec.name.to_s] || []
11
+ versions << spec.version.to_s
12
+ hash_specs[spec.name.to_s] = versions
13
+ end
14
+
15
+ gems = []
16
+ hash_specs.each do |spec_name, versions|
17
+ gems << {'name' => spec_name, 'versions' => versions}
18
+ end
19
+
20
+ main_hash = {'gems' => gems, 'sources' => Gem.sources}
21
+ #puts main_hash.to_yaml.to_s #for debug only :P
22
+
23
+ File.open(filename, "w") { |file| file.puts(main_hash.to_yaml) }
24
+ filename
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,25 @@
1
+ module GemsSnapshot
2
+
3
+ #require all "importers" from importer folder
4
+ Dir["#{File.dirname(__FILE__)}/importer/*_importer.rb"].each do |file|
5
+ require "gems_snapshot/importer/#{File.basename(file, ".rb")}"
6
+ end
7
+
8
+ class Importer
9
+
10
+ def self.import(filename, options = {})
11
+ options = {:format => :tar}.merge(options)
12
+ format = options.delete(:format)
13
+
14
+ begin
15
+ importer = GemsSnapshot.const_get("#{format.to_s.capitalize}Importer").send(:new)
16
+ importer.import(filename)
17
+ rescue => ex
18
+ raise Gem::Exception, "Ops! An unexpected error occurred: #{ex.message}"
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,55 @@
1
+ require "tmpdir" #necessary to use Dir.tmp
2
+
3
+ module GemsSnapshot
4
+
5
+ class TarImporter
6
+
7
+ def import(filename)
8
+ files = extract_files_from_tar(filename)
9
+ copy_gems_to_cache_directory files
10
+ yml_metadata = get_metadata(files)
11
+
12
+ yml_importer = GemsSnapshot::YmlImporter.new
13
+ yml_importer.import(yml_metadata)
14
+ end
15
+
16
+ private
17
+
18
+ def extract_files_from_tar(filename)
19
+ files = []
20
+
21
+ tmp_dir = "#{Dir.tmpdir}/#{Time.now.to_i}"
22
+ FileUtils.rm_rf tmp_dir
23
+ FileUtils.mkdir_p tmp_dir
24
+
25
+ begin
26
+ File.open(filename, "r") do |file|
27
+ Gem::Package::TarReader.new(file).each_entry do |entry|
28
+ destination_file = "#{tmp_dir}/#{entry.full_name}"
29
+ FileUtils.mkdir_p File.dirname(destination_file)
30
+
31
+ File.open(destination_file, "w+") { |f| f.write entry.read }
32
+ files << destination_file
33
+ end
34
+ end
35
+ rescue ex
36
+ raise "An error occurred while extracting files. #{ex.message}"
37
+ end
38
+ files
39
+ end
40
+
41
+ def get_metadata(files)
42
+ result = files.select { |file| file =~ /gems.yml$/ }
43
+ raise "File gems.yml not found!" if result.nil? or result.size == 0
44
+ result.first
45
+ end
46
+
47
+ def copy_gems_to_cache_directory(files)
48
+ cache_directory = "#{Gem.path.first}/cache"
49
+ files.select { |file| file =~ /.gem$/ }.each do |file|
50
+ FileUtils.cp file, "#{cache_directory}/#{File.basename(file)}"
51
+ end
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,72 @@
1
+ require 'rubygems/dependency_installer'
2
+ require 'yaml'
3
+
4
+ module GemsSnapshot
5
+
6
+ class YmlImporter
7
+
8
+ attr :errors
9
+
10
+ def import(filename)
11
+ yml_hash = YAML.load(File.read(filename)) #TODO: validate file content someday
12
+
13
+ yml_hash['gems'].each do |hash_gem|
14
+ gem_name = hash_gem['name']
15
+ hash_gem['versions'].each do |version|
16
+
17
+ if Gem.available? gem_name, version
18
+ puts "#{gem_name}-#{version} already available!"
19
+ next
20
+ end
21
+
22
+ gem_name = check_for_cache(gem_name, version)
23
+
24
+ puts "Going to install #{gem_name} -v#{version} ... wish me luck!"
25
+ begin
26
+ gem_install(gem_name, version)
27
+ rescue Gem::InstallError => e
28
+ errors << "Error installing #{gem_name}:\n\t#{e.message}"
29
+ rescue Gem::GemNotFoundException => e
30
+ errors << "Gem not found #{e.message}"
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+
37
+ protected
38
+
39
+ #Return gem file if exist at cache folder.
40
+ def check_for_cache(gem_name, version)
41
+ gem_file = "#{gem_name}-#{version}.gem"
42
+ Gem.path.each do |gem_path|
43
+ complete_path = "#{gem_path}/cache/#{gem_file}"
44
+ return complete_path if File.exist? complete_path
45
+ end
46
+ gem_name
47
+ end
48
+
49
+ def installer_options
50
+ @installer_options ||= Gem::DependencyInstaller::DEFAULT_OPTIONS.merge({
51
+ :generate_rdoc => true,
52
+ :generate_ri => true,
53
+ :format_executable => false,
54
+ :test => false,
55
+ :version => Gem::Requirement.default,
56
+ #aditional default parameters
57
+ :ignore_dependencies => true,
58
+ :verbose => true
59
+ })
60
+ end
61
+
62
+ def gem_install(gem_name, version, options = installer_options)
63
+ inst = Gem::DependencyInstaller.new(options)
64
+ inst.install(gem_name, version)
65
+ inst.installed_gems.each do |spec|
66
+ puts "Successfully installed #{spec.full_name}"
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -1,4 +1,8 @@
1
1
  require 'rubygems/command_manager'
2
2
  require 'commands/snapshot_command'
3
+
4
+ require "gems_snapshot/exporter"
5
+ require "gems_snapshot/importer"
6
+
3
7
  Gem::CommandManager.instance.register_command :snapshot
4
8
 
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubygems_snapshot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Roger Leite
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-02-05 00:00:00 -02:00
17
+ date: 2010-05-06 00:00:00 -03:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -23,22 +28,28 @@ extra_rdoc_files: []
23
28
 
24
29
  files:
25
30
  - lib/commands/snapshot_command.rb
31
+ - lib/gems_snapshot/importer/tar_importer.rb
32
+ - lib/gems_snapshot/importer/yml_importer.rb
33
+ - lib/gems_snapshot/exporter/tar_exporter.rb
34
+ - lib/gems_snapshot/exporter/yml_exporter.rb
35
+ - lib/gems_snapshot/exporter.rb
36
+ - lib/gems_snapshot/importer.rb
26
37
  - lib/rubygems_plugin.rb
27
38
  - README.textile
28
39
  has_rdoc: true
29
40
  homepage: http://github.com/rogerleite/rubygems_snapshot
30
41
  licenses: []
31
42
 
32
- post_install_message: |+
33
-
34
- ========================================================================
35
-
36
- Thanks for installing RubygemsSnapshot! You can now run:
37
-
38
- gem snapshot import/export your gems
39
-
40
- ========================================================================
41
-
43
+ post_install_message: |
44
+ ===============================================================================
45
+ Thanks for installing RubygemsSnapshot! You can now run:
46
+ gem snapshot export example
47
+ gem snapshot import example
48
+ ***
49
+ gem help snapshot for help! ;)
50
+ OR http://github.com/rogerleite/rubygems_snapshot
51
+ ===============================================================================
52
+
42
53
  rdoc_options: []
43
54
 
44
55
  require_paths:
@@ -47,18 +58,22 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
58
  requirements:
48
59
  - - ">="
49
60
  - !ruby/object:Gem::Version
61
+ segments:
62
+ - 0
50
63
  version: "0"
51
- version:
52
64
  required_rubygems_version: !ruby/object:Gem::Requirement
53
65
  requirements:
54
66
  - - ">="
55
67
  - !ruby/object:Gem::Version
68
+ segments:
69
+ - 1
70
+ - 3
71
+ - 5
56
72
  version: 1.3.5
57
- version:
58
73
  requirements: []
59
74
 
60
75
  rubyforge_project: rubygems_snapshot
61
- rubygems_version: 1.3.5
76
+ rubygems_version: 1.3.6
62
77
  signing_key:
63
78
  specification_version: 3
64
79
  summary: Command to import/export gems