polycrystal 0.1.2 → 0.1.3

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 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: []