gem-checkout 0.0.5 → 0.1.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.
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