bundix 2.3.0 → 2.5.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 +5 -5
- data/bin/bundix +2 -114
- data/lib/bundix.rb +103 -43
- data/lib/bundix/commandline.rb +169 -0
- data/lib/bundix/nixer.rb +104 -0
- data/lib/bundix/shell_nix_context.rb +27 -0
- data/lib/bundix/source.rb +96 -40
- data/lib/bundix/version.rb +1 -1
- data/template/nixer/list.erb +1 -0
- data/template/nixer/set.erb +3 -0
- data/template/shell-nix.erb +13 -0
- metadata +11 -6
- data/lib/bundix/fetchurl-force.nix +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3fbcd152e7e9e610f2357bd6ee0658d84fa9bbcd497c3ced755d7efafb9547a9
|
4
|
+
data.tar.gz: 9f8eb407611278f324960b8393e7452d4b9385434cfbc028db61dbddc7335f3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 564b4bf345a72c9556d3a776c7d39f62f1ee060b71c5a9c99d7b29ad43096d1d321a6e860da52124b43a4f9675dfc0f3bdbd1a5fe2dadb0d6561967b3e17f4b3
|
7
|
+
data.tar.gz: 0565a326c0babef8e995afb905895c6c591c27926d5b7fb011a59478c89f128eabd3aa18c10dfa1f9f040663f7e48c7c86697a55973ad37a77fb07ed8b693d57
|
data/bin/bundix
CHANGED
@@ -1,117 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'tmpdir'
|
5
|
-
require 'tempfile'
|
6
|
-
require 'pathname'
|
3
|
+
require_relative '../lib/bundix/commandline'
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
options = {
|
11
|
-
ruby: 'ruby',
|
12
|
-
bundle_pack_path: 'vendor/bundle',
|
13
|
-
gemfile: 'Gemfile',
|
14
|
-
lockfile: 'Gemfile.lock',
|
15
|
-
gemset: 'gemset.nix',
|
16
|
-
}
|
17
|
-
|
18
|
-
op = OptionParser.new do |o|
|
19
|
-
o.on '-m', '--magic', 'lock, pack, and write dependencies' do
|
20
|
-
options[:magic] = true
|
21
|
-
end
|
22
|
-
|
23
|
-
o.on '--ruby=ruby', 'ruby version to use for magic and init, defaults to latest' do |value|
|
24
|
-
options[:ruby] = value
|
25
|
-
end
|
26
|
-
|
27
|
-
o.on '--bundle-pack-path=vendor/bundle', "path to pack the magic" do |value|
|
28
|
-
options[:bundle_pack_path] = value
|
29
|
-
end
|
30
|
-
|
31
|
-
o.on '-i', '--init', "initialize a new shell.nix for nix-shell (won't overwrite old ones)" do
|
32
|
-
options[:init] = true
|
33
|
-
end
|
34
|
-
|
35
|
-
o.on '--gemset=gemset.nix', 'path to the gemset.nix' do |value|
|
36
|
-
options[:gemset] = File.expand_path(value)
|
37
|
-
end
|
38
|
-
|
39
|
-
o.on '--lockfile=Gemfile.lock', 'path to the Gemfile.lock' do |value|
|
40
|
-
options[:lockfile] = File.expand_path(value)
|
41
|
-
end
|
42
|
-
|
43
|
-
o.on '--gemfile=Gemfile', 'path to the Gemfile' do |value|
|
44
|
-
options[:gemfile] = File.expand_path(value)
|
45
|
-
end
|
46
|
-
|
47
|
-
o.on '-d', '--dependencies', 'include gem dependencies (deprecated)' do
|
48
|
-
warn '--dependencies/-d is deprecated because'
|
49
|
-
warn 'dependencies will always be fetched'
|
50
|
-
end
|
51
|
-
|
52
|
-
o.on '-q', '--quiet', 'only output errors' do
|
53
|
-
options[:quiet] = true
|
54
|
-
end
|
55
|
-
|
56
|
-
o.on '-l', '--lock', 'generate Gemfile.lock first' do
|
57
|
-
options[:lock] = true
|
58
|
-
end
|
59
|
-
|
60
|
-
o.on '-v', '--version', 'show the version of bundix' do
|
61
|
-
puts Bundix::VERSION
|
62
|
-
exit
|
63
|
-
end
|
64
|
-
|
65
|
-
o.on '--env', 'show the environment in bundix' do
|
66
|
-
system('env')
|
67
|
-
exit
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
op.parse!
|
72
|
-
$VERBOSE = !options[:quiet]
|
73
|
-
|
74
|
-
if options[:magic]
|
75
|
-
fail unless system(
|
76
|
-
Bundix::NIX_SHELL, '-p', options[:ruby],
|
77
|
-
"bundler.override { ruby = #{options[:ruby]}; }",
|
78
|
-
"--command", "bundle lock --lockfile=#{options[:lockfile]}")
|
79
|
-
fail unless system(
|
80
|
-
Bundix::NIX_SHELL, '-p', options[:ruby],
|
81
|
-
"bundler.override { ruby = #{options[:ruby]}; }",
|
82
|
-
"--command", "bundle pack --all --path #{options[:bundle_pack_path]}")
|
83
|
-
end
|
84
|
-
|
85
|
-
if options[:init]
|
86
|
-
if File.file?('shell.nix')
|
87
|
-
warn "won't override existing shell.nix"
|
88
|
-
else
|
89
|
-
shell_nix = File.read(File.expand_path('../template/shell.nix', __dir__))
|
90
|
-
shell_nix.gsub!('PROJECT', File.basename(Dir.pwd))
|
91
|
-
shell_nix.gsub!('RUBY', options[:ruby])
|
92
|
-
shell_nix.gsub!('LOCKFILE', "./#{Pathname(options[:lockfile]).relative_path_from(Pathname('./'))}")
|
93
|
-
shell_nix.gsub!('GEMSET', "./#{Pathname(options[:gemset]).relative_path_from(Pathname('./'))}")
|
94
|
-
File.write('shell.nix', shell_nix)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
if options[:lock]
|
99
|
-
lock = !File.file?(options[:lockfile])
|
100
|
-
lock ||= File.mtime(options[:gemfile]) > File.mtime(options[:lockfile])
|
101
|
-
if lock
|
102
|
-
system('bundle', 'lock')
|
103
|
-
fail 'bundle lock failed' unless $?.success?
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
gemset = Bundix.new(options).convert
|
108
|
-
|
109
|
-
tempfile = Tempfile.new('gemset.nix', encoding: 'UTF-8')
|
110
|
-
begin
|
111
|
-
Bundix.object2nix(gemset, 2, tempfile)
|
112
|
-
tempfile.flush
|
113
|
-
FileUtils.cp(tempfile.path, options[:gemset])
|
114
|
-
ensure
|
115
|
-
tempfile.close!
|
116
|
-
tempfile.unlink
|
117
|
-
end
|
5
|
+
Bundix::CommandLine.run
|
data/lib/bundix.rb
CHANGED
@@ -6,44 +6,92 @@ require 'pp'
|
|
6
6
|
|
7
7
|
require_relative 'bundix/version'
|
8
8
|
require_relative 'bundix/source'
|
9
|
+
require_relative 'bundix/nixer'
|
9
10
|
|
10
11
|
class Bundix
|
11
12
|
NIX_INSTANTIATE = 'nix-instantiate'
|
12
13
|
NIX_PREFETCH_URL = 'nix-prefetch-url'
|
13
14
|
NIX_PREFETCH_GIT = 'nix-prefetch-git'
|
14
|
-
NIX_BUILD = 'nix-build'
|
15
15
|
NIX_HASH = 'nix-hash'
|
16
16
|
NIX_SHELL = 'nix-shell'
|
17
17
|
|
18
|
-
FETCHURL_FORCE = File.expand_path('../bundix/fetchurl-force.nix', __FILE__)
|
19
|
-
FETCHURL_FORCE_CHECK = lambda do |_, out|
|
20
|
-
out =~ /success! failing outer nix build.../
|
21
|
-
end
|
22
|
-
|
23
18
|
SHA256_32 = %r(^[a-z0-9]{52}$)
|
24
|
-
SHA256_16 = %r(^[a-f0-9]{64}$)
|
25
19
|
|
26
20
|
attr_reader :options
|
27
21
|
|
22
|
+
attr_accessor :fetcher
|
23
|
+
|
24
|
+
class Dependency < Bundler::Dependency
|
25
|
+
def initialize(name, version, options={}, &blk)
|
26
|
+
super(name, version, options, &blk)
|
27
|
+
@bundix_version = version
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :version
|
31
|
+
end
|
32
|
+
|
28
33
|
def initialize(options)
|
29
34
|
@options = { quiet: false, tempfile: nil }.merge(options)
|
35
|
+
@fetcher = Fetcher.new
|
30
36
|
end
|
31
37
|
|
32
38
|
def convert
|
33
39
|
cache = parse_gemset
|
34
40
|
lock = parse_lockfile
|
41
|
+
dep_cache = build_depcache(lock)
|
35
42
|
|
36
43
|
# reverse so git comes last
|
37
44
|
lock.specs.reverse_each.with_object({}) do |spec, gems|
|
38
|
-
gem = find_cached_spec(spec, cache) || convert_spec(spec, cache)
|
45
|
+
gem = find_cached_spec(spec, cache) || convert_spec(spec, cache, dep_cache)
|
39
46
|
gems.merge!(gem)
|
40
47
|
|
41
|
-
|
48
|
+
if spec.dependencies.any?
|
49
|
+
gems[spec.name]['dependencies'] = spec.dependencies.map(&:name) - ['bundler']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def groups(spec, dep_cache)
|
55
|
+
{groups: dep_cache.fetch(spec.name).groups}
|
56
|
+
end
|
57
|
+
|
58
|
+
PLATFORM_MAPPING = {}
|
59
|
+
|
60
|
+
{
|
61
|
+
"ruby" => [{engine: "ruby"}, {engine:"rbx"}, {engine:"maglev"}],
|
62
|
+
"mri" => [{engine: "ruby"}, {engine: "maglev"}],
|
63
|
+
"rbx" => [{engine: "rbx"}],
|
64
|
+
"jruby" => [{engine: "jruby"}],
|
65
|
+
"mswin" => [{engine: "mswin"}],
|
66
|
+
"mswin64" => [{engine: "mswin64"}],
|
67
|
+
"mingw" => [{engine: "mingw"}],
|
68
|
+
"truffleruby" => [{engine: "ruby"}],
|
69
|
+
"x64_mingw" => [{engine: "mingw"}],
|
70
|
+
}.each do |name, list|
|
71
|
+
PLATFORM_MAPPING[name] = list
|
72
|
+
%w(1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6).each do |version|
|
73
|
+
PLATFORM_MAPPING["#{name}_#{version.sub(/[.]/,'')}"] = list.map do |platform|
|
74
|
+
platform.merge(:version => version)
|
75
|
+
end
|
42
76
|
end
|
43
77
|
end
|
44
78
|
|
45
|
-
def
|
46
|
-
|
79
|
+
def platforms(spec, dep_cache)
|
80
|
+
# c.f. Bundler::CurrentRuby
|
81
|
+
platforms = dep_cache.fetch(spec.name).platforms.map do |platform_name|
|
82
|
+
PLATFORM_MAPPING[platform_name.to_s]
|
83
|
+
end.flatten
|
84
|
+
|
85
|
+
{platforms: platforms}
|
86
|
+
end
|
87
|
+
|
88
|
+
def convert_spec(spec, cache, dep_cache)
|
89
|
+
{
|
90
|
+
spec.name => {
|
91
|
+
version: spec.version.to_s,
|
92
|
+
source: Source.new(spec, fetcher).convert
|
93
|
+
}.merge(platforms(spec, dep_cache)).merge(groups(spec, dep_cache))
|
94
|
+
}
|
47
95
|
rescue => ex
|
48
96
|
warn "Skipping #{spec.name}: #{ex}"
|
49
97
|
puts ex.backtrace
|
@@ -70,12 +118,53 @@ class Bundix
|
|
70
118
|
{name => cached} if cached
|
71
119
|
end
|
72
120
|
|
121
|
+
def build_depcache(lock)
|
122
|
+
definition = Bundler::Definition.build(options[:gemfile], options[:lockfile], false)
|
123
|
+
dep_cache = {}
|
124
|
+
|
125
|
+
definition.dependencies.each do |dep|
|
126
|
+
dep_cache[dep.name] = dep
|
127
|
+
end
|
128
|
+
|
129
|
+
lock.specs.each do |spec|
|
130
|
+
dep_cache[spec.name] ||= Dependency.new(spec.name, nil, {})
|
131
|
+
end
|
132
|
+
|
133
|
+
begin
|
134
|
+
changed = false
|
135
|
+
lock.specs.each do |spec|
|
136
|
+
as_dep = dep_cache.fetch(spec.name)
|
137
|
+
|
138
|
+
spec.dependencies.each do |dep|
|
139
|
+
cached = dep_cache.fetch(dep.name) do |name|
|
140
|
+
if name != "bundler"
|
141
|
+
raise KeyError, "Gem dependency '#{name}' not specified in #{lockfile}"
|
142
|
+
end
|
143
|
+
dep_cache[name] = Dependency.new(name, lock.bundler_version, {})
|
144
|
+
end
|
145
|
+
|
146
|
+
if !((as_dep.groups - cached.groups) - [:default]).empty? or !(as_dep.platforms - cached.platforms).empty?
|
147
|
+
changed = true
|
148
|
+
dep_cache[cached.name] = (Dependency.new(cached.name, nil, {
|
149
|
+
"group" => as_dep.groups | cached.groups,
|
150
|
+
"platforms" => as_dep.platforms | cached.platforms
|
151
|
+
}))
|
152
|
+
|
153
|
+
cc = dep_cache[cached.name]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end while changed
|
158
|
+
|
159
|
+
return dep_cache
|
160
|
+
end
|
73
161
|
|
74
162
|
def parse_gemset
|
75
163
|
path = File.expand_path(options[:gemset])
|
76
164
|
return {} unless File.file?(path)
|
77
|
-
json = Bundix.sh(
|
78
|
-
|
165
|
+
json = Bundix.sh(NIX_INSTANTIATE, '--eval', '-E', %(
|
166
|
+
builtins.toJSON (import #{Nixer.serialize(path)}))
|
167
|
+
)
|
79
168
|
JSON.parse(json.strip.gsub(/\\"/, '"')[1..-2])
|
80
169
|
end
|
81
170
|
|
@@ -83,37 +172,8 @@ class Bundix
|
|
83
172
|
Bundler::LockfileParser.new(File.read(options[:lockfile]))
|
84
173
|
end
|
85
174
|
|
86
|
-
def self.object2nix(obj, level = 2, out = '')
|
87
|
-
case obj
|
88
|
-
when Hash
|
89
|
-
out << "{\n"
|
90
|
-
obj.sort_by{|k, v| k.to_s.downcase }.each do |(k, v)|
|
91
|
-
out << ' ' * level
|
92
|
-
if k.to_s =~ /^[a-zA-Z_-]+[a-zA-Z0-9_-]*$/
|
93
|
-
out << k.to_s
|
94
|
-
else
|
95
|
-
object2nix(k, level + 2, out)
|
96
|
-
end
|
97
|
-
out << ' = '
|
98
|
-
object2nix(v, level + 2, out)
|
99
|
-
out << (v.is_a?(Hash) ? "\n" : ";\n")
|
100
|
-
end
|
101
|
-
out << (' ' * (level - 2)) << (level == 2 ? '}' : '};')
|
102
|
-
when Array
|
103
|
-
out << '[' << obj.sort.map{|o| o.to_str.dump }.join(' ') << ']'
|
104
|
-
when String
|
105
|
-
out << obj.dump
|
106
|
-
when Symbol
|
107
|
-
out << obj.to_s.dump
|
108
|
-
when true, false
|
109
|
-
out << obj.to_s
|
110
|
-
else
|
111
|
-
fail obj.inspect
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
175
|
def self.sh(*args, &block)
|
116
|
-
out, status = Open3.
|
176
|
+
out, status = Open3.capture2(*args)
|
117
177
|
unless block_given? ? block.call(status, out) : status.success?
|
118
178
|
puts "$ #{args.join(' ')}" if $VERBOSE
|
119
179
|
puts out if $VERBOSE
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'tempfile'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
require_relative '../bundix'
|
7
|
+
require_relative 'shell_nix_context'
|
8
|
+
|
9
|
+
class Bundix
|
10
|
+
class CommandLine
|
11
|
+
|
12
|
+
DEFAULT_OPTIONS = {
|
13
|
+
ruby: 'ruby',
|
14
|
+
bundle_pack_path: 'vendor/bundle',
|
15
|
+
gemfile: 'Gemfile',
|
16
|
+
lockfile: 'Gemfile.lock',
|
17
|
+
gemset: 'gemset.nix',
|
18
|
+
project: File.basename(Dir.pwd)
|
19
|
+
}
|
20
|
+
|
21
|
+
def self.run
|
22
|
+
self.new.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@options = DEFAULT_OPTIONS.clone
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_accessor :options
|
30
|
+
|
31
|
+
def run
|
32
|
+
parse_options
|
33
|
+
handle_magic
|
34
|
+
handle_lock
|
35
|
+
handle_init
|
36
|
+
gemset = build_gemset
|
37
|
+
save_gemset(gemset)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_options
|
41
|
+
op = OptionParser.new do |o|
|
42
|
+
o.on '-m', '--magic', 'lock, pack, and write dependencies' do
|
43
|
+
options[:magic] = true
|
44
|
+
end
|
45
|
+
|
46
|
+
o.on "--ruby=#{options[:ruby]}", 'ruby version to use for magic and init, defaults to latest' do |value|
|
47
|
+
options[:ruby] = value
|
48
|
+
end
|
49
|
+
|
50
|
+
o.on "--bundle-pack-path=#{options[:bundle_pack_path]}", "path to pack the magic" do |value|
|
51
|
+
options[:bundle_pack_path] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
o.on '-i', '--init', "initialize a new shell.nix for nix-shell (won't overwrite old ones)" do
|
55
|
+
options[:init] = true
|
56
|
+
end
|
57
|
+
|
58
|
+
o.on "--gemset=#{options[:gemset]}", 'path to the gemset.nix' do |value|
|
59
|
+
options[:gemset] = File.expand_path(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
o.on "--lockfile=#{options[:lockfile]}", 'path to the Gemfile.lock' do |value|
|
63
|
+
options[:lockfile] = File.expand_path(value)
|
64
|
+
end
|
65
|
+
|
66
|
+
o.on "--gemfile=#{options[:gemfile]}", 'path to the Gemfile' do |value|
|
67
|
+
options[:gemfile] = File.expand_path(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
o.on '-d', '--dependencies', 'include gem dependencies (deprecated)' do
|
71
|
+
warn '--dependencies/-d is deprecated because'
|
72
|
+
warn 'dependencies will always be fetched'
|
73
|
+
end
|
74
|
+
|
75
|
+
o.on '-q', '--quiet', 'only output errors' do
|
76
|
+
options[:quiet] = true
|
77
|
+
end
|
78
|
+
|
79
|
+
o.on '-l', '--lock', 'generate Gemfile.lock first' do
|
80
|
+
options[:lock] = true
|
81
|
+
end
|
82
|
+
|
83
|
+
o.on '-v', '--version', 'show the version of bundix' do
|
84
|
+
puts Bundix::VERSION
|
85
|
+
exit
|
86
|
+
end
|
87
|
+
|
88
|
+
o.on '--env', 'show the environment in bundix' do
|
89
|
+
system('env')
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
op.parse!
|
95
|
+
$VERBOSE = !options[:quiet]
|
96
|
+
options
|
97
|
+
end
|
98
|
+
|
99
|
+
def handle_magic
|
100
|
+
ENV['BUNDLE_GEMFILE'] = options[:gemfile]
|
101
|
+
|
102
|
+
if options[:magic]
|
103
|
+
fail unless system(
|
104
|
+
Bundix::NIX_SHELL, '-p', options[:ruby],
|
105
|
+
"bundler.override { ruby = #{options[:ruby]}; }",
|
106
|
+
"--command", "bundle lock --lockfile=#{options[:lockfile]}")
|
107
|
+
fail unless system(
|
108
|
+
Bundix::NIX_SHELL, '-p', options[:ruby],
|
109
|
+
"bundler.override { ruby = #{options[:ruby]}; }",
|
110
|
+
"--command", "bundle pack --all --path #{options[:bundle_pack_path]}")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def shell_nix_context
|
115
|
+
ShellNixContext.from_hash(options)
|
116
|
+
end
|
117
|
+
|
118
|
+
def shell_nix_string
|
119
|
+
tmpl = ERB.new(File.read(File.expand_path('../../template/shell-nix.erb', __dir__)))
|
120
|
+
tmpl.result(shell_nix_context.bind)
|
121
|
+
end
|
122
|
+
|
123
|
+
def handle_init
|
124
|
+
if options[:init]
|
125
|
+
if File.file?('shell.nix')
|
126
|
+
warn "won't override existing shell.nix but here is what it'd look like:"
|
127
|
+
puts shell_nix_string
|
128
|
+
else
|
129
|
+
File.write('shell.nix', shell_nix_string)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def handle_lock
|
135
|
+
if options[:lock]
|
136
|
+
lock = !File.file?(options[:lockfile])
|
137
|
+
lock ||= File.mtime(options[:gemfile]) > File.mtime(options[:lockfile])
|
138
|
+
if lock
|
139
|
+
ENV.delete('BUNDLE_PATH')
|
140
|
+
ENV.delete('BUNDLE_FROZEN')
|
141
|
+
ENV.delete('BUNDLE_BIN_PATH')
|
142
|
+
system('bundle', 'lock')
|
143
|
+
fail 'bundle lock failed' unless $?.success?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def build_gemset
|
149
|
+
Bundix.new(options).convert
|
150
|
+
end
|
151
|
+
|
152
|
+
def object2nix(obj)
|
153
|
+
Nixer.serialize(obj)
|
154
|
+
end
|
155
|
+
|
156
|
+
def save_gemset(gemset)
|
157
|
+
tempfile = Tempfile.new('gemset.nix', encoding: 'UTF-8')
|
158
|
+
begin
|
159
|
+
tempfile.write(object2nix(gemset))
|
160
|
+
tempfile.flush
|
161
|
+
FileUtils.cp(tempfile.path, options[:gemset])
|
162
|
+
FileUtils.chmod(0644, options[:gemset])
|
163
|
+
ensure
|
164
|
+
tempfile.close!
|
165
|
+
tempfile.unlink
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/bundix/nixer.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# regretfully, duckpunching
|
5
|
+
def <=>(other)
|
6
|
+
if other.is_a?(Hash)
|
7
|
+
larray = to_a.sort{|l,r| Bundix::Nixer.order(l,r)}
|
8
|
+
rarray = other.to_a.sort{|l,r| Bundix::Nixer.order(l,r)}
|
9
|
+
larray <=> rarray
|
10
|
+
else
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Bundix
|
17
|
+
class Nixer
|
18
|
+
class << self
|
19
|
+
def serialize(obj)
|
20
|
+
new(obj).serialize
|
21
|
+
end
|
22
|
+
|
23
|
+
def order(left, right)
|
24
|
+
if right.is_a?(left.class)
|
25
|
+
if right.respond_to?(:<=>)
|
26
|
+
cmp = right <=> left
|
27
|
+
return -1 * (cmp) unless cmp.nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if left.is_a?(right.class)
|
32
|
+
if left.respond_to?(:<=>)
|
33
|
+
cmp = right <=> left
|
34
|
+
if cmp.nil?
|
35
|
+
return class_order(left, right)
|
36
|
+
else
|
37
|
+
return cmp
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return class_order(left, right)
|
43
|
+
end
|
44
|
+
|
45
|
+
def class_order(left, right)
|
46
|
+
left.class.name <=> right.class.name # like Erlang
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_reader :level, :obj
|
51
|
+
|
52
|
+
SET_T = ERB.new(File.read(File.expand_path("../../template/nixer/set.erb", __dir__)).chomp)
|
53
|
+
LIST_T = ERB.new(File.read(File.expand_path("../../template/nixer/list.erb", __dir__)).chomp)
|
54
|
+
|
55
|
+
def initialize(obj, level = 0)
|
56
|
+
@obj = obj
|
57
|
+
@level = level
|
58
|
+
end
|
59
|
+
|
60
|
+
def indent
|
61
|
+
' ' * (level + 2)
|
62
|
+
end
|
63
|
+
|
64
|
+
def outdent
|
65
|
+
' ' * level
|
66
|
+
end
|
67
|
+
|
68
|
+
def sub(obj, indent = 0)
|
69
|
+
self.class.new(obj, level + indent).serialize
|
70
|
+
end
|
71
|
+
|
72
|
+
def serialize_key(k)
|
73
|
+
if k.to_s =~ /^[a-zA-Z_-]+[a-zA-Z0-9_-]*$/
|
74
|
+
k.to_s
|
75
|
+
else
|
76
|
+
sub(k, 2)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def serialize
|
81
|
+
case obj
|
82
|
+
when Hash
|
83
|
+
return SET_T.result(binding)
|
84
|
+
when Array
|
85
|
+
return LIST_T.result(binding)
|
86
|
+
when String
|
87
|
+
obj.dump
|
88
|
+
when Symbol
|
89
|
+
obj.to_s.dump
|
90
|
+
when Pathname
|
91
|
+
str = obj.to_s
|
92
|
+
if %r{/} !~ str
|
93
|
+
"./"+ str
|
94
|
+
else
|
95
|
+
str
|
96
|
+
end
|
97
|
+
when true, false
|
98
|
+
obj.to_s
|
99
|
+
else
|
100
|
+
fail "Cannot convert to nix: #{obj.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Bundix
|
2
|
+
class ShellNixContext < Struct.new(:project, :ruby, :gemfile, :lockfile, :gemset)
|
3
|
+
def self.from_hash(hash)
|
4
|
+
new(*hash.values_at(*members))
|
5
|
+
end
|
6
|
+
|
7
|
+
def bind
|
8
|
+
binding
|
9
|
+
end
|
10
|
+
|
11
|
+
def path_for(file)
|
12
|
+
Nixer.serialize(Pathname(file).relative_path_from(Pathname('./')))
|
13
|
+
end
|
14
|
+
|
15
|
+
def gemfile_path
|
16
|
+
path_for(gemfile)
|
17
|
+
end
|
18
|
+
|
19
|
+
def lockfile_path
|
20
|
+
path_for(lockfile)
|
21
|
+
end
|
22
|
+
|
23
|
+
def gemset_path
|
24
|
+
path_for(gemset)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/bundix/source.rb
CHANGED
@@ -1,17 +1,5 @@
|
|
1
1
|
class Bundix
|
2
|
-
class
|
3
|
-
def convert
|
4
|
-
case spec.source
|
5
|
-
when Bundler::Source::Rubygems
|
6
|
-
convert_rubygems
|
7
|
-
when Bundler::Source::Git
|
8
|
-
convert_git
|
9
|
-
else
|
10
|
-
pp spec
|
11
|
-
fail 'unkown bundler source'
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
2
|
+
class Fetcher
|
15
3
|
def sh(*args, &block)
|
16
4
|
Bundix.sh(*args, &block)
|
17
5
|
end
|
@@ -20,50 +8,95 @@ class Bundix
|
|
20
8
|
warn "Downloading #{file} from #{url}"
|
21
9
|
uri = URI(url)
|
22
10
|
open_options = {}
|
23
|
-
|
11
|
+
|
12
|
+
unless uri.user
|
13
|
+
inject_credentials_from_bundler_settings(uri)
|
14
|
+
end
|
15
|
+
|
16
|
+
if uri.user
|
24
17
|
open_options[:http_basic_authentication] = [uri.user, uri.password]
|
25
18
|
uri.user = nil
|
26
19
|
uri.password = nil
|
27
20
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
21
|
+
|
22
|
+
begin
|
23
|
+
open(uri.to_s, 'r', 0600, open_options) do |net|
|
24
|
+
File.open(file, 'wb+') { |local|
|
25
|
+
File.copy_stream(net, local)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
rescue OpenURI::HTTPError => e
|
29
|
+
# e.message: "403 Forbidden" or "401 Unauthorized"
|
30
|
+
debrief_access_denied(uri.host) if e.message =~ /^40[13] /
|
31
|
+
raise
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def inject_credentials_from_bundler_settings(uri)
|
36
|
+
@bundler_settings ||= Bundler::Settings.new(Bundler.root + '.bundle')
|
37
|
+
|
38
|
+
if val = @bundler_settings[uri.host]
|
39
|
+
uri.user, uri.password = val.split(':', 2)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def debrief_access_denied(host)
|
44
|
+
print_error(
|
45
|
+
"Authentication is required for #{host}.\n" +
|
46
|
+
"Please supply credentials for this source. You can do this by running:\n" +
|
47
|
+
" bundle config packages.shopify.io username:password"
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def print_error(msg)
|
52
|
+
msg = "\x1b[31m#{msg}\x1b[0m" if $stdout.tty?
|
53
|
+
STDERR.puts(msg)
|
54
|
+
end
|
55
|
+
|
35
56
|
def nix_prefetch_url(url)
|
36
|
-
dir = File.
|
57
|
+
dir = File.join(ENV['XDG_CACHE_HOME'] || "#{ENV['HOME']}/.cache", 'bundix')
|
37
58
|
FileUtils.mkdir_p dir
|
38
59
|
file = File.join(dir, url.gsub(/[^\w-]+/, '_'))
|
39
60
|
|
40
|
-
unless File.size?(file)
|
41
|
-
download(file, url)
|
42
|
-
end
|
43
|
-
|
61
|
+
download(file, url) unless File.size?(file)
|
44
62
|
return unless File.size?(file)
|
45
63
|
|
46
|
-
sh(
|
47
|
-
|
64
|
+
sh(
|
65
|
+
Bundix::NIX_PREFETCH_URL,
|
66
|
+
'--type', 'sha256',
|
67
|
+
'--name', File.basename(url), # --name mygem-1.2.3.gem
|
68
|
+
"file://#{file}", # file:///.../https_rubygems_org_gems_mygem-1_2_3_gem
|
69
|
+
).force_encoding('UTF-8').strip
|
48
70
|
rescue => ex
|
49
71
|
puts ex
|
50
72
|
nil
|
51
73
|
end
|
52
74
|
|
53
|
-
def nix_prefetch_git(uri, revision)
|
75
|
+
def nix_prefetch_git(uri, revision, submodules: false)
|
54
76
|
home = ENV['HOME']
|
55
77
|
ENV['HOME'] = '/homeless-shelter'
|
56
|
-
|
78
|
+
|
79
|
+
args = []
|
80
|
+
args << '--url' << uri
|
81
|
+
args << '--rev' << revision
|
82
|
+
args << '--hash' << 'sha256'
|
83
|
+
args << '--fetch-submodules' if submodules
|
84
|
+
|
85
|
+
sh(NIX_PREFETCH_GIT, *args)
|
57
86
|
ensure
|
58
87
|
ENV['HOME'] = home
|
59
88
|
end
|
60
89
|
|
90
|
+
def format_hash(hash)
|
91
|
+
sh(NIX_HASH, '--type', 'sha256', '--to-base32', hash)[SHA256_32]
|
92
|
+
end
|
93
|
+
|
61
94
|
def fetch_local_hash(spec)
|
62
95
|
spec.source.caches.each do |cache|
|
63
|
-
path = File.join(cache, "#{spec.
|
96
|
+
path = File.join(cache, "#{spec.full_name}.gem")
|
64
97
|
next unless File.file?(path)
|
65
|
-
hash = nix_prefetch_url(
|
66
|
-
return hash if hash
|
98
|
+
hash = nix_prefetch_url(path)[SHA256_32]
|
99
|
+
return format_hash(hash) if hash
|
67
100
|
end
|
68
101
|
|
69
102
|
nil
|
@@ -72,14 +105,14 @@ class Bundix
|
|
72
105
|
def fetch_remotes_hash(spec, remotes)
|
73
106
|
remotes.each do |remote|
|
74
107
|
hash = fetch_remote_hash(spec, remote)
|
75
|
-
return remote, hash if hash
|
108
|
+
return remote, format_hash(hash) if hash
|
76
109
|
end
|
77
110
|
|
78
111
|
nil
|
79
112
|
end
|
80
113
|
|
81
114
|
def fetch_remote_hash(spec, remote)
|
82
|
-
uri = "#{remote}/gems/#{spec.
|
115
|
+
uri = "#{remote}/gems/#{spec.full_name}.gem"
|
83
116
|
result = nix_prefetch_url(uri)
|
84
117
|
return unless result
|
85
118
|
result[SHA256_32]
|
@@ -88,14 +121,36 @@ class Bundix
|
|
88
121
|
puts e.backtrace
|
89
122
|
nil
|
90
123
|
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Source < Struct.new(:spec, :fetcher)
|
127
|
+
def convert
|
128
|
+
case spec.source
|
129
|
+
when Bundler::Source::Rubygems
|
130
|
+
convert_rubygems
|
131
|
+
when Bundler::Source::Git
|
132
|
+
convert_git
|
133
|
+
when Bundler::Source::Path
|
134
|
+
convert_path
|
135
|
+
else
|
136
|
+
pp spec
|
137
|
+
fail 'unkown bundler source'
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def convert_path
|
142
|
+
{
|
143
|
+
type: "path",
|
144
|
+
path: spec.source.path
|
145
|
+
}
|
146
|
+
end
|
91
147
|
|
92
148
|
def convert_rubygems
|
93
149
|
remotes = spec.source.remotes.map{|remote| remote.to_s.sub(/\/+$/, '') }
|
94
|
-
hash = fetch_local_hash(spec)
|
95
|
-
remote, hash = fetch_remotes_hash(spec, remotes) unless hash
|
96
|
-
fail "couldn't fetch hash for #{spec.
|
97
|
-
hash
|
98
|
-
puts "#{hash} => #{spec.name}-#{spec.version}.gem" if $VERBOSE
|
150
|
+
hash = fetcher.fetch_local_hash(spec)
|
151
|
+
remote, hash = fetcher.fetch_remotes_hash(spec, remotes) unless hash
|
152
|
+
fail "couldn't fetch hash for #{spec.full_name}" unless hash
|
153
|
+
puts "#{hash} => #{spec.full_name}.gem" if $VERBOSE
|
99
154
|
|
100
155
|
{ type: 'gem',
|
101
156
|
remotes: (remote ? [remote] : remotes),
|
@@ -105,17 +160,18 @@ class Bundix
|
|
105
160
|
def convert_git
|
106
161
|
revision = spec.source.options.fetch('revision')
|
107
162
|
uri = spec.source.options.fetch('uri')
|
108
|
-
|
163
|
+
submodules = !!spec.source.submodules
|
164
|
+
output = fetcher.nix_prefetch_git(uri, revision, submodules: submodules)
|
109
165
|
# FIXME: this is a hack, we should separate $stdout/$stderr in the sh call
|
110
166
|
hash = JSON.parse(output[/({[^}]+})\s*\z/m])['sha256']
|
111
|
-
fail "couldn't fetch hash for #{spec.
|
167
|
+
fail "couldn't fetch hash for #{spec.full_name}" unless hash
|
112
168
|
puts "#{hash} => #{uri}" if $VERBOSE
|
113
169
|
|
114
170
|
{ type: 'git',
|
115
171
|
url: uri.to_s,
|
116
172
|
rev: revision,
|
117
173
|
sha256: hash,
|
118
|
-
fetchSubmodules:
|
174
|
+
fetchSubmodules: submodules }
|
119
175
|
end
|
120
176
|
end
|
121
177
|
end
|
data/lib/bundix/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
[<% obj.sort{|l,r| Nixer.order(l,r)}.each_with_index do |o, n|%><%if n > 0%> <%end%><%= sub(o) %><%end%>]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
with (import <nixpkgs> {});
|
2
|
+
let
|
3
|
+
env = bundlerEnv {
|
4
|
+
name = "<%= project %>-bundler-env";
|
5
|
+
inherit <%= ruby %>;
|
6
|
+
gemfile = <%= gemfile_path %>;
|
7
|
+
lockfile = <%= lockfile_path %>;
|
8
|
+
gemset = <%= gemset_path %>;
|
9
|
+
};
|
10
|
+
in stdenv.mkDerivation {
|
11
|
+
name = "<%= project %>";
|
12
|
+
buildInputs = [ env ];
|
13
|
+
}
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bundix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael 'manveru' Fellinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.11'
|
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
26
|
version: '1.11'
|
27
27
|
description: Creates Nix packages from Gemfiles.
|
@@ -33,9 +33,14 @@ extra_rdoc_files: []
|
|
33
33
|
files:
|
34
34
|
- bin/bundix
|
35
35
|
- lib/bundix.rb
|
36
|
-
- lib/bundix/
|
36
|
+
- lib/bundix/commandline.rb
|
37
|
+
- lib/bundix/nixer.rb
|
38
|
+
- lib/bundix/shell_nix_context.rb
|
37
39
|
- lib/bundix/source.rb
|
38
40
|
- lib/bundix/version.rb
|
41
|
+
- template/nixer/list.erb
|
42
|
+
- template/nixer/set.erb
|
43
|
+
- template/shell-nix.erb
|
39
44
|
homepage: https://github.com/manveru/bundix
|
40
45
|
licenses:
|
41
46
|
- MIT
|
@@ -56,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
61
|
version: '0'
|
57
62
|
requirements: []
|
58
63
|
rubyforge_project:
|
59
|
-
rubygems_version: 2.6.
|
64
|
+
rubygems_version: 2.7.6.2
|
60
65
|
signing_key:
|
61
66
|
specification_version: 4
|
62
67
|
summary: Creates Nix packages from Gemfiles.
|
@@ -1,27 +0,0 @@
|
|
1
|
-
{ nixpkgs ? import <nixpkgs> {}
|
2
|
-
, url
|
3
|
-
}:
|
4
|
-
|
5
|
-
with nixpkgs;
|
6
|
-
|
7
|
-
# (ab)use fetchurl to download a URL and add it to the nix store
|
8
|
-
# *without* already knowing its hash.
|
9
|
-
fetchurl {
|
10
|
-
inherit url;
|
11
|
-
sha256 = "0000000000000000000000000000000000000000000000000000";
|
12
|
-
downloadToTemp = true;
|
13
|
-
postFetch = ''
|
14
|
-
PATH="$PATH:${stdenv.lib.makeBinPath [ nix ]}"
|
15
|
-
|
16
|
-
sha256="$(nix-hash --base32 --type sha256 --flat "$downloadedFile")"
|
17
|
-
printf "%s\n" "$sha256"
|
18
|
-
|
19
|
-
file="$(dirname "$downloadedFile")/$(basename "$url")"
|
20
|
-
mv "$downloadedFile" "$file"
|
21
|
-
echo "adding to nix store..."
|
22
|
-
nix-store --add "$file"
|
23
|
-
|
24
|
-
echo "success! failing outer nix build..."
|
25
|
-
exit 1
|
26
|
-
'';
|
27
|
-
}
|