gemfile_locker 0.2.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2f411635748ebab869141b3e36ca6a8ef8cb7e5a
4
- data.tar.gz: 8269cc977e333fe795775831873f7692184edb00
2
+ SHA256:
3
+ metadata.gz: d2725a59f53ef8af74767a9452e43e17e5c1e402acfa78a97570698a40209c92
4
+ data.tar.gz: cfdf2128c68cde403638e976ca6a25454b342a2436134369a1c086c95eb893ce
5
5
  SHA512:
6
- metadata.gz: 1845a4763600725c8f58d1f5e6c88579eb710a978e8553af9c9bcfcf27df0dbdd06a4b371cad3399c16a9a62aa284f4d05b7cebc63a213b1e119c4d8b526c639
7
- data.tar.gz: 75009ff12e89fc6051e68af04d9fed9ade15a008170a636c58409c23f42214e1be13eae4d1feeed7878aaa0c2ab38d4424a7e9b1efd6a7c1dbe0a3687c723da6
6
+ metadata.gz: 78b6f30fb6d863984499c8f48de1d5f29070c35d861b1637cac54729d400ac0026392efe876ba0bb50dc070608a157e4cde6d301ec6cef3eee74146a0b1e01b8
7
+ data.tar.gz: 3e06350ba9b4be3c59f79b502399660b3c48147473f00f162183a91e10e67e409f7a13842db3e2cfcf8b4a82834972089581590f8be9d456df1c3deae3a456e5
@@ -27,8 +27,9 @@ TXT
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ['lib']
29
29
 
30
- spec.add_runtime_dependency 'thor', '~> 0.19'
31
30
  spec.add_runtime_dependency 'bundler', '~> 1.13'
31
+ spec.add_runtime_dependency 'parser', '~> 2.0'
32
+ spec.add_runtime_dependency 'thor', '~> 0.19'
32
33
 
33
34
  spec.add_development_dependency 'rake', '~> 10.0'
34
35
  end
@@ -0,0 +1,54 @@
1
+ module GemfileLocker
2
+ class GemEntry
3
+ attr_reader :rewriter, :node
4
+
5
+ def initialize(rewriter, node)
6
+ @rewriter = rewriter
7
+ @node = node
8
+ end
9
+
10
+ def name
11
+ node.children[2].children[0]
12
+ end
13
+
14
+ # Overriden in prepended modules.
15
+ def lock(**options)
16
+ end
17
+
18
+ # Overriden in prepended modules.
19
+ def unlock
20
+ end
21
+
22
+ require 'gemfile_locker/gem_entry/versions'
23
+ prepend Versions
24
+
25
+ require 'gemfile_locker/gem_entry/git_ref'
26
+ prepend GitRef
27
+
28
+ protected
29
+
30
+ # Node with gem options, if present.
31
+ def options_node
32
+ result = node.children.last
33
+ result if result.type == :hash
34
+ end
35
+
36
+ # Change content of string, keeping quoting style.
37
+ def replace_string_node(target, value)
38
+ quote = target.loc.begin.source
39
+ rewriter.replace(target.loc.expression, "#{quote}#{value}#{quote}")
40
+ end
41
+
42
+ # Remove node with preceding comma.
43
+ def remove_node_with_comma(target)
44
+ expression = target.loc.expression
45
+ comma_pos = expression.source_buffer.source.rindex(',', expression.begin_pos)
46
+ rewriter.remove(expression.with(begin_pos: comma_pos))
47
+ end
48
+
49
+ # Quote style used in name of gem.
50
+ def name_quote
51
+ node.children[2].loc.begin.source
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,54 @@
1
+ module GemfileLocker
2
+ class GemEntry
3
+ module GitRef
4
+ def lock(options)
5
+ git_ref = options[:git_ref]
6
+ set_git_ref(git_ref) if git_ref && !has_git_tag?
7
+ super
8
+ end
9
+
10
+ def unlock
11
+ remove_git_ref
12
+ super
13
+ end
14
+
15
+ def has_git_tag?
16
+ git_option_nodes.any? { |pair| pair.children[0].children[0] == :tag }
17
+ end
18
+
19
+ def set_git_ref(ref) # rubocop:disable AccessorMethodName
20
+ ref_node = ref_option_node
21
+ return replace_string_node(ref_node.children[1], ref) if ref_node
22
+ git_nodes = git_option_nodes
23
+ insert_after_node = git_nodes.any? ? git_nodes.last : node.children.last
24
+ quote = name_quote
25
+ rewriter.insert_after(insert_after_node.loc.expression.end, ", ref: #{quote}#{ref}#{quote}")
26
+ end
27
+
28
+ def remove_git_ref
29
+ ref_node = ref_option_node
30
+ remove_node_with_comma(ref_node) if ref_node
31
+ end
32
+
33
+ protected
34
+
35
+ def ref_option_node
36
+ return unless options_node
37
+ options_node.children.find do |pair|
38
+ pair.children[0].to_sexp_array == [:sym, :ref]
39
+ end
40
+ end
41
+
42
+ RELATED_OPTIONS = /\A(git*|branch|tag)\z/
43
+
44
+ def git_option_nodes
45
+ return [] unless options_node
46
+ options_node.children.reverse.select do |pair|
47
+ key_node = pair.children[0]
48
+ next unless key_node.type == :sym
49
+ RELATED_OPTIONS =~ key_node.children[0].to_s
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,52 @@
1
+ module GemfileLocker
2
+ class GemEntry
3
+ module Versions
4
+ EXTRA_VERSION_REGEXP = /\A[><]/
5
+
6
+ def lock(options)
7
+ version = options[:version]
8
+ set_version(version) if version
9
+ super
10
+ end
11
+
12
+ def unlock
13
+ remove_version
14
+ super
15
+ end
16
+
17
+ def locked?
18
+ version_nodes.any?
19
+ end
20
+
21
+ def set_version(version) # rubocop:disable AccessorMethodName
22
+ version_nodes = self.version_nodes
23
+ if version_nodes.any?
24
+ replace_string_node(version_nodes.first, version)
25
+ else
26
+ quote = name_quote
27
+ rewriter.insert_after(node.children[2].loc.end, ", #{quote}#{version}#{quote}")
28
+ end
29
+ end
30
+
31
+ def remove_version
32
+ # If multiple version strings are given, keep that which start with `>, >=, <, <=`.
33
+ version_nodes = self.version_nodes(strict: ->(versions) { versions.size > 1 })
34
+ version_nodes.each do |arg_node|
35
+ remove_node_with_comma(arg_node)
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def version_nodes(strict_if: nil, strict: !strict_if)
42
+ result = node.children.drop(3).select { |arg_node| arg_node.type == :str }
43
+ if strict_if && strict_if[result] || strict
44
+ result = result.reject do |arg_node|
45
+ EXTRA_VERSION_REGEXP =~ arg_node.children[0]
46
+ end
47
+ end
48
+ result
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,27 +1,22 @@
1
+ require 'parser'
2
+ require 'parser/current'
3
+ require 'gemfile_locker/gem_entry'
4
+
1
5
  module GemfileLocker
2
6
  class GemfileProcessor
3
- GEM_LINE_REGEX = /
4
- ^
5
- (?<prefix>\s*gem\s*["'])
6
- (?<name>[^'"]+)
7
- (?<name_quote>['"])
8
- (?<version_section>
9
- (?<version_prefix>\s*,\s*['"])
10
- (?<version>[^'"]*)
11
- (?<version_quote>['"])
12
- )?
13
- (?<suffix>,?.*)?
14
- $
15
- /x
16
- GEM_MATCH_FIELDS = %i(
17
- prefix
18
- name
19
- name_quote
20
- version_prefix
21
- version
22
- version_quote
23
- suffix
24
- ).freeze
7
+ class Rewriter < Parser::TreeRewriter
8
+ def rewrite(*args, &block)
9
+ @rewrite_block = block
10
+ super(*args)
11
+ end
12
+
13
+ def on_send(node)
14
+ children = node.children
15
+ return unless children[0].nil? && node.children[1] == :gem
16
+ gem_entry = GemEntry.new(self, node)
17
+ @rewrite_block[gem_entry]
18
+ end
19
+ end
25
20
 
26
21
  attr_reader :path, :options
27
22
 
@@ -30,47 +25,25 @@ module GemfileLocker
30
25
  end
31
26
 
32
27
  def call(string)
33
- process_gems(string) do |data|
34
- process_gem(data) unless skip_gem?(data)
28
+ buffer = Parser::Source::Buffer.new('(Gemfile)')
29
+ buffer.source = string
30
+ parser = Parser::CurrentRuby.new
31
+ ast = parser.parse(buffer)
32
+ Rewriter.new.rewrite(buffer, ast) do |gem_entry|
33
+ process_gem(gem_entry) unless skip_gem?(gem_entry)
35
34
  end
36
35
  end
37
36
 
38
- def skip_gem?(data)
37
+ def skip_gem?(gem_entry)
39
38
  if options[:only]
40
- !options[:only].include?(data[:name])
39
+ !options[:only].include?(gem_entry.name)
41
40
  elsif options[:except]
42
- options[:except].include?(data[:name])
43
- end
44
- end
45
-
46
- def process_gems(string)
47
- string.gsub(GEM_LINE_REGEX) do
48
- match = Regexp.last_match
49
- data = Hash[GEM_MATCH_FIELDS.map { |x| [x, match[x]] }]
50
- result = yield data
51
- result ||= data
52
- GEM_MATCH_FIELDS.map { |x| result[x] }.join
41
+ options[:except].include?(gem_entry.name)
53
42
  end
54
43
  end
55
44
 
56
45
  def process_gem(_name, _data)
57
46
  raise 'Abstract method'
58
47
  end
59
-
60
- def set_gem_version(data, version)
61
- data = data.dup
62
- if version
63
- data[:version_prefix] ||= ", #{data[:name_quote] || "'"}"
64
- data[:version_quote] ||= data[:name_quote] || "'"
65
- data[:version] = version
66
- else
67
- %i(
68
- version_prefix
69
- version
70
- version_quote
71
- ).each { |x| data.delete(x) }
72
- end
73
- data
74
- end
75
48
  end
76
49
  end
@@ -20,14 +20,15 @@ module GemfileLocker
20
20
  @bundler_specs ||= Bundler::LockfileParser.new(lockfile).specs
21
21
  end
22
22
 
23
- def process_gem(data)
24
- name = data[:name]
25
- locked = bundler_specs.find { |x| x.name == name }
26
- locked && set_gem_version(data, prepare_version(locked.version))
23
+ def process_gem(gem_entry)
24
+ name = gem_entry.name
25
+ spec = bundler_specs.find { |x| x.name == name }
26
+ return unless spec
27
+ gem_entry.lock(version: prepare_version(spec.version), git_ref: prepare_git_ref(spec))
27
28
  end
28
29
 
29
- def skip_gem?(data)
30
- super || data[:version] && !options[:force]
30
+ def skip_gem?(gem_entry)
31
+ super || gem_entry.locked? && !options[:force]
31
32
  end
32
33
 
33
34
  private
@@ -40,5 +41,11 @@ module GemfileLocker
40
41
  version.to_s
41
42
  end
42
43
  end
44
+
45
+ def prepare_git_ref(spec)
46
+ if spec.source.is_a?(Bundler::Source::Git)
47
+ spec.source.options['ref'] || spec.source.revision[0...7]
48
+ end
49
+ end
43
50
  end
44
51
  end
@@ -2,8 +2,8 @@ module GemfileLocker
2
2
  class Unlocker < GemfileProcessor
3
3
  attr_reader :lockfile
4
4
 
5
- def process_gem(data)
6
- set_gem_version(data, nil)
5
+ def process_gem(gem_entry)
6
+ gem_entry.unlock
7
7
  end
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  module GemfileLocker
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
 
4
4
  def self.gem_version
5
5
  Gem::Version.new VERSION
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemfile_locker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Melentiev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-19 00:00:00.000000000 Z
11
+ date: 2018-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.19'
19
+ version: '1.13'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.19'
26
+ version: '1.13'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: parser
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.13'
33
+ version: '2.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.13'
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.19'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.19'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -81,6 +95,9 @@ files:
81
95
  - lib/gemfile_locker.rb
82
96
  - lib/gemfile_locker/cli.rb
83
97
  - lib/gemfile_locker/file_editor.rb
98
+ - lib/gemfile_locker/gem_entry.rb
99
+ - lib/gemfile_locker/gem_entry/git_ref.rb
100
+ - lib/gemfile_locker/gem_entry/versions.rb
84
101
  - lib/gemfile_locker/gemfile_processor.rb
85
102
  - lib/gemfile_locker/locker.rb
86
103
  - lib/gemfile_locker/unlocker.rb
@@ -104,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
121
  version: '0'
105
122
  requirements: []
106
123
  rubyforge_project:
107
- rubygems_version: 2.5.1
124
+ rubygems_version: 2.7.7
108
125
  signing_key:
109
126
  specification_version: 4
110
127
  summary: Tool to manage Gemfile. Lock and unlock all dependencies for safe `bundle