gel 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +39 -0
  5. data/exe/gel +13 -0
  6. data/lib/gel.rb +22 -0
  7. data/lib/gel/catalog.rb +153 -0
  8. data/lib/gel/catalog/common.rb +82 -0
  9. data/lib/gel/catalog/compact_index.rb +152 -0
  10. data/lib/gel/catalog/dependency_index.rb +125 -0
  11. data/lib/gel/catalog/legacy_index.rb +157 -0
  12. data/lib/gel/catalog/marshal_hacks.rb +16 -0
  13. data/lib/gel/command.rb +86 -0
  14. data/lib/gel/command/config.rb +11 -0
  15. data/lib/gel/command/env.rb +7 -0
  16. data/lib/gel/command/exec.rb +66 -0
  17. data/lib/gel/command/help.rb +7 -0
  18. data/lib/gel/command/install.rb +7 -0
  19. data/lib/gel/command/install_gem.rb +16 -0
  20. data/lib/gel/command/lock.rb +34 -0
  21. data/lib/gel/command/ruby.rb +10 -0
  22. data/lib/gel/command/shell_setup.rb +25 -0
  23. data/lib/gel/command/stub.rb +12 -0
  24. data/lib/gel/command/update.rb +11 -0
  25. data/lib/gel/compatibility.rb +4 -0
  26. data/lib/gel/compatibility/bundler.rb +54 -0
  27. data/lib/gel/compatibility/bundler/cli.rb +6 -0
  28. data/lib/gel/compatibility/bundler/friendly_errors.rb +3 -0
  29. data/lib/gel/compatibility/bundler/setup.rb +4 -0
  30. data/lib/gel/compatibility/rubygems.rb +192 -0
  31. data/lib/gel/compatibility/rubygems/command.rb +4 -0
  32. data/lib/gel/compatibility/rubygems/dependency_installer.rb +0 -0
  33. data/lib/gel/compatibility/rubygems/gem_runner.rb +6 -0
  34. data/lib/gel/config.rb +80 -0
  35. data/lib/gel/db.rb +294 -0
  36. data/lib/gel/direct_gem.rb +29 -0
  37. data/lib/gel/environment.rb +592 -0
  38. data/lib/gel/error.rb +104 -0
  39. data/lib/gel/gemfile_parser.rb +144 -0
  40. data/lib/gel/gemspec_parser.rb +95 -0
  41. data/lib/gel/git_catalog.rb +38 -0
  42. data/lib/gel/git_depot.rb +119 -0
  43. data/lib/gel/httpool.rb +148 -0
  44. data/lib/gel/installer.rb +251 -0
  45. data/lib/gel/lock_loader.rb +164 -0
  46. data/lib/gel/lock_parser.rb +64 -0
  47. data/lib/gel/locked_store.rb +126 -0
  48. data/lib/gel/multi_store.rb +96 -0
  49. data/lib/gel/package.rb +156 -0
  50. data/lib/gel/package/inspector.rb +23 -0
  51. data/lib/gel/package/installer.rb +267 -0
  52. data/lib/gel/path_catalog.rb +44 -0
  53. data/lib/gel/pinboard.rb +140 -0
  54. data/lib/gel/pub_grub/preference_strategy.rb +82 -0
  55. data/lib/gel/pub_grub/source.rb +153 -0
  56. data/lib/gel/runtime.rb +27 -0
  57. data/lib/gel/store.rb +205 -0
  58. data/lib/gel/store_catalog.rb +31 -0
  59. data/lib/gel/store_gem.rb +80 -0
  60. data/lib/gel/stub_set.rb +51 -0
  61. data/lib/gel/support/gem_platform.rb +225 -0
  62. data/lib/gel/support/gem_requirement.rb +264 -0
  63. data/lib/gel/support/gem_version.rb +398 -0
  64. data/lib/gel/support/tar.rb +13 -0
  65. data/lib/gel/support/tar/tar_header.rb +229 -0
  66. data/lib/gel/support/tar/tar_reader.rb +123 -0
  67. data/lib/gel/support/tar/tar_reader/entry.rb +154 -0
  68. data/lib/gel/support/tar/tar_writer.rb +339 -0
  69. data/lib/gel/tail_file.rb +205 -0
  70. data/lib/gel/version.rb +5 -0
  71. data/lib/gel/work_pool.rb +143 -0
  72. data/man/man1/gel-exec.1 +16 -0
  73. data/man/man1/gel-install.1 +16 -0
  74. data/man/man1/gel.1 +30 -0
  75. metadata +131 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Help < Gel::Command
4
+ def run(command_line)
5
+ raise "TODO"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Install < Gel::Command
4
+ def run(command_line)
5
+ Gel::Environment.activate(install: true, output: $stderr)
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::InstallGem < Gel::Command
4
+ def run(command_line)
5
+ gem_name, gem_version = command_line
6
+
7
+ require_relative "../catalog"
8
+ require_relative "../work_pool"
9
+
10
+ Gel::WorkPool.new(2) do |work_pool|
11
+ catalog = Gel::Catalog.new("https://rubygems.org", work_pool: work_pool)
12
+
13
+ Gel::Environment.install_gem([catalog], gem_name, gem_version, output: $stderr)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Lock < Gel::Command
4
+ def run(command_line)
5
+ options = {}
6
+
7
+ mode = :hold
8
+ strict = false
9
+ overrides = {}
10
+
11
+ until command_line.empty?
12
+ case argument = command_line.shift
13
+ when "--strict"; strict = true
14
+ when "--major"; mode = :major
15
+ when "--minor"; mode = :minor
16
+ when "--patch"; mode = :patch
17
+ when "--hold"; mode = :hold
18
+ when /\A--lockfile(?:=(.*))?\z/
19
+ options[:lockfile] = $1 || command_line.shift
20
+ when /\A((?!-)[A-Za-z0-9_-]+)(?:(?:[\ :\/]|(?=[<>~=]))([<>~=,\ 0-9A-Za-z.-]+))?\z/x
21
+ overrides[$1] = Gel::Support::GemRequirement.new($2 ? $2.split(/\s+(?=[0-9])|\s*,\s*/) : [])
22
+ else
23
+ raise "Unknown argument #{argument.inspect}"
24
+ end
25
+ end
26
+
27
+ require_relative "../pub_grub/preference_strategy"
28
+ options[:preference_strategy] = lambda do |loader|
29
+ Gel::PubGrub::PreferenceStrategy.new(loader, overrides, bump: mode, strict: strict)
30
+ end
31
+
32
+ Gel::Environment.lock(output: $stderr, **options)
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Ruby < Gel::Command
4
+ def run(command_line)
5
+ command = Gel::Command::Exec.new
6
+ command.run(["ruby", *command_line])
7
+ ensure
8
+ self.reraise = command.reraise if command
9
+ end
10
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::ShellSetup < Gel::Command
4
+ def run(command_line)
5
+ require "shellwords"
6
+
7
+ variables = []
8
+
9
+ bin_dir = File.expand_path("~/.local/gel/bin")
10
+ unless ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).include?(bin_dir)
11
+ puts "PATH=\"#{Shellwords.shellescape bin_dir}#{File::PATH_SEPARATOR}$PATH\""
12
+ variables << "PATH"
13
+ end
14
+
15
+ lib_dir = File.expand_path("../compatibility", __dir__)
16
+ unless ENV.fetch("RUBYLIB", "").split(File::PATH_SEPARATOR).include?(lib_dir)
17
+ puts "RUBYLIB=\"#{Shellwords.shellescape lib_dir}:$RUBYLIB\""
18
+ variables << "RUBYLIB"
19
+ end
20
+
21
+ unless variables.empty?
22
+ puts "export #{variables.join(" ")}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Stub < Gel::Command
4
+ def run(command_line)
5
+ stub_command, _path, *arguments = command_line
6
+
7
+ command = Gel::Command::Exec.new
8
+ command.run([stub_command, *arguments], from_stub: true)
9
+ ensure
10
+ self.reraise = command.reraise if command
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Command::Update < Gel::Command
4
+ def run(command_line)
5
+ # Mega update mode
6
+ command_line = ["--major"] if command_line.empty?
7
+
8
+ Gel::Command::Lock.new.run(command_line)
9
+ Gel::Environment.activate(install: true, output: $stderr)
10
+ end
11
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ $:[0, 0] = File.expand_path("compatibility", __dir__)
4
+ require_relative "compatibility/rubygems"
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ def self.setup
5
+ Gel::Environment.activate(output: $stderr)
6
+ end
7
+
8
+ def self.require(*groups)
9
+ Gel::Environment.require_groups(*groups)
10
+ end
11
+
12
+ def self.default_lockfile
13
+ Pathname.new(Gel::Environment.lockfile_name)
14
+ end
15
+
16
+ module Rubygems
17
+ def self.loaded_specs(gem_name)
18
+ Gem::Specification.new(Gel::Environment.activated_gems[gem_name])
19
+ end
20
+ end
21
+
22
+ # This is only emulated for bin/spring: we really don't want to try to
23
+ # actually reproduce Bundler's API
24
+ class LockfileParser
25
+ def initialize(content)
26
+ end
27
+
28
+ def specs
29
+ []
30
+ end
31
+ end
32
+
33
+ def self.rubygems
34
+ Rubygems
35
+ end
36
+
37
+ def self.with_original_env
38
+ # TODO
39
+ yield
40
+ end
41
+
42
+ def self.with_clean_env
43
+ # TODO
44
+ yield
45
+ end
46
+
47
+ def self.settings
48
+ if gemfile = Gel::Environment.gemfile
49
+ { "gemfile" => gemfile.filename }
50
+ else
51
+ {}
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,6 @@
1
+ # We assume this file is only required by the `bundle` executable: if we
2
+ # get here, we need to re-exec it without Gel on the path, to ensure it
3
+ # has a full and proper Rubygems environment to work with.
4
+
5
+ ENV["RUBYLIB"] = Gel::Environment.original_rubylib
6
+ exec RbConfig.ruby, "--", $0, *ARGV
@@ -0,0 +1,3 @@
1
+ def Bundler.with_friendly_errors
2
+ yield
3
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../bundler"
4
+ Bundler.setup
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The goal here is not to be a full drop-in replacement of RubyGems'
4
+ # API.
5
+ #
6
+ # The threshold is basically "things that already-popular/established
7
+ # gems assume are there without checking".
8
+
9
+ require_relative "../runtime"
10
+
11
+ module Gem
12
+ Version = Gel::Support::GemVersion
13
+ Requirement = Gel::Support::GemRequirement
14
+
15
+ class Dependency
16
+ attr_reader :name
17
+ attr_reader :requirement
18
+ attr_reader :type
19
+
20
+ def initialize(name, requirement, type)
21
+ @name = name
22
+ @requirement = requirement
23
+ @type = type
24
+ end
25
+ end
26
+
27
+ LoadError = Class.new(::LoadError)
28
+
29
+ class Specification
30
+ def self.find_by_name(name, *requirements)
31
+ if g = Gel::Environment.find_gem(name, *requirements)
32
+ new(g)
33
+ else
34
+ # TODO: Should probably be a Gel exception instead?
35
+ raise Gem::LoadError, "Unable to find gem #{name.inspect}" + (requirements.empty? ? "" : " (#{requirements.join(", ")})")
36
+ end
37
+ end
38
+
39
+ def self.each(&block)
40
+ Gel::Environment.store.each.map { |g| new(g) }.each(&block)
41
+ end
42
+
43
+ def initialize(store_gem)
44
+ @store_gem = store_gem
45
+ end
46
+
47
+ def name
48
+ @store_gem.name
49
+ end
50
+
51
+ def version
52
+ Gem::Version.new(@store_gem.version)
53
+ end
54
+
55
+ def dependencies
56
+ @store_gem.dependencies.map do |name, pairs|
57
+ Gem::Dependency.new(name, pairs.map { |op, ver| "#{op} #{ver}" }, :runtime)
58
+ end
59
+ end
60
+ alias runtime_dependencies dependencies
61
+
62
+ def gem_dir
63
+ @store_gem.root
64
+ end
65
+ alias full_gem_path gem_dir
66
+
67
+ def require_paths
68
+ base = Pathname.new(gem_dir)
69
+
70
+ @store_gem.require_paths.map do |path|
71
+ Pathname.new(path).relative_path_from(base).to_s
72
+ end
73
+ end
74
+ end
75
+
76
+ class DependencyInstaller
77
+ def install(name, requirement = nil)
78
+ require_relative "../catalog"
79
+ require_relative "../work_pool"
80
+
81
+ Gel::WorkPool.new(2) do |work_pool|
82
+ catalog = Gel::Catalog.new("https://rubygems.org", work_pool: work_pool)
83
+
84
+ return Gel::Environment.install_gem([catalog], name, requirement)
85
+ end
86
+ end
87
+ end
88
+
89
+ def self.try_activate(file)
90
+ Gel::Environment.resolve_gem_path(file) != file
91
+ rescue LoadError
92
+ false
93
+ end
94
+
95
+ def self.ruby
96
+ RbConfig.ruby
97
+ end
98
+
99
+ def self.win_platform?
100
+ false
101
+ end
102
+
103
+ def self.loaded_specs
104
+ result = {}
105
+ Gel::Environment.activated_gems.each do |name, store_gem|
106
+ result[name] = Gem::Specification.new(store_gem)
107
+ end
108
+ result
109
+ end
110
+
111
+ def self.find_files(pattern)
112
+ Gel::Environment.store.each.
113
+ flat_map(&:require_paths).
114
+ flat_map { |dir| Dir[File.join(dir, pattern)] }
115
+ end
116
+
117
+ def self.refresh
118
+ # no-op
119
+ end
120
+
121
+ def self.path
122
+ Gel::Environment.store.paths
123
+ end
124
+
125
+ def self.default_dir
126
+ path.first
127
+ end
128
+
129
+ def self.activate_bin_path(gem_name, bin_name, version = nil)
130
+ if gem_name == "bundler" && bin_name == "bundle"
131
+ # Extra-special case: this is the bundler binstub, we need to
132
+ # re-exec to hand over.
133
+
134
+ ENV["RUBYLIB"] = Gel::Environment.original_rubylib
135
+ exec RbConfig.ruby, "--", $0, *ARGV
136
+ end
137
+
138
+ if g = Gel::Environment.activated_gems[gem_name]
139
+ Gel::Environment.gem g.name, version if version
140
+ elsif g = Gel::Environment.find_gem(gem_name, *version) do |g|
141
+ g.executables.include?(bin_name)
142
+ end
143
+
144
+ Gel::Environment.gem g.name, g.version
145
+ elsif g = Gel::Environment.find_gem(gem_name, *version)
146
+ raise "#{g.name} (#{g.version}) doesn't contain executable #{bin_name.inspect}"
147
+ elsif version && Gel::Environment.find_gem(gem_name)
148
+ raise "#{gem_name} (#{version}) not available"
149
+ else
150
+ raise "Unknown gem #{gem_name.inspect}"
151
+ end
152
+
153
+ Gel::Environment.find_executable(bin_name, g.name, g.version)
154
+ rescue => ex
155
+ # This method may be our entry-point, if we're being invoked by a
156
+ # rubygems binstub. Detect that situation, and provide nicer error
157
+ # reporting.
158
+
159
+ raise unless locations = caller_locations(2, 2)
160
+ raise unless locations.size == 1
161
+ raise unless path = locations.first.absolute_path
162
+ raise unless File.exist?(path) && File.readable?(path)
163
+ raise unless File.open(path, "rb") { |f| f.read(1024).include?("\n# This file was generated by RubyGems.\n") }
164
+
165
+ require_relative "../command"
166
+ Gel::Command.handle_error(ex)
167
+ end
168
+
169
+ def self.bin_path(gem_name, bin_name, version = nil)
170
+ if g = Gel::Environment.activated_gems[gem_name]
171
+ Gel::Environment.gem g.name, version if version
172
+
173
+ Gel::Environment.find_executable(bin_name, g.name, g.version)
174
+ elsif Gel::Environment.find_gem(gem_name)
175
+ raise "Gem #{gem_name.inspect} is not active"
176
+ else
177
+ raise "Unknown gem #{gem_name.inspect}"
178
+ end
179
+ end
180
+ end
181
+
182
+ def gem(*args)
183
+ Gel::Environment.gem(*args)
184
+ end
185
+ private :gem
186
+
187
+ def require(path)
188
+ super Gel::Environment.resolve_gem_path(path)
189
+ end
190
+ private :require
191
+
192
+ require "rubygems/deprecate"
@@ -0,0 +1,4 @@
1
+ module Gem::Command
2
+ def self.build_args=(value)
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ # We assume this file is only required by the `gem` executable: if we
2
+ # get here, we need to re-exec it without Gel on the path, to ensure it
3
+ # has a full and proper Rubygems environment to work with.
4
+
5
+ ENV["RUBYLIB"] = Gel::Environment.original_rubylib
6
+ exec RbConfig.ruby, "--", $0, *ARGV
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::Config
4
+ def initialize
5
+ @root = File.expand_path("~/.config/gel")
6
+ @path = File.join(@root, "config")
7
+ @config = nil
8
+ end
9
+
10
+ def config
11
+ @config ||= read
12
+ end
13
+
14
+ def [](group = nil, key)
15
+ if group.nil?
16
+ group, key = key.split(".", 2)
17
+ end
18
+
19
+ (group ? (config[group.to_s] || {}) : config)[key.to_s]
20
+ end
21
+
22
+ def []=(group = nil, key, value)
23
+ if group.nil?
24
+ group, key = key.split(".", 2)
25
+ end
26
+
27
+ (group ? (config[group.to_s] ||= {}) : config)[key.to_s] = value.to_s
28
+
29
+ write(config)
30
+ end
31
+
32
+ private
33
+
34
+ def read
35
+ result = {}
36
+ if File.exist?(@path)
37
+ context = nil
38
+ File.read(@path).each_line do |line|
39
+ line.chomp!
40
+ if line =~ /\A(\S[^:]*):\z/
41
+ context = result[$1] = {}
42
+ elsif line =~ /\A ([^:]*): (.*)\z/
43
+ context[$1] = $2
44
+ elsif line =~ /\A([^:]*): (.*)\z/
45
+ result[$1] = $2
46
+ elsif line =~ /\A\s*(?:#|\z)/
47
+ # comment / empty
48
+ else
49
+ raise "Unexpected config line #{line.inspect}"
50
+ end
51
+ end
52
+ end
53
+ result
54
+ end
55
+
56
+ def write(data)
57
+ Dir.mkdir(@root) unless Dir.exist?(@root)
58
+
59
+ tempfile = File.join(@root, ".config.#{Process.pid}")
60
+ File.open(tempfile, "w", 0644) do |f|
61
+ data.each do |key, value|
62
+ next if value.is_a?(Hash)
63
+ f.puts("#{key}: #{value}")
64
+ end
65
+
66
+ data.each do |key, value|
67
+ next unless value.is_a?(Hash)
68
+ f.puts
69
+ f.puts("#{key}:")
70
+ value.each do |subkey, subvalue|
71
+ f.puts(" #{subkey}: #{subvalue}")
72
+ end
73
+ end
74
+ end
75
+
76
+ File.rename(tempfile, @path)
77
+ ensure
78
+ File.unlink(tempfile) if File.exist?(tempfile)
79
+ end
80
+ end