gem-checkout 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee28067ee5184c515081a3cfad38b70eda8c9bb7
4
- data.tar.gz: e3a3abe9fa00964bfa733ead7414a266baa961ac
3
+ metadata.gz: 3c3ac04887cf0d974da2a2c50c35f1a74410515b
4
+ data.tar.gz: 0cb624321ec30843de7b3e2e7093e10d836c83b5
5
5
  SHA512:
6
- metadata.gz: 8a55d5ba004b3989f3020f892bf5112a1016a9d867a41ce16bc969c8e256511c674559cafa7e95d9ff3120ecbf34763c10628d5d542fafc93091a427f569ca38
7
- data.tar.gz: 2ab5e1fb93f34b50f3e44899bc292765737960c99e3cc2c6060b5241fa30007d9a435376be850a2e8d5f95eb9de2ded837fc05ef02f7c51b604cb71788fb0c44
6
+ metadata.gz: 083a70f4aa6bb4826494d20a062da913c32f530e5260a294456e22ad8000a664b5579a3582f77765b4759d6a0bded7fcab8cbd1c2aaa8696ec9bb97467aabeb2
7
+ data.tar.gz: 30a7347b10ed81c0e6464dc00e96ebfa2b38521a53d1b90a8dc213a9e1a5abe2b63878ff0b1aca7f308016ad868ea005b032c85531c74531b846eb2f67b9be47
data/README.md CHANGED
@@ -17,34 +17,35 @@ will checkout the GitHub source code (into the current dir) for the `nenv` gem a
17
17
 
18
18
  ## Installation
19
19
 
20
- Add this line to your application's Gemfile:
21
-
22
20
  ```sh
23
21
  gem install gem-checkout
24
22
  ```
25
23
 
26
24
  ## Usage
27
25
 
28
- Proof of concept right now, so open issues and/or PRs for improvements.
26
+ Proof of concept right now, so check or open issues and/or PRs for improvements.
29
27
 
30
28
  Options:
31
29
 
32
30
  ```
33
- -d LEVEL
31
+ -d LEVEL # sets debug level, where 0=debug, 1=warn, and so on...
34
32
  ```
35
- sets the debug level, where 0=debug, 1=warn, and so on...
36
33
 
37
34
  ```
38
- -v, --version VERSION
35
+ -v, --version VERSION # gem version to you want the sources for.
39
36
  ```
40
37
 
41
- The version of the gem to you want to hack on - the repo and revision will be discovered.
42
-
43
38
  (If you don't provide this option, the latest version will be used).
44
39
 
40
+ ```
41
+ -s, --verify # compare gem built from sources with released version
42
+ ```
43
+
44
+ (If it's identical, you can assume the released gem was build from these exact chechecked out sources).
45
+
45
46
  ## FAQ
46
47
 
47
- None yet, so open an issue...
48
+ None yet, so open issues and ask for improvements/features ...
48
49
 
49
50
 
50
51
  ## Development
@@ -97,10 +97,14 @@ module Gem
97
97
  end
98
98
  end
99
99
 
100
+ attr_reader :version
101
+
100
102
  def initialize(name, version=nil)
101
- Gem::Checkout.logger.debug "Gathering infor about #{name} (#{version || 'latest'})"
103
+ Gem::Checkout.logger.debug "Gathering info about #{name} (#{version || 'latest'})"
102
104
  object = Spec.info(name, version)
103
105
 
106
+ @version = object.version
107
+
104
108
  @name = name
105
109
 
106
110
  repository = RepositoryInfo.detect(object)
@@ -63,7 +63,6 @@ module Gem
63
63
  def initialize(name, version, remote)
64
64
  @data = find_by_name(name, version)
65
65
  @name = name
66
- @version = version
67
66
  @remote = remote
68
67
  end
69
68
 
@@ -90,7 +89,7 @@ module Gem
90
89
  end
91
90
 
92
91
  def version
93
- read(:version)
92
+ read(:version).to_s
94
93
  end
95
94
 
96
95
  def alternative
@@ -212,7 +211,7 @@ module Gem
212
211
  info['number'] == version
213
212
  end
214
213
 
215
- fail Error::NoSuchGem, "Could not find #{name} on rubygems.org" unless version
214
+ fail Error::NoSuchGem, "Could not find #{name} at #{version} on rubygems.org (yanked gem?)" unless version
216
215
  Gem::Checkout.logger.debug "Found info matching gem version #{@version}"
217
216
  OpenStruct.new(version)
218
217
  end
@@ -0,0 +1,146 @@
1
+ require 'digest/sha1'
2
+ require 'pathname'
3
+
4
+ require 'gem-checkout/logger'
5
+
6
+ module Gem
7
+ module Checkout
8
+ class Verifier
9
+ class Gem
10
+ class << self
11
+ def fetch(name, version)
12
+ version_opts = ['-v', version]
13
+ fail "failed to fetch gem #{name}" unless system("gem", "fetch", "-V", *version_opts, name)
14
+ end
15
+
16
+ def build(gemspec)
17
+ fail "failed to build using #{gemspec}" unless system("gem", "build", gemspec)
18
+ end
19
+ end
20
+ end
21
+
22
+ class Tar
23
+ class << self
24
+ def extract_file(archive, file)
25
+ fail "failed to untar #{file} from #{archive}" unless system("tar", "xf", archive, file)
26
+ end
27
+
28
+ def extract_compressed(archive)
29
+ fail "failed to untar#{archive}" unless system("tar", "zxf", archive)
30
+ end
31
+ end
32
+ end
33
+
34
+ class Error < RuntimeError
35
+ class DataMismatch < Error
36
+ end
37
+ end
38
+
39
+ def initialize(name, version)
40
+ @name = name
41
+ @version = version
42
+ end
43
+
44
+ def verify!
45
+ file = build_local_gem
46
+ local = get_payload_sum(file)
47
+ remote = get_remote_payload_sum
48
+
49
+ unless local == remote
50
+ local_files = local.map(&:last)
51
+ remote_files = remote.map(&:last)
52
+ if local_files != remote_files
53
+ logger.debug "Files present only in published gem: #{remote_files - local_files }"
54
+ logger.debug "Files present only in local gem: #{local_files - remote_files }"
55
+ else
56
+ diff = remote - local
57
+ diff.each do |checksum, f|
58
+ logger.debug "Checksum mismatch: #{checksum} #{f}"
59
+ end
60
+ end
61
+ fail Error::DataMismatch, "checksum mismatch (run in debug mode to see details)"
62
+ end
63
+
64
+ end
65
+
66
+ private
67
+
68
+ def name
69
+ @name
70
+ end
71
+
72
+ def version
73
+ @version
74
+ end
75
+
76
+ def digest(f)
77
+ Digest::SHA256.file(f).hexdigest
78
+ end
79
+
80
+ def logger
81
+ Checkout.logger
82
+ end
83
+
84
+ def build_local_gem
85
+ logger.debug "Building #{name}-#{version}.gem from sources..."
86
+ gemspec = detect_gemspec
87
+ Gem.build(gemspec)
88
+ File.expand_path("#{name}-#{version}.gem")
89
+ end
90
+
91
+ def detect_gemspec
92
+ gemspecs = Dir['*.gemspec']
93
+ fail "Too many gemspecs: #{gemspecs.inspect}" unless gemspecs.size == 1
94
+ gemspecs.first
95
+ end
96
+
97
+ def tempdir
98
+ Dir.mktmpdir do |dir|
99
+ Dir.chdir(dir) do
100
+ yield
101
+ end
102
+ end
103
+ end
104
+
105
+ def get_payload_sum(file)
106
+ full_path = File.expand_path(file)
107
+ logger.debug "Getting SHA digests for #{full_path}"
108
+
109
+ results = []
110
+ tempdir do
111
+ data_file = "data.tar.gz"
112
+ Tar.extract_file(full_path, data_file)
113
+
114
+ archive_path = File.expand_path(data_file)
115
+
116
+ tempdir do
117
+ Tar.extract_compressed(archive_path)
118
+ add_directory_sums(results, '.')
119
+ end
120
+ end
121
+ results
122
+ end
123
+
124
+ def get_remote_payload_sum
125
+ logger.debug "Fetching remote gem for verification"
126
+ tempdir do
127
+ Gem.fetch(name, version)
128
+ file = "#{name}-#{version}.gem"
129
+ return get_payload_sum(file)
130
+ end
131
+ end
132
+
133
+ def add_directory_sums(results, dir)
134
+ # TODO: check for filesystem loops/symlinks?
135
+ Pathname.new(dir).children.each do |f|
136
+ if File.directory?(f)
137
+ add_directory_sums(results, f)
138
+ else
139
+ logger.debug "SHA digest #{File.expand_path(f)}"
140
+ results << [digest(f), f]
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,5 @@
1
+ module Gem
2
+ module Checkout
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -1,6 +1,7 @@
1
1
  require 'logger'
2
2
 
3
3
  require 'gem-checkout/source'
4
+ require 'gem-checkout/verifier'
4
5
 
5
6
  class Gem::Commands::CheckoutCommand < Gem::Command
6
7
  def initialize
@@ -12,6 +13,10 @@ class Gem::Commands::CheckoutCommand < Gem::Command
12
13
  add_option('-d', '--debug LEVEL', 'set debug mode (0=debug)') do |level, options|
13
14
  options[:debug_level] = Integer(level)
14
15
  end
16
+
17
+ add_option('-s', '--[no-]verify', 'verify sources match gem exactly') do |verify, options|
18
+ options[:verify] = verify
19
+ end
15
20
  end
16
21
 
17
22
  def arguments # :nodoc:
@@ -37,13 +42,22 @@ class Gem::Commands::CheckoutCommand < Gem::Command
37
42
 
38
43
  name = get_one_gem_name
39
44
  source = Gem::Checkout::Source.new(name, options[:version])
45
+ version = source.version
46
+
40
47
  repository = source.repository
41
48
  repository.clone(directory: name)
42
49
  Dir.chdir(name) do
43
50
  repository.checkout(source.source_reference)
51
+ if options[:verify]
52
+ verifier = Gem::Checkout::Verifier.new(name, version)
53
+ verifier.verify!
54
+ end
44
55
  end
45
56
  rescue Gem::Checkout::Repository::Error => ex
46
57
  alert_error ex.message
47
58
  terminate_interaction 1
59
+ rescue Gem::Checkout::Verifier::Error => ex
60
+ alert_error ex.message
61
+ terminate_interaction 1
48
62
  end
49
63
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gem-checkout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cezary Baginski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-21 00:00:00.000000000 Z
11
+ date: 2015-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gems
@@ -54,6 +54,8 @@ files:
54
54
  - lib/gem-checkout/repository/git.rb
55
55
  - lib/gem-checkout/source.rb
56
56
  - lib/gem-checkout/spec.rb
57
+ - lib/gem-checkout/verifier.rb
58
+ - lib/gem-checkout/version.rb
57
59
  - lib/rubygems/commands/checkout_command.rb
58
60
  - lib/rubygems_plugin.rb
59
61
  homepage: https://github.com/e2/gem-checkout