lapidario 0.2alpha.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +17 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +68 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/lapidario +6 -0
- data/bin/setup +8 -0
- data/lapidario.gemspec +42 -0
- data/lib/cli.rb +21 -0
- data/lib/gemfile_info.rb +88 -0
- data/lib/helper.rb +68 -0
- data/lib/lapidario/version.rb +5 -0
- data/lib/lapidario.rb +72 -0
- data/lib/lockfile_info.rb +51 -0
- data/sig/lapidario.rbs +4 -0
- metadata +99 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 721c005dc4e70e80f45c56f387ee66f6c8bbccecf06ca06349aa0ae362efd40f
|
|
4
|
+
data.tar.gz: 46f65d04260e78be7455b87545fecd6bcafb25b84aec9b4124a7808e84e0452e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c3ed33e86fded4875b8f3765b1a60954b3f9aca7ef1d81093e87f5895f2749e53e5f664daf0c2801a3b53d0d517001942d819d6f1d37a57fad1659812134f901
|
|
7
|
+
data.tar.gz: d5fa0f607b5db55ffc32817e2f84dcb25202ca681cb4da94f74e87f4c2da52c0cf0604e0096abb867201b5331cbd4c012fd423037b611e916507581fd821a31b
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.6
|
|
3
|
+
|
|
4
|
+
Style/StringLiterals:
|
|
5
|
+
Enabled: true
|
|
6
|
+
EnforcedStyle: double_quotes
|
|
7
|
+
|
|
8
|
+
Style/StringLiteralsInInterpolation:
|
|
9
|
+
Enabled: true
|
|
10
|
+
EnforcedStyle: double_quotes
|
|
11
|
+
|
|
12
|
+
Layout/LineLength:
|
|
13
|
+
Max: 120
|
|
14
|
+
|
|
15
|
+
AllCops:
|
|
16
|
+
Exclude:
|
|
17
|
+
- 'spec/**/*'
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
# Specify your gem's dependencies in lapidario.gemspec
|
|
6
|
+
gemspec
|
|
7
|
+
|
|
8
|
+
group :development, :test do
|
|
9
|
+
gem "pry", "~> 0.14", require: true
|
|
10
|
+
|
|
11
|
+
gem "rake", "~> 13.0"
|
|
12
|
+
|
|
13
|
+
gem "rspec", "~> 3.0"
|
|
14
|
+
|
|
15
|
+
gem "rubocop", "~> 1.21"
|
|
16
|
+
end
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
lapidario (0.1.0alpha)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
ast (2.4.2)
|
|
10
|
+
coderay (1.1.3)
|
|
11
|
+
diff-lcs (1.5.0)
|
|
12
|
+
json (2.6.3)
|
|
13
|
+
language_server-protocol (3.17.0.3)
|
|
14
|
+
method_source (1.0.0)
|
|
15
|
+
parallel (1.23.0)
|
|
16
|
+
parser (3.2.2.4)
|
|
17
|
+
ast (~> 2.4.1)
|
|
18
|
+
racc
|
|
19
|
+
pry (0.14.2)
|
|
20
|
+
coderay (~> 1.1)
|
|
21
|
+
method_source (~> 1.0)
|
|
22
|
+
racc (1.7.3)
|
|
23
|
+
rainbow (3.1.1)
|
|
24
|
+
rake (13.1.0)
|
|
25
|
+
regexp_parser (2.8.2)
|
|
26
|
+
rexml (3.2.6)
|
|
27
|
+
rspec (3.12.0)
|
|
28
|
+
rspec-core (~> 3.12.0)
|
|
29
|
+
rspec-expectations (~> 3.12.0)
|
|
30
|
+
rspec-mocks (~> 3.12.0)
|
|
31
|
+
rspec-core (3.12.2)
|
|
32
|
+
rspec-support (~> 3.12.0)
|
|
33
|
+
rspec-expectations (3.12.3)
|
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
35
|
+
rspec-support (~> 3.12.0)
|
|
36
|
+
rspec-mocks (3.12.6)
|
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
38
|
+
rspec-support (~> 3.12.0)
|
|
39
|
+
rspec-support (3.12.1)
|
|
40
|
+
rubocop (1.57.2)
|
|
41
|
+
json (~> 2.3)
|
|
42
|
+
language_server-protocol (>= 3.17.0)
|
|
43
|
+
parallel (~> 1.10)
|
|
44
|
+
parser (>= 3.2.2.4)
|
|
45
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
46
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
47
|
+
rexml (>= 3.2.5, < 4.0)
|
|
48
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
|
49
|
+
ruby-progressbar (~> 1.7)
|
|
50
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
|
51
|
+
rubocop-ast (1.30.0)
|
|
52
|
+
parser (>= 3.2.1.0)
|
|
53
|
+
ruby-progressbar (1.13.0)
|
|
54
|
+
unicode-display_width (2.5.0)
|
|
55
|
+
|
|
56
|
+
PLATFORMS
|
|
57
|
+
x86_64-darwin-22
|
|
58
|
+
|
|
59
|
+
DEPENDENCIES
|
|
60
|
+
bundler (~> 2)
|
|
61
|
+
lapidario!
|
|
62
|
+
pry (~> 0.14)
|
|
63
|
+
rake (~> 13.0)
|
|
64
|
+
rspec (~> 3.0)
|
|
65
|
+
rubocop (~> 1.21)
|
|
66
|
+
|
|
67
|
+
BUNDLED WITH
|
|
68
|
+
2.4.10
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 octehren
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Lapidario
|
|
2
|
+
|
|
3
|
+
TODO: Delete this and the text below, and describe your gem
|
|
4
|
+
|
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/lapidario`. To experiment with that code, run `bin/console` for an interactive prompt.
|
|
6
|
+
|
|
7
|
+
## TO DO:
|
|
8
|
+
- [ ] Backup system: keep `Gemfile.original` stashed persistently
|
|
9
|
+
- [ ] Add option to ignore Gemfile lines with `# LOCK` commented on their right
|
|
10
|
+
- [ ] Normalize git gems with rubygems from Gemfile.lock
|
|
11
|
+
- [ ] Normalize gems from other sources with rubygems from Gemfile.lock
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
|
16
|
+
|
|
17
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
18
|
+
|
|
19
|
+
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
|
20
|
+
|
|
21
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
22
|
+
|
|
23
|
+
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
TODO: Write usage instructions here
|
|
28
|
+
|
|
29
|
+
## Development
|
|
30
|
+
|
|
31
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
32
|
+
|
|
33
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
34
|
+
|
|
35
|
+
## Contributing
|
|
36
|
+
|
|
37
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/lapidario.
|
|
38
|
+
|
|
39
|
+
## License
|
|
40
|
+
|
|
41
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "lapidario"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require "irb"
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/lapidario
ADDED
data/bin/setup
ADDED
data/lapidario.gemspec
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/lapidario/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "lapidario"
|
|
7
|
+
spec.version = Lapidario::VERSION
|
|
8
|
+
spec.authors = ["octehren"]
|
|
9
|
+
spec.email = ["ehren.dev.mail@gmail.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Auxiliary for bulk updates of gems in a project."
|
|
12
|
+
spec.description = "Lapidario is a Gemfile and Gemfile.lock static analyzer that helps with bulk updates of gems in a project. As of version 0.1, run it in a directory with both a Gemfile and Gemfile.lock to hard-code the locked versions in Gemfile.lock to the Gemfile."
|
|
13
|
+
spec.homepage = "https://example.com"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
|
+
|
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
+
spec.metadata["source_code_uri"] = "https://example.com"
|
|
21
|
+
spec.metadata["changelog_uri"] = "https://example.com" # Put your gem's CHANGELOG.md URL here.
|
|
22
|
+
|
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
27
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[test/ spec/ features/ .git .circleci appveyor])
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
# spec.bindir = "exe"
|
|
31
|
+
spec.require_paths = ["lib", "bin"]
|
|
32
|
+
spec.executables = ["lapidario"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# Uncomment to register a new dependency of your gem
|
|
36
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
|
37
|
+
spec.add_development_dependency "bundler", "~> 2"
|
|
38
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
39
|
+
|
|
40
|
+
# For more information and examples about making a new gem, check out our
|
|
41
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
42
|
+
end
|
data/lib/cli.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "optparse"
|
|
3
|
+
require_relative "lapidario"
|
|
4
|
+
|
|
5
|
+
module Lapidario
|
|
6
|
+
module CLI
|
|
7
|
+
def self.start(_cmd_args)
|
|
8
|
+
puts "cmd args: #{_cmd_args}"
|
|
9
|
+
project_path_hash = { project_path: './' }
|
|
10
|
+
info_instances = Lapidario.get_gemfile_and_lockfile_info(project_path_hash)
|
|
11
|
+
gemfile_info = info_instances[0]
|
|
12
|
+
lockfile_info = info_instances[1]
|
|
13
|
+
original_gemfile_lines = gemfile_info.original_gemfile
|
|
14
|
+
new_gemfile_info = Lapidario.hardcode_lockfile_versions_into_gemfile_info(gemfile_info, lockfile_info)
|
|
15
|
+
new_gemfile = Lapidario.build_new_gemfile(new_gemfile_info, original_gemfile_lines)
|
|
16
|
+
puts "New gemfile created:"
|
|
17
|
+
puts new_gemfile
|
|
18
|
+
puts "In case it does not look right, check for Gemfile.original in the same directory."
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/gemfile_info.rb
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "helper"
|
|
4
|
+
|
|
5
|
+
module Lapidario
|
|
6
|
+
class GemfileInfo
|
|
7
|
+
attr_accessor :gemfile_lines_info
|
|
8
|
+
attr_reader :original_gemfile
|
|
9
|
+
|
|
10
|
+
def initialize(gemfile_as_strings)
|
|
11
|
+
@original_gemfile = gemfile_as_strings
|
|
12
|
+
# array of hashes:
|
|
13
|
+
# { line_number: int; name: string; prepended_spaces: int;
|
|
14
|
+
# current_version: string; version_sign: string; extra_info: string}
|
|
15
|
+
@gemfile_lines_info = Lapidario::GemfileInfo.extract_gemfile_lines_info(gemfile_as_strings)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.get_gem_name(gem_name_item)
|
|
19
|
+
gem_name_item.sub("gem ", "").gsub("'", "").gsub('"', "")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# detects version field, removes it from array and returns it
|
|
23
|
+
def self.pop_version_field!(gemfile_line_items)
|
|
24
|
+
version_index = 0
|
|
25
|
+
version_number_and_sign = []
|
|
26
|
+
gemfile_line_items
|
|
27
|
+
.map { |item| item.gsub('"', "").gsub("'", "").gsub(" ", "") } # can be something like [" '~> 6.3'"]
|
|
28
|
+
.each_with_index do |item, index|
|
|
29
|
+
next unless Lapidario::Helper.version_fragment? item
|
|
30
|
+
|
|
31
|
+
version_number_and_sign = item
|
|
32
|
+
version_index = index
|
|
33
|
+
break # will break at first index, so if there is an upper range index later this won't affect results
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
return [] if version_number_and_sign.empty?
|
|
37
|
+
|
|
38
|
+
version_number = version_number_and_sign.gsub(/(~>|>=|<=|>|<)/, "")
|
|
39
|
+
version_sign = version_number_and_sign.gsub(/[^~>=<]/, "")
|
|
40
|
+
|
|
41
|
+
gemfile_line_items.delete_at(version_index)
|
|
42
|
+
[version_number, version_sign]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.gem_info(gemfile_line, line_index = -9999)
|
|
46
|
+
gem_info = { line_index: line_index, name: "", prepended_spaces: 0, current_version: "", version_sign: "", extra_info: "" }
|
|
47
|
+
# count prepended spaces to reuse on gemfile rebuild
|
|
48
|
+
gem_info[:prepended_spaces] = gemfile_line.match(/\A\s*/)[0].size
|
|
49
|
+
# splits on coma, removes prepended whitespaces if any
|
|
50
|
+
gemfile_line_items = gemfile_line.sub(/\A\s*/, '').split(",")
|
|
51
|
+
# first element will always be gem name, so return and remove it with shift; remove all spaces in edge case that gem has trailing spaces
|
|
52
|
+
gem_info[:name] = Lapidario::GemfileInfo.get_gem_name(gemfile_line_items.shift).gsub(' ','')
|
|
53
|
+
# second might not be the version number, so find the version, store it separetly and remove it from the rest of the line
|
|
54
|
+
version_number_and_sign = Lapidario::GemfileInfo.pop_version_field!(gemfile_line_items)
|
|
55
|
+
# to_s will make a nil value an empty string
|
|
56
|
+
gem_info[:current_version] = version_number_and_sign[0].to_s
|
|
57
|
+
gem_info[:version_sign] = version_number_and_sign[1].to_s
|
|
58
|
+
# in case version is ranged, run pop_version_field! again, just removing the field and appending it to the beginning of extra info, immediately after lower range.
|
|
59
|
+
version_upper_range = Lapidario::GemfileInfo.pop_version_field!(gemfile_line_items)
|
|
60
|
+
unless version_upper_range.empty?
|
|
61
|
+
gemfile_line_items.unshift("'#{version_upper_range[1]} #{version_upper_range[0]}'")
|
|
62
|
+
end
|
|
63
|
+
# all that's left is extra_info
|
|
64
|
+
gem_info[:extra_info] = gemfile_line_items.compact.join(", ").split(",").join(", ").gsub(/\s+/, " ").strip
|
|
65
|
+
gem_info
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.extract_gemfile_lines_info(gemfile_as_strings)
|
|
69
|
+
gemfile_lines = []
|
|
70
|
+
gemfile_as_strings.each_with_index do |line, index|
|
|
71
|
+
gemfile_lines << Lapidario::GemfileInfo.gem_info(line, index) if Lapidario::Helper.gem_line? line
|
|
72
|
+
end
|
|
73
|
+
gemfile_lines
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# gi = gem_info
|
|
77
|
+
def self.build_gemfile_line(gi)
|
|
78
|
+
line = "#{' ' * gi[:prepended_spaces].to_i}gem '#{gi[:name]}'"
|
|
79
|
+
if gi[:current_version]
|
|
80
|
+
version_fragment = "#{gi[:current_version]}"
|
|
81
|
+
version_fragment = "#{gi[:version_sign]} " + version_fragment if gi[:version_sign]
|
|
82
|
+
line = line + ", '#{version_fragment}'"
|
|
83
|
+
end
|
|
84
|
+
line = line + ", #{gi[:extra_info]}" if gi[:extra_info] && !gi[:extra_info].empty?
|
|
85
|
+
line
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
data/lib/helper.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Lapidario
|
|
6
|
+
module Helper
|
|
7
|
+
# regex to match the version fragment in a Gemfile, such as '~> 0.21', '1.2', '>= 10.2.1', '1.2alpha' etc;
|
|
8
|
+
@@GEM_VERSION_FRAGMENT = /^\s*([<>]=?|~>)?\s*[0-9a-zA-Z\s.]+\s*$/
|
|
9
|
+
@@DETECT_GEMFILE_IN_PATH = /\/Gemfile/
|
|
10
|
+
@@DETECT_LOCKFILE_IN_PATH = /\/Gemfile\.lock/
|
|
11
|
+
|
|
12
|
+
def self.version_fragment?(line_section)
|
|
13
|
+
line_section.match? @@GEM_VERSION_FRAGMENT
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.gem_line?(gemfile_line)
|
|
17
|
+
gemfile_line.match?(/^\s*gem\s+["']([^"']+)["']/)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# formats based on depth; ex: version_fragment = '3.12.4' with depth 2 returns 3.12
|
|
21
|
+
def self.format_version_based_on_depth(version_fragment, depth = 2)
|
|
22
|
+
raise Lapidario::Error, "Tried to format #{version_fragment} with inadequate depth '#{depth}'." unless depth >= 1 && depth <= 3
|
|
23
|
+
version_fragment.split(".").slice(0, depth).join(".")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.format_path(filepath, for_lockfile = false)
|
|
27
|
+
# path can be ./project/, ./project or ./project/Gemfile, but never ./project/Gemfile/
|
|
28
|
+
appendage = ""
|
|
29
|
+
appendage = "/" unless (filepath =~ /\/$/ or filepath =~ @@DETECT_GEMFILE_IN_PATH) # checks if path finishes on '/' or if it contains Gemfile (also valid for lockfile)
|
|
30
|
+
unless for_lockfile
|
|
31
|
+
appendage = appendage + "Gemfile" unless filepath =~ @@DETECT_GEMFILE_IN_PATH
|
|
32
|
+
else
|
|
33
|
+
appendage = appendage + "Gemfile.lock" unless filepath =~ @@DETECT_LOCKFILE_IN_PATH
|
|
34
|
+
end
|
|
35
|
+
filepath + appendage
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.save_file(save_path, content)
|
|
39
|
+
File.write(save_path, content)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.get_file_as_array_of_lines(filepath)
|
|
43
|
+
begin
|
|
44
|
+
File.read(filepath).split("\n")
|
|
45
|
+
rescue => e
|
|
46
|
+
raise Lapidario::Error, "#{e.message}\n\nDouble-check the path provided for the Gemfile or Gemfile.lock\nProvided path:\n#{filepath}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Lockfile-focused helpers
|
|
51
|
+
def self.slice_up_to_next_empty_line(initial_index, lines_array)
|
|
52
|
+
final_index = -1
|
|
53
|
+
(initial_index...lines_array.size).each do |i|
|
|
54
|
+
final_index = i if lines_array[i].empty?
|
|
55
|
+
end
|
|
56
|
+
raise Lapidario::Error, "Gemfile.lock should have an empty line as the last line in the file." if final_index < 0
|
|
57
|
+
lines_array.slice(initial_index, final_index)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# a primary gem line will always begin with 4 whitespaces.
|
|
61
|
+
def self.lockfile_primary_gem_line?(line)
|
|
62
|
+
# \A: Asserts the start of the string.
|
|
63
|
+
# \x20: represents a whitespace character; whitespace is char 32 in ascii, 20 is 32 in hex
|
|
64
|
+
# {4}: Indicates exactly 4 occurrences of the preceding character (whitespace in this case).
|
|
65
|
+
line.match?(/\A\x20{4}[A-Za-z0-9]/)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/lapidario.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require_relative "lapidario/version"
|
|
3
|
+
require_relative "helper"
|
|
4
|
+
require_relative "lockfile_info"
|
|
5
|
+
require_relative "gemfile_info"
|
|
6
|
+
|
|
7
|
+
module Lapidario
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
######################
|
|
11
|
+
## shared processes ## ex: steps for specific processes, used more than once
|
|
12
|
+
######################
|
|
13
|
+
|
|
14
|
+
# first step: build gemfile and lockfile info instances
|
|
15
|
+
# input: project_path_hash; has either :project_path key or both :gemfile_path and :lockfile_path; returns GemfileInfo and LockfileInfo instances
|
|
16
|
+
def self.get_gemfile_and_lockfile_info(project_path_hash)
|
|
17
|
+
project_path = project_path_hash[:project_path]
|
|
18
|
+
if (project_path && !project_path.empty?)
|
|
19
|
+
gemfile_path, lockfile_path = Lapidario::Helper.format_path(project_path, false), Lapidario::Helper.format_path(project_path, true)
|
|
20
|
+
elsif !(project_path_hash[:gemfile_path] && !project_path_hash[:gemfile_path].empty?) && !(project_path_hash[:lockfile_path] && !project_path_hash[:lockfile_path].empty?)
|
|
21
|
+
raise Lapidario::Error, "Double-check input for project path."
|
|
22
|
+
else
|
|
23
|
+
gemfile_path, lockfile_path = Lapidario::Helper.format_path(project_path_hash[:gemfile_path], false), Lapidario::Helper.format_path(project_path_hash[:lockfile_path], true)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
gemfile_info = Lapidario::GemfileInfo.new(Lapidario::Helper.get_file_as_array_of_lines(gemfile_path))
|
|
27
|
+
lockfile_info = Lapidario::LockfileInfo.new(Lapidario::Helper.get_file_as_array_of_lines(lockfile_path))
|
|
28
|
+
[gemfile_info, lockfile_info]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# semi-final step: build new temporary gemfile, replacing changed lines in the original; intermediary object will be altered by one of the methods at the bottom of the page
|
|
32
|
+
def self.build_new_gemfile(new_gemfile_info, original_gemfile_lines)
|
|
33
|
+
new_gemfile = original_gemfile_lines.clone
|
|
34
|
+
new_gemfile_info.each do |info_item|
|
|
35
|
+
new_line = Lapidario::GemfileInfo.build_gemfile_line(info_item)
|
|
36
|
+
new_gemfile[info_item[:line_index]] = new_line
|
|
37
|
+
end
|
|
38
|
+
new_gemfile
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# final step: save new, backup old
|
|
42
|
+
def self.save_gemfiles(save_path, new_gemfile, original_gemfile)
|
|
43
|
+
# save original gemfile as backup
|
|
44
|
+
original_save_path = Lapidario::Helper.format_path(save_path) + ".original"
|
|
45
|
+
Lapidario::Helper.save_file(original_save_path, original_gemfile.join("\n"))
|
|
46
|
+
# overwrite current Gemfile with new content
|
|
47
|
+
new_save_path = Lapidario::Helper.format_path(save_path)
|
|
48
|
+
Lapidario::Helper.save_file(new_save_path, new_gemfile.join("\n"))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
######################
|
|
52
|
+
# specific processes # ex: specific functionality achieved through composition of shared processes
|
|
53
|
+
######################
|
|
54
|
+
|
|
55
|
+
# loops through lockfile info, collecting versions
|
|
56
|
+
# hard-codes these versions on gemfile, as they might differ from the lockfile's
|
|
57
|
+
# will use '~>' as default sign and 2 as default depth
|
|
58
|
+
def self.hardcode_lockfile_versions_into_gemfile_info(gemfile_info, lockfile_info, default_sign = '~>', default_depth = 2)
|
|
59
|
+
new_gemfile_info = gemfile_info.gemfile_lines_info.clone
|
|
60
|
+
lockfile_primary_gems = lockfile_info.primary_gems
|
|
61
|
+
# replace versions in gemfile with ones on lockfile
|
|
62
|
+
new_gemfile_info.each do |gem_info|
|
|
63
|
+
lock_version = lockfile_primary_gems[gem_info[:name]]
|
|
64
|
+
if lock_version
|
|
65
|
+
gem_info[:current_version] = lock_version
|
|
66
|
+
gem_info[:current_version] = Lapidario::Helper.format_version_based_on_depth(lock_version, default_depth) if default_depth
|
|
67
|
+
gem_info[:version_sign] = default_sign if default_sign && !default_sign.empty?
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
new_gemfile_info
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "helper"
|
|
4
|
+
|
|
5
|
+
module Lapidario
|
|
6
|
+
class LockfileInfo
|
|
7
|
+
attr_accessor :primary_gems
|
|
8
|
+
|
|
9
|
+
def initialize(gemfile_lock_as_strings)
|
|
10
|
+
@git_gems = []
|
|
11
|
+
@rubygems_gems = Lapidario::LockfileInfo.get_rubygems_from_gemfile_lock(gemfile_lock_as_strings)
|
|
12
|
+
# joins gem names and versions from git/rubygems/other sources in a single format
|
|
13
|
+
@primary_gems = @rubygems_gems
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def puts_versionless_rubygems_info
|
|
17
|
+
versionless_gems = []
|
|
18
|
+
@rubygems_gems.each do |gem, version|
|
|
19
|
+
versionless_gems << [gem, version] if version.nil? || version.empty?
|
|
20
|
+
end
|
|
21
|
+
print "#{versionless_gems.join("\n")}\nThere are #{versionless_gems.size} gems without specified version, names are listed above."
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def git_gems?
|
|
25
|
+
puts "TODO"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# gets gems installed from rubygems; in the future check also for other remote sources
|
|
29
|
+
def self.get_rubygems_from_gemfile_lock(gemfile_lock_as_strings)
|
|
30
|
+
gem_section = []
|
|
31
|
+
gem_names_and_versions = {}
|
|
32
|
+
gemfile_lock_as_strings.each_with_index do |line, index|
|
|
33
|
+
gem_section = Helper.slice_up_to_next_empty_line(index, gemfile_lock_as_strings) if line == "GEM"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if gem_section.empty?
|
|
37
|
+
raise "#{gemfile_lock_as_strings.join("\n")}\n\nEND OF OUTPUT\nA line consisting of a single 'GEM' string with no further chars wasn't found. See output above."
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
gem_section.each do |line|
|
|
41
|
+
next unless Lapidario::Helper.lockfile_primary_gem_line? line
|
|
42
|
+
|
|
43
|
+
gem_name_and_version = line.clone.strip.split(" ")
|
|
44
|
+
name = gem_name_and_version[0]
|
|
45
|
+
version = gem_name_and_version[1]
|
|
46
|
+
gem_names_and_versions[name] = version ? version.gsub(/[()]/, "") : ""
|
|
47
|
+
end
|
|
48
|
+
gem_names_and_versions
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/sig/lapidario.rbs
ADDED
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lapidario
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2alpha.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- octehren
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2023-12-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.12'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.12'
|
|
41
|
+
description: Lapidario is a Gemfile and Gemfile.lock static analyzer that helps with
|
|
42
|
+
bulk updates of gems in a project. As of version 0.1, run it in a directory with
|
|
43
|
+
both a Gemfile and Gemfile.lock to hard-code the locked versions in Gemfile.lock
|
|
44
|
+
to the Gemfile.
|
|
45
|
+
email:
|
|
46
|
+
- ehren.dev.mail@gmail.com
|
|
47
|
+
executables:
|
|
48
|
+
- lapidario
|
|
49
|
+
extensions: []
|
|
50
|
+
extra_rdoc_files: []
|
|
51
|
+
files:
|
|
52
|
+
- ".rspec"
|
|
53
|
+
- ".rubocop.yml"
|
|
54
|
+
- CHANGELOG.md
|
|
55
|
+
- Gemfile
|
|
56
|
+
- Gemfile.lock
|
|
57
|
+
- LICENSE.txt
|
|
58
|
+
- README.md
|
|
59
|
+
- Rakefile
|
|
60
|
+
- bin/console
|
|
61
|
+
- bin/lapidario
|
|
62
|
+
- bin/setup
|
|
63
|
+
- lapidario.gemspec
|
|
64
|
+
- lib/cli.rb
|
|
65
|
+
- lib/gemfile_info.rb
|
|
66
|
+
- lib/helper.rb
|
|
67
|
+
- lib/lapidario.rb
|
|
68
|
+
- lib/lapidario/version.rb
|
|
69
|
+
- lib/lockfile_info.rb
|
|
70
|
+
- sig/lapidario.rbs
|
|
71
|
+
homepage: https://example.com
|
|
72
|
+
licenses:
|
|
73
|
+
- MIT
|
|
74
|
+
metadata:
|
|
75
|
+
allowed_push_host: https://rubygems.org
|
|
76
|
+
homepage_uri: https://example.com
|
|
77
|
+
source_code_uri: https://example.com
|
|
78
|
+
changelog_uri: https://example.com
|
|
79
|
+
post_install_message:
|
|
80
|
+
rdoc_options: []
|
|
81
|
+
require_paths:
|
|
82
|
+
- lib
|
|
83
|
+
- bin
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: 2.6.0
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">"
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 1.3.1
|
|
94
|
+
requirements: []
|
|
95
|
+
rubygems_version: 3.4.10
|
|
96
|
+
signing_key:
|
|
97
|
+
specification_version: 4
|
|
98
|
+
summary: Auxiliary for bulk updates of gems in a project.
|
|
99
|
+
test_files: []
|