bundix 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +7 -0
  2. data/bin/bundix +44 -0
  3. data/lib/bundix/source.rb +114 -0
  4. data/lib/bundix.rb +109 -0
  5. metadata +47 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 463a40e4d1cb3c3f2d3734509fb2c5f71bdbaa1b
4
+ data.tar.gz: 1d38eaad6a27ac93279500dd86ce21477bb73259
5
+ SHA512:
6
+ metadata.gz: a2ff4f560cc61af3f388b10677bc660a678b4f12174916e47ed9de050dd2115758e4dcb70bc6f05fd0c33c7a7616de2b14c8eff32677369b7920b108f88a8830
7
+ data.tar.gz: 3eb1c4652f577833e51cc1682a283fb2484d19b6066eb1f9a2a78e84d6514c3f7a85632529982bde640e39d2ae616fbd4b3d23f90e7386270fcd6afbcc8a9797
data/bin/bundix ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ require_relative '../lib/bundix'
6
+
7
+ options = {}
8
+
9
+ op = OptionParser.new do |o|
10
+ o.on '--gemset=gemset.nix', 'path to the gemset.nix' do |value|
11
+ options[:gemset] = File.expand_path(value)
12
+ end
13
+
14
+ o.on '--lockfile=Gemfile.lock', 'path to the Gemfile.lock' do |value|
15
+ options[:lockfile] = File.expand_path(value)
16
+ end
17
+
18
+ o.on '-d', '--dependencies', 'include gem dependencies' do
19
+ options[:deps] = true
20
+ end
21
+
22
+ o.on '-q', '--quiet', 'only output errors' do
23
+ options[:quiet] = true
24
+ end
25
+
26
+ o.on '-v', '--version', 'show the version of bundix' do
27
+ puts Bundix::VERSION
28
+ exit
29
+ end
30
+ end
31
+
32
+ op.parse!
33
+ $VERBOSE = !options[:quiet]
34
+ gemset = Bundix.new(options).convert
35
+
36
+ tempfile = Tempfile.new('gemset.nix', encoding: 'UTF-8')
37
+ begin
38
+ Bundix.object2nix(gemset, 2, tempfile)
39
+ tempfile.close
40
+ FileUtils.cp(tempfile.path, options[:gemset])
41
+ ensure
42
+ tempfile.close!
43
+ tempfile.unlink
44
+ end
@@ -0,0 +1,114 @@
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
+
15
+ def sh(*args)
16
+ Bundix.sh(*args)
17
+ end
18
+
19
+ def nix_prefetch_url(*args)
20
+ sh(NIX_PREFETCH_URL, '--type', 'sha256', *args)
21
+ end
22
+
23
+ def nix_prefetch_git(uri, revision)
24
+ home = ENV['HOME']
25
+ ENV['HOME'] = '/homeless-shelter'
26
+ sh(NIX_PREFETCH_GIT, '--url', uri, '--rev', revision, '--hash', 'sha256', '--leave-dotGit')
27
+ ensure
28
+ ENV['HOME'] = home
29
+ end
30
+
31
+ def fetch_local_hash(spec)
32
+ spec.source.caches.each do |cache|
33
+ path = File.join(cache, "#{spec.name}-#{spec.version}.gem")
34
+ next unless File.file?(path)
35
+ begin
36
+ return nix_prefetch_url("file://#{path}")[SHA256_32]
37
+ rescue
38
+ end
39
+ end
40
+
41
+ nil
42
+ end
43
+
44
+ def fetch_remotes_hash(spec, remotes)
45
+ remotes.each do |remote|
46
+ begin
47
+ return fetch_remote_hash(spec, remote)
48
+ rescue
49
+ end
50
+ end
51
+
52
+ nil
53
+ end
54
+
55
+ def fetch_remote_hash(spec, remote)
56
+ hash = nil
57
+
58
+ if URI(remote).host == 'rubygems.org'
59
+ uri = "#{remote}/api/v1/versions/#{spec.name}.json"
60
+ puts "Getting SHA256 from: #{uri}" if $VERBOSE
61
+ open uri do |io|
62
+ versions = JSON.parse(io.read)
63
+ if found_version = versions.find{|obj| obj['number'] == spec.version.to_s }
64
+ hash = found_version['sha']
65
+ break
66
+ end
67
+ end
68
+ end
69
+
70
+ uri = "#{remote}/gems/#{spec.name}-#{spec.version}.gem"
71
+
72
+ if hash
73
+ begin
74
+ nix_prefetch_url(uri, hash)[SHA256_16]
75
+ rescue
76
+ nix_prefetch_url(uri)[SHA256_32]
77
+ end
78
+ else
79
+ nix_prefetch_url(uri)[SHA256_32]
80
+ end
81
+ end
82
+
83
+ def convert_rubygems
84
+ remotes = spec.source.remotes.map{|remote| remote.to_s.sub(/\/+$/, '') }
85
+ hash = fetch_local_hash(spec) || fetch_remotes_hash(spec, remotes)
86
+ hash = sh(NIX_HASH, '--type', 'sha256', '--to-base32', hash)[SHA256_32]
87
+ fail "couldn't fetch hash for #{spec.name}-#{spec.version}" unless hash
88
+ puts "#{hash} => #{spec.name}-#{spec.version}.gem" if $VERBOSE
89
+
90
+ {
91
+ type: 'gem',
92
+ remotes: remotes,
93
+ sha256: hash
94
+ }
95
+ end
96
+
97
+ def convert_git
98
+ revision = spec.source.options.fetch('revision')
99
+ uri = spec.source.options.fetch('uri')
100
+ hash = nix_prefetch_git(uri, revision)[/^\h{64}$/m]
101
+ hash = sh(NIX_HASH, '--type', 'sha256', '--to-base32', hash)[SHA256_32]
102
+ fail "couldn't fetch hash for #{spec.name}-#{spec.version}" unless hash
103
+ puts "#{hash} => #{uri}" if $VERBOSE
104
+
105
+ {
106
+ type: 'git',
107
+ url: uri.to_s,
108
+ rev: revision,
109
+ sha256: hash,
110
+ fetchSubmodules: false
111
+ }
112
+ end
113
+ end
114
+ end
data/lib/bundix.rb ADDED
@@ -0,0 +1,109 @@
1
+ require 'bundler'
2
+ require 'json'
3
+ require 'open-uri'
4
+ require 'open3'
5
+ require 'pp'
6
+
7
+ require_relative 'bundix/source'
8
+
9
+ class Bundix
10
+ VERSION = '2.0.0'
11
+
12
+ NIX_INSTANTIATE = 'nix-instantiate'
13
+ NIX_PREFETCH_URL = 'nix-prefetch-url'
14
+ NIX_PREFETCH_GIT = 'nix-prefetch-git'
15
+ NIX_HASH = 'nix-hash'
16
+
17
+ SHA256_32 = %r(^[a-z0-9]{52}$)
18
+ SHA256_16 = %r(^[a-f0-9]{64}$)
19
+
20
+ attr_reader :options
21
+
22
+ def initialize(options)
23
+ @options = {
24
+ gemset: './gemset.nix',
25
+ lockfile: './Gemfile.lock',
26
+ quiet: false,
27
+ tempfile: nil,
28
+ deps: false
29
+ }.merge(options)
30
+ end
31
+
32
+ def convert
33
+ cache = parse_gemset
34
+ lock = parse_lockfile
35
+
36
+ # reverse so git comes last
37
+ lock.specs.reverse_each.with_object({}) do |spec, gems|
38
+ name, cached = cache.find{|k, v|
39
+ k == spec.name &&
40
+ v['version'] == spec.version.to_s &&
41
+ v.dig('source', 'sha256').to_s.size == 52
42
+ }
43
+
44
+ if cached
45
+ gems[name] = cached
46
+ next
47
+ end
48
+
49
+ gems[spec.name] = {
50
+ version: spec.version.to_s,
51
+ source: Source.new(spec).convert
52
+ }
53
+
54
+ if options[:deps] && spec.dependencies.any?
55
+ gems[spec.name][:dependencies] = spec.dependencies.map(&:name) - ['bundler']
56
+ end
57
+ end
58
+ end
59
+
60
+ def parse_gemset
61
+ return {} unless File.file?(options[:gemset])
62
+ json = Bundix.sh(
63
+ NIX_INSTANTIATE, '--eval', '-E', "builtins.toJSON(import #{options[:gemset]})")
64
+ JSON.parse(json.strip.gsub(/\\"/, '"')[1..-2])
65
+ end
66
+
67
+ def parse_lockfile
68
+ Bundler::LockfileParser.new(File.read(options[:lockfile]))
69
+ end
70
+
71
+ def self.object2nix(obj, level = 2, out = '')
72
+ case obj
73
+ when Hash
74
+ out << "{\n"
75
+ obj.each do |k, v|
76
+ out << ' ' * level
77
+ if k.to_s =~ /^[a-zA-Z_-]+[a-zA-Z0-9_-]*$/
78
+ out << k.to_s
79
+ else
80
+ object2nix(k, level + 2, out)
81
+ end
82
+ out << ' = '
83
+ object2nix(v, level + 2, out)
84
+ out << (v.is_a?(Hash) ? "\n" : ";\n")
85
+ end
86
+ out << (' ' * (level - 2)) << (level == 2 ? '}' : '};')
87
+ when Array
88
+ out << '[' << obj.map{|o| o.to_str.dump }.join(' ') << ']'
89
+ when String
90
+ out << obj.dump
91
+ when Symbol
92
+ out << obj.to_s.dump
93
+ when true, false
94
+ out << obj.to_s
95
+ else
96
+ fail obj.inspect
97
+ end
98
+ end
99
+
100
+ def self.sh(*args)
101
+ out, status = Open3.capture2e(*args)
102
+ unless status.success?
103
+ puts "$ #{args.join(' ')}" if $VERBOSE
104
+ puts out if $VERBOSE
105
+ fail "command execution failed: #{status}"
106
+ end
107
+ out
108
+ end
109
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bundix
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael 'manveru' Fellinger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Creates Nix packages from Gemfiles.
14
+ email:
15
+ executables:
16
+ - bundix
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - bin/bundix
21
+ - lib/bundix.rb
22
+ - lib/bundix/source.rb
23
+ homepage: https://github.com/manveru/bundix
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 2.5.1
44
+ signing_key:
45
+ specification_version: 4
46
+ summary: Creates Nix packages from Gemfiles.
47
+ test_files: []