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,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