bundix 2.3.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
}
|