davidsmalley-gem-thief 0.0.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/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.0.1 / 2008-11-01
2
+
3
+ * Working release that just clones your local gems to a remote server.
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/thief
6
+ lib/gem_thief.rb
7
+ lib/gem_thief/export.rb
8
+ lib/gem_thief/import.rb
9
+ lib/thief.rb
10
+ spec/gem_thief_spec.rb
11
+ spec/spec_helper.rb
12
+ test/test_gem-thief.rb
data/README.txt ADDED
@@ -0,0 +1,67 @@
1
+ gem-thief
2
+ by David Smalley
3
+ http://github.com/davidsmalley/gem-thief
4
+
5
+ == DESCRIPTION:
6
+
7
+ Gem Thief was designed to help me sync the various gem versions on the application servers running Litmus.
8
+ Everytime we deploy a new server I need to reinstall all the necessary gems and get the right versions. Rails
9
+ gem dependencies are great but they don't work across all of the apps we run including a few Ruby utility apps.
10
+ Gem thief is designed to be run on one machine which has the gems, and given the credentials to connect to the
11
+ remote machine which needs gems installing.
12
+
13
+ == FEATURES/PROBLEMS:
14
+
15
+ * Will mirror gems on your local computer to a remote computer using a number of different strategies
16
+ * Parses remote gems from the gem list --local command, not really ideal but works for now
17
+ (new RubyGem versions might break the expected output)
18
+
19
+ == SYNOPSIS:
20
+
21
+ ./thief -h a.remote.machine.com -u root --strategy latest -x
22
+
23
+ You can also pass in the following flags:
24
+ --no-docs :Pass --no-ri --no-rdoc onto the gem install command
25
+ --no-deps :Do all installs with the --ignore-dependencies flag
26
+ --pretend :Just print a list of gems which would have been updated
27
+
28
+ Strategy has 4 options:
29
+ - all: Totally install all gems and versionsfrom the local machine regardless of what gems are already on the remote machine
30
+ - latest: Just install the most recent versions of all the gems on the local machine
31
+ - missing: Install all versions of gems which are on the local machine but not on the remote machine
32
+ - latest_missing: Install the most recent versions of any missing gems on the remote machine
33
+
34
+ == REQUIREMENTS:
35
+
36
+ * Net/ssh > 2
37
+ * RubyGems > 1.2
38
+
39
+ == INSTALL:
40
+
41
+ * Install the gem
42
+ * run Thief command from machine which has the desired gems
43
+
44
+ == LICENSE:
45
+
46
+ (The MIT License)
47
+
48
+ Copyright (c) 2008
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining
51
+ a copy of this software and associated documentation files (the
52
+ 'Software'), to deal in the Software without restriction, including
53
+ without limitation the rights to use, copy, modify, merge, publish,
54
+ distribute, sublicense, and/or sell copies of the Software, and to
55
+ permit persons to whom the Software is furnished to do so, subject to
56
+ the following conditions:
57
+
58
+ The above copyright notice and this permission notice shall be
59
+ included in all copies or substantial portions of the Software.
60
+
61
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
62
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
63
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
65
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
66
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
67
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ begin
6
+ require 'bones'
7
+ Bones.setup
8
+ rescue LoadError
9
+ load 'tasks/setup.rb'
10
+ end
11
+
12
+ ensure_in_path 'lib'
13
+ require 'gem_thief'
14
+
15
+ task :default => 'spec:run'
16
+
17
+ PROJ.name = 'gem-thief'
18
+ PROJ.authors = 'David Smalley'
19
+ PROJ.email = 'david[at]davidsmalley.com'
20
+ PROJ.url = 'http://github.com/davidsmalley/gem-thief'
21
+ PROJ.version = GemThief::VERSION
22
+ PROJ.rubyforge.name = 'gem-thief'
23
+
24
+ PROJ.spec.opts << '--color'
25
+
26
+ # EOF
data/bin/thief ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib gem_thief]))
5
+
6
+ require 'optparse'
7
+ require 'pp'
8
+
9
+ options = {}
10
+ OptionParser.new do |opts|
11
+
12
+ opts.banner
13
+
14
+ # no argument, shows at tail
15
+ opts.on_tail("--help", "show this message") {puts opts; exit}
16
+
17
+ # mandatory argument
18
+ opts.on("-h", "--remote-host [HOST]",
19
+ "Remote host that",
20
+ "gems will be mirrored to") do |o|
21
+ options[:host] = o
22
+ end
23
+ opts.on("-u", "--user [USER]",
24
+ "The user to connect as") do |o|
25
+ options[:user] = o
26
+ end
27
+ opts.on("-p", "--password [PASSWORD]",
28
+ "The password to connect", "Not required if you have a public key setup already") do |o|
29
+ options[:password] = o || ""
30
+ end
31
+ opts.on("-s", "--strategy [STRATEGY]",
32
+ "The gem mirroring strategy used",
33
+ "Can be: all, latest, missing, latest_missing") do |o|
34
+ options[:strategy] = o.to_sym
35
+ end
36
+ options[:pretend] = false
37
+ opts.on("-x", "--pretend", TrueClass, "Pretend and just print output") do |o|
38
+ options[:pretend] = o
39
+ end
40
+ options[:no_docs] = true
41
+ opts.on("-d", "--no-docs", TrueClass, "Don't install with Ri+Rdoc") do |o|
42
+ options[:no_docs] = o
43
+ end
44
+ options[:no_deps] = false
45
+ opts.on("-i", "--ignore-deps", TrueClass, "Ignore dependencies") do |o|
46
+ options[:no_deps] = o
47
+ end
48
+
49
+ end.parse!
50
+
51
+ GemThief::Thief.run(options)
@@ -0,0 +1,92 @@
1
+ gem "net-ssh", ">2.0"
2
+ require 'net/ssh'
3
+ module GemThief
4
+ class Export
5
+ include GemThief::Thief
6
+
7
+
8
+ def initialize(import, options = {})
9
+ @import = import
10
+ @host = options[:host]
11
+ @user = options[:user]
12
+ @password = options[:password] || ""
13
+ end
14
+
15
+ def mirror_gems(options = {})
16
+ mirror_sources
17
+ gems = case options[:strategy]
18
+ when :all
19
+ @import.gem_list
20
+ when :latest
21
+ @import.latest_gem_list
22
+ when :missing
23
+ missing_gems
24
+ when :latest_missing
25
+ latest_missing_gems
26
+ end
27
+ connect do |ssh|
28
+ gems.each do |gem|
29
+ begin
30
+ if options[:pretend]
31
+ puts "Would have mirrored #{gem[0]} version #{gem[1]}"
32
+ else
33
+ ssh.exec!(gem_command(gem, options))
34
+ puts "Mirrored #{gem[0]} version #{gem[1]}"
35
+ end
36
+ rescue
37
+ puts "Error mirroring #{gem[0]} version #{gem[1]}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def sources
44
+ connect do |ssh|
45
+ return clean_sources(ssh.exec!("gem sources"))
46
+ end
47
+ end
48
+
49
+ def installed_gems
50
+ connect do |ssh|
51
+ return list_from_cli_source(ssh.exec!("gem list --local"))
52
+ end
53
+ end
54
+
55
+ def missing_gems
56
+ @import.gem_list - installed_gems
57
+ end
58
+
59
+ def latest_missing_gems
60
+ @import.latest_gem_list - installed_gems
61
+ end
62
+
63
+ def missing_sources
64
+ @import.sources - sources
65
+ end
66
+
67
+ def mirror_sources
68
+ connect do |ssh|
69
+ missing_sources.each do |source|
70
+ ssh.exec!("gem sources -a #{source}")
71
+ ssh.exec!("gem sources -u #{source}")
72
+ end
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def gem_command(gem, options = {})
79
+ gem_command = "gem install #{gem[0]} -v #{gem[1]}"
80
+ gem_command << " --no-rdoc --no-ri" if options[:no_docs]
81
+ gem_command << " --ignore-dependencies" if options[:no_deps]
82
+ return gem_command
83
+ end
84
+
85
+ def connect(&block)
86
+ Net::SSH.start(@host, @user, :password => @password) do |ssh|
87
+ yield ssh
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ module GemThief
3
+ class Import
4
+ include GemThief::Thief
5
+
6
+
7
+ def initialize(options = {})
8
+ @gem_home = File.expand_path Gem.dir
9
+ @spec_dir = File.join @gem_home, 'specifications'
10
+ end
11
+
12
+ def sources
13
+ clean_sources(`gem sources`)
14
+ end
15
+
16
+ def gem_list
17
+ @gem_list ||= t = []
18
+ source_index.each {|name,x| t << [x.name, x.version]} if @gem_list.empty?
19
+ @gem_list
20
+ end
21
+
22
+ def latest_gem_list
23
+ @latest_gem_list ||= source_index.latest_specs.collect {|x| [x.name, x.version]}
24
+ end
25
+
26
+ def source_index
27
+ @source_index ||= Gem::SourceIndex.from_gems_in @spec_dir
28
+ end
29
+
30
+ end
31
+ end
data/lib/gem_thief.rb ADDED
@@ -0,0 +1,50 @@
1
+ module GemThief
2
+
3
+ # :stopdoc:
4
+ VERSION = '0.0.1'
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ # :startdoc:
8
+
9
+ # Returns the version string for the library.
10
+ #
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ # Returns the library path for the module. If any arguments are given,
16
+ # they will be joined to the end of the libray path using
17
+ # <tt>File.join</tt>.
18
+ #
19
+ def self.libpath( *args )
20
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
21
+ end
22
+
23
+ # Returns the lpath for the module. If any arguments are given,
24
+ # they will be joined to the end of the path using
25
+ # <tt>File.join</tt>.
26
+ #
27
+ def self.path( *args )
28
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
29
+ end
30
+
31
+ # Utility method used to rquire all files ending in .rb that lie in the
32
+ # directory below this file that has the same name as the filename passed
33
+ # in. Optionally, a specific _directory_ name can be passed in such that
34
+ # the _filename_ does not have to be equivalent to the directory.
35
+ #
36
+ def self.require_all_libs_relative_to( fname, dir = nil )
37
+ dir ||= ::File.basename(fname, '.*')
38
+ search_me = ::File.expand_path(
39
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
40
+
41
+ Dir.glob(search_me).sort.each {|rb| require rb}
42
+ end
43
+
44
+ end # module GemThief
45
+
46
+ require 'rubygems'
47
+ require GemThief.libpath + '/thief'
48
+ GemThief.require_all_libs_relative_to(__FILE__)
49
+
50
+ # EOF
data/lib/thief.rb ADDED
@@ -0,0 +1,27 @@
1
+ module GemThief
2
+ module Thief
3
+
4
+ def self.run(options = {})
5
+ import = Import.new
6
+ export = Export.new(import, options)
7
+ export.mirror_gems(options)
8
+ end
9
+
10
+ def clean_sources(sources_string)
11
+ return sources_string.split.delete_if {|x| x !~ /^http.*/}
12
+ end
13
+
14
+ def list_from_cli_source(cli_source)
15
+ raw_list = cli_source.split("\n").delete_if { |x| x == "" || x =~ /\*\*\* (LOCAL|REMOTE) GEMS \*\*\*/ }
16
+ split_list = raw_list.collect {|line| [line.split(" (")[0], line.split(" (")[1].gsub(")", "").split(", ")] }
17
+ gem_list = []
18
+ split_list.each do |gem|
19
+ gem[1].each do |version|
20
+ gem_list << [gem[0], version]
21
+ end
22
+ end
23
+ return gem_list || []
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[spec_helper])
3
+
4
+ describe GemThief do
5
+ end
6
+
7
+ # EOF
@@ -0,0 +1,16 @@
1
+
2
+ require File.expand_path(
3
+ File.join(File.dirname(__FILE__), %w[.. lib gem-thief]))
4
+
5
+ Spec::Runner.configure do |config|
6
+ # == Mock Framework
7
+ #
8
+ # RSpec uses it's own mocking framework by default. If you prefer to
9
+ # use mocha, flexmock or RR, uncomment the appropriate line:
10
+ #
11
+ # config.mock_with :mocha
12
+ # config.mock_with :flexmock
13
+ # config.mock_with :rr
14
+ end
15
+
16
+ # EOF
File without changes
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: davidsmalley-gem-thief
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - David Smalley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-01 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Mirrors gems across machines
17
+ email: david[at]davidsmalley.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - History.txt
26
+ - Manifest.txt
27
+ - README.txt
28
+ - Rakefile
29
+ - bin/thief
30
+ - lib/gem_thief.rb
31
+ - lib/gem_thief/export.rb
32
+ - lib/gem_thief/import.rb
33
+ - lib/thief.rb
34
+ - spec/gem_thief_spec.rb
35
+ - spec/spec_helper.rb
36
+ - test/test_gem-thief.rb
37
+ has_rdoc: false
38
+ homepage: http://github.com/davidsmalley/gem-thief
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ - lib/gem_thief
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: Mirrors gems across machines
64
+ test_files: []
65
+