polycrystal 0.1.2 → 0.1.3

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
2
  SHA256:
3
- metadata.gz: 46441f58bfab74d37c13333f222535918c57664bbb25e41078e722a95a3be082
4
- data.tar.gz: 453ce9f790daa4fec95da21809e99b5b5c459b51b6ff0d2e005b8d8eab9d9224
3
+ metadata.gz: 6b792f50cc3fd49e84d1964fb3a494cad847b945685b887774ccb902e5d37092
4
+ data.tar.gz: b07a7239c6dfa5daeb20cfdf17c9dee8d592183509d7e2c25e16df0cf63582d6
5
5
  SHA512:
6
- metadata.gz: 127245a07887867cdb4de1902965cb2523b3a57fd1a065d1a9edcad18f687f034377c1824fd92e7b38fe37f4c19dbae92ba4c78848077c118c567601dd8a4673
7
- data.tar.gz: c269b0e48439cd52ae938f3fbdf85ba6b4c21c73b59839be93017971126ad03cb3394e97bdfcc81a3f9e799a3fc863001ad16e17b86a1597bf304d25b5de0e22
6
+ metadata.gz: fcc7135cbcadd6ccaa981e71192c3305f08e71c82f08883bb0820c938991fb0db7a39cd4cc06a181aae1df5ea59ecde1bc565252d9086a9bd2e29a017756a37c
7
+ data.tar.gz: 647f6a42daf887880b76e3a42fc3c9f995734e0a57f69cc18766b2e67780092f16aec941998cadf2f4b4830d5cbc73103db3e9678964da72098c825015b018bc
data/.gitignore CHANGED
@@ -19,3 +19,4 @@ ext/polycrystal/Makefile
19
19
  .byebug_history
20
20
  /.vscode
21
21
  Gemfile.lock
22
+ polycrystal-*.gem
data/README.md CHANGED
@@ -71,21 +71,42 @@ Polycrystal::Registry.register(
71
71
  modules: ['CrystalModule']
72
72
  )
73
73
 
74
- # directory for entrypoint and compiled library.
74
+ # cpmpile and load
75
+ # should be called once, after all Polycrystal::Registry#register calls
76
+ Polycrystal.load
77
+ ```
78
+
79
+ Set custom properties
80
+ ```ruby
81
+ # directory for crystal entrypoint and compiled library.
75
82
  build_path = File.expand_path("#{__dir__}/build")
76
83
  FileUtils.mkdir_p(build_path)
77
84
 
78
- # cpmpile and load
79
- # should be called once, after all Polycrystal::Registry#register calls
80
- Polycrystal::Loader.new(build_path: build_path).load
85
+
86
+ Polycrystal.load(
87
+ # directory for crystal entrypoint and compiled library.
88
+ build_path: build_path,
89
+ # used to find lib with installed shards. SHARDS_INSTALL_PATH is used if present
90
+ shardfile: "./crystal/shard.yml",
91
+ # Polycrystal::NO_PRECOMPILE - compile everytime
92
+ # Polycrystal::LAZY_COMPILE - compile if not yet compiled
93
+ # Polycrystal::REQUIRE_AOT - not compile, require to be precompiled
94
+ precompile: Polycrystal::LAZY_COMPILE, # by default
95
+ )
81
96
  ```
82
97
 
83
98
  ## TODO
84
99
 
85
100
  1. Test suite
101
+ 2. Remove C code from this extension.
102
+ * C code is not required. Crystal code may be directly compiled to extension and loaded using standard `requre`
103
+ * To achieve that, anyolite glue files should be compiled to object files and linked to existing ruby correctly. I got segfault when I built glue files outside of ruby extension
86
104
  2. Code should not be recompiled if it was not changed
105
+ * Rudimentary implementation is present, but more stable is preferrable: `Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE)`
87
106
  3. Ability to precompile all code on demand, e.g. for Docker images
88
- 4. make shards work. Anyolite may be loaded from shards, if my patches are merged, or better alternatives implemented
107
+ * It is possible to do that right now by calling `Polycrystal.load(precompile: Polycrystal::LAZY_COMPILE)` in separate command, while loading Crystal module using `Polycrystal.load(precompile: Polycrystal::REQUIRE_AOT)`
108
+ 4. make shards work. DONE, except:
109
+ * Anyolite can't be loaded from shards, because it's postinstall script downloads and compiles it's own mruby
89
110
 
90
111
  ## Development
91
112
 
@@ -1,32 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'zlib'
4
+
3
5
  module Polycrystal
4
6
  class Compiler
5
- attr_reader :build_path, :registry
7
+ attr_reader :build_path, :shardfile, :registry, :precompile
6
8
 
7
- def initialize(build_path:, registry: Polycrystal::Registry.instance)
9
+ def initialize(build_path:, shardfile: nil, registry: Polycrystal::Registry.instance, precompile: LAZY_COMPILE)
8
10
  @build_path = build_path
9
11
  @registry = registry
10
- # load anyolite
11
- add_anyolite
12
+ @shardfile = shardfile
13
+ @precompile = precompile
12
14
  end
13
15
 
14
16
  def prepare
15
17
  # load anyolite
16
18
  add_anyolite
19
+ # add lib with shards
20
+ use_shards
17
21
  # write crystal entrypoint
18
22
  in_file.write(entrypoint)
19
23
  in_file.close
20
24
  end
21
25
 
22
26
  def execute
23
- # run compiler
24
- puts command
25
- raise 'Failed to compile crystal module' unless system(command)
27
+ if precompile == NO_PRECOMPILE
28
+ compile
29
+ elsif precompile == REQUIRE_AOT
30
+ raise 'Crystal module should be compiled before run' unless File.exist?(outfile)
31
+ else
32
+ compile unless File.exist?(outfile)
33
+ end
26
34
 
27
35
  outfile
28
36
  end
29
37
 
38
+ private
39
+
40
+ def use_shards
41
+ shard_path = ENV.fetch('SHARDS_INSTALL_PATH') do
42
+ return unless shardfile
43
+
44
+ shardfile_path = File.expand_path(shardfile)
45
+ return unless File.exist?(shardfile_path)
46
+
47
+ "#{File.dirname(shardfile_path)}/lib"
48
+ end
49
+ registry.register(path: shard_path)
50
+ end
51
+
30
52
  def add_anyolite
31
53
  registry.register(
32
54
  path: find_anyolite,
@@ -87,16 +109,16 @@ module Polycrystal
87
109
  end
88
110
 
89
111
  def crystal_link_flags
90
- case RUBY_PLATFORM
91
- when /darwin/
92
- "-dynamic -bundle"
93
- when /linux/
94
- mapfile = File.expand_path("#{build_path}/version.map")
95
- File.write(mapfile, "VERS_1.1 {\tglobal:\t\t*;};")
96
- "-shared -Wl,--version-script=#{mapfile}"
97
- else
98
- raise "Unknown platform"
99
- end
112
+ case RUBY_PLATFORM
113
+ when /darwin/
114
+ '-dynamic -bundle'
115
+ when /linux/
116
+ mapfile = File.expand_path("#{build_path}/version.map")
117
+ File.write(mapfile, "VERS_1.1 {\tglobal:\t\t*;};")
118
+ "-shared -Wl,--version-script=#{mapfile}"
119
+ else
120
+ raise 'Unknown platform'
121
+ end
100
122
  end
101
123
 
102
124
  def pad_line(line, n)
@@ -112,31 +134,31 @@ module Polycrystal
112
134
  end
113
135
 
114
136
  def outfile
115
- File.expand_path("#{build_path}/polycrystal_module.#{lib_ext}")
137
+ @outfile ||= File.expand_path("#{build_path}/polycrystal#{compile_hash}_module.#{lib_ext}")
116
138
  end
117
139
 
118
140
  def lib_ext
119
- case RUBY_PLATFORM
120
- when /darwin/
121
- "bundle"
122
- when /linux/
123
- "so"
124
- else
125
- raise "Unknown platform"
126
- end
141
+ case RUBY_PLATFORM
142
+ when /darwin/
143
+ 'bundle'
144
+ when /linux/
145
+ 'so'
146
+ else
147
+ raise 'Unknown platform'
148
+ end
127
149
  end
128
150
 
129
151
  def include_paths
130
- existing = `#{compiler_cmd} env`.split("\n").find { |line| line.start_with?('CRYSTAL_PATH') }
131
- [existing, *crystal_paths].join(':')
152
+ existing = `#{compiler_cmd} env CRYSTAL_PATH`.strip
153
+ ["CRYSTAL_PATH=#{existing}", *crystal_paths].join(':')
132
154
  end
133
155
 
134
156
  def anyolite_glue
135
157
  "-L#{RbConfig::CONFIG['libdir']} #{RbConfig::CONFIG['LIBRUBYARG_SHARED']} " \
136
- "#{File.expand_path("#{__dir__}/../../ext/polycrystal/data_helper.o")} " \
137
- "#{File.expand_path("#{__dir__}/../../ext/polycrystal/error_helper.o")} " \
138
- "#{File.expand_path("#{__dir__}/../../ext/polycrystal/return_functions.o")} " \
139
- "#{File.expand_path("#{__dir__}/../../ext/polycrystal/script_helper.o")} "
158
+ "#{File.expand_path("#{__dir__}/../../ext/polycrystal/data_helper.o")} " \
159
+ "#{File.expand_path("#{__dir__}/../../ext/polycrystal/error_helper.o")} " \
160
+ "#{File.expand_path("#{__dir__}/../../ext/polycrystal/return_functions.o")} " \
161
+ "#{File.expand_path("#{__dir__}/../../ext/polycrystal/script_helper.o")} "
140
162
  end
141
163
 
142
164
  def compiler_cmd
@@ -162,5 +184,20 @@ module Polycrystal
162
184
 
163
185
  local_path
164
186
  end
187
+
188
+ def compile
189
+ # run compiler
190
+ puts command
191
+ raise 'Failed to compile crystal module' unless system(command)
192
+ end
193
+
194
+ def compile_hash
195
+ paths = crystal_paths.sort + [in_file.path]
196
+ paths.map { |path| path_hash(path) }.reduce(:^).to_s(32)
197
+ end
198
+
199
+ def path_hash(path)
200
+ Zlib.crc32(`ls -lRF #{path}`)
201
+ end
165
202
  end
166
203
  end
@@ -2,18 +2,13 @@
2
2
 
3
3
  module Polycrystal
4
4
  class Loader
5
- attr_reader :build_path, :registry
5
+ attr_reader :compiler
6
6
 
7
- def initialize(build_path:, registry: Polycrystal::Registry.instance)
8
- @build_path = build_path
9
- @registry = registry
7
+ def initialize(compiler:)
8
+ @compiler = compiler
10
9
  end
11
10
 
12
11
  def load
13
- compiler = Polycrystal::Compiler.new(
14
- build_path: build_path,
15
- registry: registry
16
- )
17
12
  compiler.prepare
18
13
  library = compiler.execute
19
14
  load_library(library) # load_library is defined in C file
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polycrystal
4
- VERSION = '0.1.2'
4
+ VERSION = '0.1.3'
5
5
  end
data/lib/polycrystal.rb CHANGED
@@ -8,5 +8,19 @@ require 'polycrystal/loader'
8
8
 
9
9
  module Polycrystal
10
10
  class Error < StandardError; end
11
- # Your code goes here...
11
+
12
+ PRECOMPILE = [
13
+ NO_PRECOMPILE = :no_precompile,
14
+ LAZY_COMPILE = :lazy_compile,
15
+ REQUIRE_AOT = :require_compiled
16
+ ].freeze
17
+
18
+ def self.load(build_path: nil, shardfile: nil, precompile: LAZY_COMPILE)
19
+ build_path ||= "#{Dir.pwd}/build"
20
+ shardfile ||= "#{Dir.pwd}/shard.yml" if File.exist?("#{Dir.pwd}/shard.yml")
21
+ shardfile ||= "#{Dir.pwd}/crystal/shard.yml" if File.exist?("#{Dir.pwd}/crystal/shard.yml")
22
+
23
+ compiler = Polycrystal::Compiler.new(build_path: build_path, shardfile: shardfile, precompile: precompile)
24
+ Polycrystal::Loader.new(compiler: compiler).load
25
+ end
12
26
  end
@@ -1 +1,2 @@
1
- /build
1
+ /build
2
+ /crystal/lib
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- polycrystal (0.1.1)
4
+ polycrystal (0.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,8 +1,14 @@
1
+ require "jwt"
2
+
1
3
  class CrystalModule
2
4
  class SomeThing
3
5
  def some_method
4
6
  69.0
5
7
  end
8
+
9
+ def check_deps
10
+ JWT.encode({"test" => "key"}, "SecretKey", JWT::Algorithm::HS256)
11
+ end
6
12
  end
7
13
 
8
14
  class CrystalClass
@@ -0,0 +1,14 @@
1
+ version: 2.0
2
+ shards:
3
+ bindata:
4
+ git: https://github.com/spider-gazelle/bindata.git
5
+ version: 1.10.0
6
+
7
+ jwt:
8
+ git: https://github.com/crystal-community/jwt.git
9
+ version: 1.6.0
10
+
11
+ openssl_ext:
12
+ git: https://github.com/spider-gazelle/openssl_ext.git
13
+ version: 2.2.0
14
+
@@ -0,0 +1,14 @@
1
+ name: sample_project
2
+ version: 0.1.0
3
+
4
+ # authors:
5
+ # - name <email@example.com>
6
+
7
+ # description: |
8
+ # Short description of sample_project
9
+
10
+ dependencies:
11
+ jwt:
12
+ github: crystal-community/jwt
13
+
14
+ # license: MIT
@@ -11,8 +11,4 @@ Polycrystal::Registry.register(
11
11
  modules: ['CrystalModule']
12
12
  )
13
13
 
14
- build_path = File.expand_path("#{__dir__}/build")
15
-
16
- FileUtils.mkdir_p(build_path)
17
-
18
- Polycrystal::Loader.new(build_path: build_path).load
14
+ Polycrystal.load
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polycrystal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrii Hrushetskyi
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-09-09 00:00:00.000000000 Z
11
+ date: 2022-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,6 +100,8 @@ files:
100
100
  - sample_project/Gemfile
101
101
  - sample_project/Gemfile.lock
102
102
  - sample_project/crystal/sample.cr
103
+ - sample_project/crystal/shard.lock
104
+ - sample_project/crystal/shard.yml
103
105
  - sample_project/sample.rb
104
106
  homepage: https://github.com/ahrushetskyi/polycrystal
105
107
  licenses:
@@ -109,7 +111,7 @@ metadata:
109
111
  source_code_uri: https://github.com/ahrushetskyi/polycrystal
110
112
  changelog_uri: https://github.com/ahrushetskyi/polycrystal/CHANGELOG.md
111
113
  rubygems_mfa_required: 'true'
112
- post_install_message:
114
+ post_install_message:
113
115
  rdoc_options: []
114
116
  require_paths:
115
117
  - lib
@@ -125,8 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
127
  - !ruby/object:Gem::Version
126
128
  version: '0'
127
129
  requirements: []
128
- rubygems_version: 3.0.3.1
129
- signing_key:
130
+ rubygems_version: 3.2.33
131
+ signing_key:
130
132
  specification_version: 4
131
133
  summary: Integrate Crystal into ruby
132
134
  test_files: []