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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 623983fdd769dae25b35ce73300b7c15e2e05406
4
- data.tar.gz: 467820098d81bee233d3292e0a26cca9924e5c62
2
+ SHA256:
3
+ metadata.gz: 3fbcd152e7e9e610f2357bd6ee0658d84fa9bbcd497c3ced755d7efafb9547a9
4
+ data.tar.gz: 9f8eb407611278f324960b8393e7452d4b9385434cfbc028db61dbddc7335f3d
5
5
  SHA512:
6
- metadata.gz: 730d8af2547d66f2fb33e1e5dd5c1afafec4f30dbc896de6f942552f485ae187e001f65ea786486553110f813e798e7cb8010f9c4012f9a82b686cc9b77bf359
7
- data.tar.gz: e8e3ffa6148a782fe38c44128e11c86e836681eec0e03fddcccd2800b96a430f8f48f5e0c0923ef4b87787c6ccb14e3e5de18287a1acfe5a36c35f9bf9fa0e62
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
- require 'optparse'
4
- require 'tmpdir'
5
- require 'tempfile'
6
- require 'pathname'
3
+ require_relative '../lib/bundix/commandline'
7
4
 
8
- require_relative '../lib/bundix'
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
- gems[spec.name]['dependencies'] = spec.dependencies.map(&:name) - ['bundler']
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 convert_spec(spec, cache)
46
- {spec.name => {version: spec.version.to_s, source: Source.new(spec).convert}}
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
- NIX_INSTANTIATE, '--eval', '-E', "builtins.toJSON(import #{path})")
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.capture2e(*args)
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
@@ -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 Source < Struct.new(:spec)
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
- if uri.user && uri.password
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
- open(uri, 'r', 0600, open_options) do |net|
29
- File.open(file, 'wb+') { |local|
30
- File.copy_stream(net, local)
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.expand_path('~/.cache/bundix')
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('nix-prefetch-url', '--type', 'sha256', "file://#{file}")
47
- .force_encoding('UTF-8').strip
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
- sh(NIX_PREFETCH_GIT, '--url', uri, '--rev', revision, '--hash', 'sha256', '--leave-dotGit')
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.name}-#{spec.version}.gem")
96
+ path = File.join(cache, "#{spec.full_name}.gem")
64
97
  next unless File.file?(path)
65
- hash = nix_prefetch_url("file://#{path}")[SHA256_32]
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.name}-#{spec.version}.gem"
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.name}-#{spec.version}" unless hash
97
- hash = sh(NIX_HASH, '--type', 'sha256', '--to-base32', hash)[SHA256_32]
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
- output = nix_prefetch_git(uri, revision)
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.name}-#{spec.version}" unless hash
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: false }
174
+ fetchSubmodules: submodules }
119
175
  end
120
176
  end
121
177
  end
@@ -1,3 +1,3 @@
1
1
  class Bundix
2
- VERSION = '2.3.0'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -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,3 @@
1
+ {
2
+ <% obj.sort_by{|k,v| k.to_s.downcase}.each do |(k,v)| %><%= indent %><%= serialize_key(k) %> = <%= sub(v,2)%>;
3
+ <%end%><%= outdent%>}
@@ -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.3.0
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: 2017-07-05 00:00:00.000000000 Z
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/fetchurl-force.nix
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.10
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
- }