gel 0.2.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.
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,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "strscan"
4
+
5
+ class Gel::LockParser
6
+ def parse(content)
7
+ sections = []
8
+
9
+ scanner = StringScanner.new(content)
10
+ while section = scanner.scan(/^(\w.+)\n/)
11
+ section.chomp!
12
+ case section
13
+ when "GIT", "PATH", "GEM"
14
+ content = {}
15
+ while scanner.skip(/^ \b/)
16
+ label = scanner.scan(/[^:]+:/).chop
17
+ if scanner.skip(/ /)
18
+ value = scanner.scan(/.*/)
19
+ scanner.skip(/\n/)
20
+ (content[label] ||= []) << value
21
+ else
22
+ scanner.skip(/\n/)
23
+ value = []
24
+ while scanner.skip(/^ \b/)
25
+ entry = scanner.scan(/.*/)
26
+ scanner.skip(/\n/)
27
+ children = []
28
+ while scanner.skip(/^ \b/)
29
+ child = scanner.scan(/.*/)
30
+ children << child
31
+ scanner.skip(/\n/)
32
+ end
33
+ if children.empty?
34
+ value << [entry]
35
+ else
36
+ value << [entry, children]
37
+ end
38
+ end
39
+ content[label] = value
40
+ end
41
+ end
42
+ when "PLATFORMS", "DEPENDENCIES"
43
+ content = []
44
+ while scanner.skip(/^ \b/)
45
+ entry = scanner.scan(/.*/)
46
+ content << entry
47
+ scanner.skip(/\n/)
48
+ end
49
+ when "BUNDLED WITH"
50
+ content = []
51
+ while scanner.skip(/^ \b/)
52
+ entry = scanner.scan(/.*/)
53
+ content << entry
54
+ scanner.skip(/\n/)
55
+ end
56
+ end
57
+ scanner.skip(/\n+/)
58
+
59
+ sections << [section, content]
60
+ end
61
+
62
+ sections
63
+ end
64
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Gel::LockedStore
4
+ attr_reader :inner
5
+
6
+ def initialize(inner)
7
+ @inner = inner
8
+ @locked_versions = nil
9
+
10
+ @lib_cache = Hash.new { |h, k| h[k] = [] }
11
+ @full_cache = false
12
+ end
13
+
14
+ def paths
15
+ @inner.paths
16
+ end
17
+
18
+ def root
19
+ @inner.root
20
+ end
21
+
22
+ def inspect
23
+ content = @locked_versions.map { |name, version| "#{name}=#{version.is_a?(String) ? version : version.root}" }
24
+ content = ["(none)"] if content.empty?
25
+ content.sort!
26
+
27
+ "#<#{self.class} inner=#{@inner.inspect} locks=#{content.join(",")}>"
28
+ end
29
+
30
+ def prepare(locks)
31
+ return if @full_cache
32
+
33
+ inner_versions = {}
34
+ locks.each do |name, version|
35
+ if version.is_a?(Gel::StoreGem)
36
+ version.libs do |file, subdir|
37
+ @lib_cache[file] << [version, subdir]
38
+ end
39
+ else
40
+ inner_versions[name] = version
41
+ end
42
+ end
43
+
44
+ g = @inner.gems(inner_versions)
45
+ @inner.libs_for_gems(inner_versions) do |name, version, subs|
46
+ subs.each do |subdir, files|
47
+ v = [g[name], subdir]
48
+ files.each do |file|
49
+ @lib_cache[file] << v
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ def lock(locks)
56
+ @locked_versions = locks.dup
57
+ prepare(locks)
58
+ @full_cache = true
59
+ end
60
+
61
+ def locked?(gem)
62
+ !@locked_versions || @locked_versions[gem.name] == gem.version
63
+ end
64
+
65
+ def locked_gems
66
+ @locked_versions ? @locked_versions.values.grep(Gel::StoreGem) : []
67
+ end
68
+
69
+ def gem(name, version)
70
+ if !@locked_versions || @locked_versions[name] == version
71
+ @inner.gem(name, version)
72
+ else
73
+ locked_gems.find { |g| g.name == name && g.version == version }
74
+ end
75
+ end
76
+
77
+ def gems(name_version_pairs)
78
+ r = @inner.gems(name_version_pairs)
79
+ locked_gems.each do |g|
80
+ r[g.name] = g
81
+ end
82
+ r
83
+ end
84
+
85
+ def gems_for_lib(file)
86
+ if c = @lib_cache.fetch(file, nil)
87
+ c.each { |gem, subdir| yield gem, subdir }
88
+ return
89
+ end
90
+
91
+ hits = []
92
+ unless @full_cache
93
+ @inner.gems_for_lib(file) do |gem, subdir|
94
+ if locked?(gem)
95
+ hits << [gem, subdir]
96
+ yield gem, subdir
97
+ end
98
+ end
99
+ end
100
+
101
+ locked_gems.each do |gem|
102
+ if File.exist?(gem.path(file) + ".rb")
103
+ hits << [gem, nil]
104
+ yield gem, nil
105
+ end
106
+ end
107
+
108
+ @lib_cache[file] = hits
109
+ end
110
+
111
+ def each(gem_name = nil)
112
+ return enum_for(__callee__, gem_name) unless block_given?
113
+
114
+ list = locked_gems
115
+
116
+ @inner.each(gem_name) do |gem|
117
+ next unless locked?(gem)
118
+ yield gem
119
+ list.delete gem
120
+ end
121
+
122
+ list.each do |gem|
123
+ yield gem if !gem_name || gem.name == gem_name
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+ require_relative "stub_set"
5
+
6
+ class Gel::MultiStore
7
+ VERSION = "#{RbConfig::CONFIG["ruby_version"]}"
8
+
9
+ attr_reader :root
10
+ attr_reader :monitor
11
+
12
+ def initialize(root, stores)
13
+ @root = File.realpath(File.expand_path(root)) if root
14
+ @stores = stores
15
+
16
+ @monitor = Monitor.new
17
+ end
18
+
19
+ def stub_set
20
+ @stub_set ||= Gel::StubSet.new(@root)
21
+ end
22
+
23
+ def paths
24
+ @stores.values.flat_map(&:paths).uniq
25
+ end
26
+
27
+ def [](architecture, version = false)
28
+ @stores[self.class.subkey(architecture, version)]
29
+ end
30
+
31
+ def self.subkey(architecture, version)
32
+ architecture ||= "ruby"
33
+ if version && architecture == "ruby"
34
+ VERSION
35
+ elsif version
36
+ "#{architecture}-#{VERSION}"
37
+ else
38
+ "#{architecture}"
39
+ end
40
+ end
41
+
42
+ def prepare(versions)
43
+ @stores.each do |_, store|
44
+ store.prepare(versions)
45
+ end
46
+ end
47
+
48
+ def gems_for_lib(file)
49
+ @stores.each do |_, store|
50
+ store.gems_for_lib(file) do |gem, subdir|
51
+ yield gem, subdir
52
+ end
53
+ end
54
+ end
55
+
56
+ def each(gem_name = nil, &block)
57
+ return enum_for(__callee__, gem_name) unless block_given?
58
+
59
+ @stores.each do |_, store|
60
+ store.each(gem_name, &block)
61
+ end
62
+ end
63
+
64
+ def gem(name, version)
65
+ @stores.each do |_, store|
66
+ g = store.gem(name, version)
67
+ return g if g
68
+ end
69
+ nil
70
+ end
71
+
72
+ def gems(name_version_pairs)
73
+ result = {}
74
+
75
+ @stores.each do |_, store|
76
+ result.update(store.gems(name_version_pairs)) do |l, r|
77
+ l
78
+ end
79
+ end
80
+
81
+ result
82
+ end
83
+
84
+ def gem?(name, version, platform = nil)
85
+ @stores.any? do |key, store|
86
+ next if platform && !key.start_with?(platform)
87
+ store.gem?(name, version)
88
+ end
89
+ end
90
+
91
+ def libs_for_gems(versions, &block)
92
+ @stores.each do |_, store|
93
+ store.libs_for_gems(versions, &block)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zlib"
4
+ require "yaml"
5
+
6
+ require_relative "support/tar"
7
+
8
+ module Gel
9
+ class Package
10
+ class Specification
11
+ def initialize(inner)
12
+ @inner = inner
13
+ end
14
+
15
+ def name
16
+ @inner.name
17
+ end
18
+
19
+ def version
20
+ @inner.version
21
+ end
22
+
23
+ def architecture
24
+ @inner.architecture
25
+ end
26
+
27
+ def bindir
28
+ @inner.bindir
29
+ end
30
+
31
+ def executables
32
+ @inner.executables
33
+ end
34
+
35
+ def require_paths
36
+ @inner.require_paths
37
+ end
38
+
39
+ def extensions
40
+ @inner.extensions
41
+ end
42
+
43
+ def runtime_dependencies
44
+ h = {}
45
+ @inner.dependencies.each do |dep|
46
+ next unless dep.type == :runtime || dep.type.nil?
47
+ req = dep.requirement || dep.version_requirements
48
+ h[dep.name] = req.requirements.map { |pair| pair.map(&:to_s) }
49
+ end
50
+ h
51
+ end
52
+ end
53
+
54
+ class YAMLLoader < ::YAML::ClassLoader::Restricted
55
+ #--
56
+ # Based on YAML.safe_load
57
+ def self.load(yaml, filename)
58
+ result = if Psych::VERSION < "3.1" # Ruby 2.5 & below
59
+ ::YAML.parse(yaml, filename)
60
+ else
61
+ ::YAML.parse(yaml, filename: filename)
62
+ end
63
+ return unless result
64
+
65
+ class_loader = self.new
66
+ scanner = ::YAML::ScalarScanner.new class_loader
67
+
68
+ visitor = ::YAML::Visitors::ToRuby.new scanner, class_loader
69
+ visitor.accept result
70
+ end
71
+
72
+ def initialize
73
+ super(%w(Symbol Time), [])
74
+ end
75
+
76
+ def find(klass)
77
+ case klass
78
+ when "Gem::Specification"
79
+ Gem_Specification
80
+ when "Gem::Version"
81
+ Gem_Version
82
+ when "Gem::Version::Requirement", "Gem::Requirement"
83
+ Gem_Requirement
84
+ when "Gem::Platform"
85
+ Gem_Platform
86
+ when "Gem::Dependency"
87
+ Gem_Dependency
88
+ else
89
+ super
90
+ end
91
+ end
92
+
93
+ class Gem_Specification
94
+ attr_accessor :architecture, :bindir, :executables, :name, :require_paths, :specification_version, :version, :dependencies, :extensions
95
+ end
96
+ class Gem_Dependency
97
+ attr_accessor :name, :requirement, :type, :version_requirements
98
+ end
99
+ class Gem_Platform; end
100
+ Gem_Version = Gel::Support::GemVersion
101
+ class Gem_Requirement
102
+ attr_accessor :requirements
103
+ end
104
+ end
105
+
106
+ def self.with_file(reader, filename, checksums)
107
+ reader.seek(filename) do |stream|
108
+ if checksums
109
+ data = stream.read
110
+ stream.rewind
111
+
112
+ checksums.each do |type, map|
113
+ next unless %w(SHA1 SHA512).include?(type)
114
+ calculated = Digest(type).hexdigest(data)
115
+ raise "#{type} checksum mismatch on #{filename}" unless calculated == map[filename]
116
+ end
117
+ end
118
+
119
+ yield stream
120
+ end
121
+ end
122
+
123
+ def self.extract(filename, receiver)
124
+ File.open(filename) do |io|
125
+ Gel::Support::Tar::TarReader.new(io) do |package_reader|
126
+ sums = with_file(package_reader, "checksums.yaml.gz", nil) do |sum_stream|
127
+ yaml = Zlib::GzipReader.new(sum_stream).read
128
+
129
+ if Psych::VERSION < "3.1" # Ruby 2.5 & below
130
+ ::YAML.safe_load(yaml, [], [], false, "#{filename}:checksums.yaml.gz")
131
+ else
132
+ ::YAML.safe_load(yaml, filename: "#{filename}:checksums.yaml.gz")
133
+ end
134
+ end
135
+
136
+ spec = with_file(package_reader, "metadata.gz", sums) do |meta_stream|
137
+ yaml = Zlib::GzipReader.new(meta_stream).read
138
+ loaded = YAMLLoader.load(yaml, "#{filename}:metadata.gz")
139
+ Specification.new(loaded)
140
+ end or raise "no metadata.gz"
141
+
142
+ return receiver.gem(spec) do |target|
143
+ with_file(package_reader, "data.tar.gz", sums) do |data_stream|
144
+ Gel::Support::Tar::TarReader.new(Zlib::GzipReader.new(data_stream)) do |data_reader|
145
+ data_reader.each do |entry|
146
+ target.file(entry.full_name, entry, entry.header.mode)
147
+ end
148
+ end
149
+ true
150
+ end or raise "no data.tar.gz"
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gel
4
+ class Package
5
+ class Inspector
6
+ def initialize(&block)
7
+ @block = block
8
+ end
9
+
10
+ attr_reader :spec
11
+
12
+ def gem(spec)
13
+ @spec = spec
14
+
15
+ yield self if @block
16
+ end
17
+
18
+ def file(filename, io, _mode)
19
+ @block.call filename, io
20
+ end
21
+ end
22
+ end
23
+ end