diametric 0.1.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +28 -0
- data/Jarfile +20 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +49 -0
- data/bin/datomic-rest +33 -0
- data/bin/download-datomic +13 -0
- data/datomic_version.yml +4 -0
- data/diametric-java.gemspec +39 -0
- data/ext/diametric/DiametricCollection.java +147 -0
- data/ext/diametric/DiametricConnection.java +113 -0
- data/ext/diametric/DiametricDatabase.java +107 -0
- data/ext/diametric/DiametricEntity.java +90 -0
- data/ext/diametric/DiametricListenableFuture.java +47 -0
- data/ext/diametric/DiametricObject.java +66 -0
- data/ext/diametric/DiametricPeer.java +414 -0
- data/ext/diametric/DiametricService.java +102 -0
- data/ext/diametric/DiametricUUID.java +61 -0
- data/ext/diametric/DiametricUtils.java +183 -0
- data/lib/boolean_type.rb +3 -0
- data/lib/diametric.rb +42 -0
- data/lib/diametric/config.rb +54 -0
- data/lib/diametric/config/environment.rb +42 -0
- data/lib/diametric/entity.rb +659 -0
- data/lib/diametric/errors.rb +13 -0
- data/lib/diametric/generators/active_model.rb +42 -0
- data/lib/diametric/persistence.rb +48 -0
- data/lib/diametric/persistence/common.rb +82 -0
- data/lib/diametric/persistence/peer.rb +154 -0
- data/lib/diametric/persistence/rest.rb +107 -0
- data/lib/diametric/query.rb +259 -0
- data/lib/diametric/railtie.rb +52 -0
- data/lib/diametric/rest_service.rb +74 -0
- data/lib/diametric/service_base.rb +77 -0
- data/lib/diametric/transactor.rb +86 -0
- data/lib/diametric/version.rb +3 -0
- data/lib/diametric_service.jar +0 -0
- data/lib/tasks/create_schema.rb +27 -0
- data/lib/tasks/diametric_config.rb +45 -0
- data/lib/value_enums.rb +8 -0
- data/spec/conf_helper.rb +55 -0
- data/spec/config/free-transactor-template.properties +73 -0
- data/spec/config/logback.xml +59 -0
- data/spec/data/seattle-data0.dtm +452 -0
- data/spec/data/seattle-data1.dtm +326 -0
- data/spec/developer_create_sample.rb +39 -0
- data/spec/developer_query_spec.rb +120 -0
- data/spec/diametric/config_spec.rb +60 -0
- data/spec/diametric/entity_spec.rb +476 -0
- data/spec/diametric/peer_api_spec.rb +147 -0
- data/spec/diametric/persistence/peer_many2many_spec.rb +76 -0
- data/spec/diametric/persistence/peer_spec.rb +27 -0
- data/spec/diametric/persistence/rest_spec.rb +30 -0
- data/spec/diametric/persistence_spec.rb +59 -0
- data/spec/diametric/query_spec.rb +118 -0
- data/spec/diametric/rest_service_spec.rb +56 -0
- data/spec/diametric/transactor_spec.rb +68 -0
- data/spec/integration_spec.rb +107 -0
- data/spec/parent_child_sample.rb +42 -0
- data/spec/peer_integration_spec.rb +121 -0
- data/spec/peer_seattle_spec.rb +200 -0
- data/spec/rc2013_seattle_big.rb +82 -0
- data/spec/rc2013_seattle_small.rb +60 -0
- data/spec/rc2013_simple_sample.rb +72 -0
- data/spec/seattle_integration_spec.rb +106 -0
- data/spec/simple_validation_sample.rb +31 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/support/entities.rb +157 -0
- data/spec/support/gen_entity_class.rb +9 -0
- data/spec/support/persistence_examples.rb +104 -0
- data/spec/test_version_file.yml +4 -0
- metadata +290 -0
@@ -0,0 +1,259 @@
|
|
1
|
+
require 'diametric'
|
2
|
+
|
3
|
+
module Diametric
|
4
|
+
# +Query+ objects are used to generate Datomic queries, whether to
|
5
|
+
# send via an external client or via the persistence API. The two
|
6
|
+
# methods used to generate a query are +.where+ and +.filter+, both
|
7
|
+
# of which are chainable. To get the query data and arguments for a
|
8
|
+
# +Query+, use the +data+ method.
|
9
|
+
#
|
10
|
+
# If you are using a persistence API, you can ask +Query+ to get the
|
11
|
+
# results of a Datomic query. +Diametric::Query+ is an
|
12
|
+
# +Enumerable+. To get the results of a query, use +Enumerable+
|
13
|
+
# methods such as +.each+ or +.first+. +Query+ also provides a
|
14
|
+
# +.all+ method to run the query and get the results.
|
15
|
+
class Query
|
16
|
+
include Enumerable
|
17
|
+
|
18
|
+
attr_reader :conditions, :filters, :filter_attrs, :model, :connection, :resolve
|
19
|
+
|
20
|
+
# Create a new Datomic query.
|
21
|
+
#
|
22
|
+
# @param model [Entity] This model must include +Datomic::Entity+. Including
|
23
|
+
# a persistence module is optional.
|
24
|
+
def initialize(model, connection_or_database=nil, resolve=false)
|
25
|
+
@model = model
|
26
|
+
@conditions = {}
|
27
|
+
@filters = []
|
28
|
+
@filter_attrs = []
|
29
|
+
@conn_or_db = connection_or_database
|
30
|
+
@resolve = resolve
|
31
|
+
end
|
32
|
+
|
33
|
+
# Add conditions to your Datomic query. Conditions check for equality
|
34
|
+
# against entity attributes. In addition, you can add conditions for
|
35
|
+
# use as variables in filters.
|
36
|
+
#
|
37
|
+
# @example Looking for mice named Wilbur.
|
38
|
+
# Query.new(Mouse).conditions(:name => "Wilbur")
|
39
|
+
#
|
40
|
+
# @param conditions [Hash] Datomic variables and values.
|
41
|
+
# @return [Query]
|
42
|
+
def where(conditions)
|
43
|
+
query = self.dup
|
44
|
+
query.conditions = query.conditions.merge(conditions)
|
45
|
+
query
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a filter to your Datomic query. Filters are known as expression clause
|
49
|
+
# predicates in the {Datomic query documentation}[http://docs.datomic.com/query.html].
|
50
|
+
#
|
51
|
+
# A filter can be in one of two forms. In the first, you pass a
|
52
|
+
# series of arguments. Any Ruby symbol given in this form will be
|
53
|
+
# converted to a EDN symbol. If the symbol is the same as one of
|
54
|
+
# the queried model's attributes or as a key passed to +where+, it
|
55
|
+
# will be prefixed with a +?+ so that it becomes a Datalog
|
56
|
+
# variable. In the second form, you pass
|
57
|
+
# {EDN}[https://github.com/relevance/edn-ruby] representing a
|
58
|
+
# Datomic predicate to +filter+. No conversion is done on this
|
59
|
+
# filter and it must be an EDN list.
|
60
|
+
#
|
61
|
+
# @example Passing arguments to be converted.
|
62
|
+
# query.filter(:>, :age, 21)
|
63
|
+
#
|
64
|
+
# @example Passing EDN, which will not be converted.
|
65
|
+
# query.filter(EDN::Type::List.new(EDN::Type::Symbol(">"),
|
66
|
+
# EDN::Type::Symbol("?age"),
|
67
|
+
# 21))
|
68
|
+
# # or, more simply
|
69
|
+
# query.filter(~[~">", ~"?age", 21])
|
70
|
+
#
|
71
|
+
# @param filter [Array] Either one +EDN::Type::List+ or a number of arguments
|
72
|
+
# that will be converted into a Datalog query.
|
73
|
+
# @return [Query]
|
74
|
+
def filter(*filter)
|
75
|
+
return peer_filter(filter) if self.model.instance_variable_get("@peer")
|
76
|
+
query = self.dup
|
77
|
+
|
78
|
+
if filter.first.is_a?(EDN::Type::List)
|
79
|
+
filter = filter.first
|
80
|
+
else
|
81
|
+
filter = filter.map { |e| convert_filter_element(e) }
|
82
|
+
filter = EDN::Type::List.new(*filter)
|
83
|
+
end
|
84
|
+
|
85
|
+
query.filters += [[filter]]
|
86
|
+
query
|
87
|
+
end
|
88
|
+
|
89
|
+
def peer_filter(*filter)
|
90
|
+
query = self.dup
|
91
|
+
|
92
|
+
if filter.first.is_a?(Array)
|
93
|
+
filter = filter.first
|
94
|
+
end
|
95
|
+
filter_attrs << filter[1].to_s
|
96
|
+
filter[1] = "?#{filter[1].to_s}"
|
97
|
+
filter = filter.tap {|e| e.to_s }.join(" ")
|
98
|
+
filter = "[(#{filter})]"
|
99
|
+
|
100
|
+
query.filters << filter
|
101
|
+
query
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Loop through the query results. In order to use +each+, your model *must*
|
106
|
+
# include a persistence API. At a minimum, it must have a +.q+ method that
|
107
|
+
# returns an +Enumerable+ object.
|
108
|
+
#
|
109
|
+
# @yield [Entity] An instance of the model passed to +Query+.
|
110
|
+
def each
|
111
|
+
# TODO check to see if the model has a `.q` method and give
|
112
|
+
# an appropriate error if not.
|
113
|
+
res = model.q(*data, @conn_or_db)
|
114
|
+
collapse_results(res).each do |entity|
|
115
|
+
if self.model.instance_variable_get("@peer") && @resolve
|
116
|
+
yield model.from_dbid_or_entity(entity.first.to_java, @conn_or_db, @resolve)
|
117
|
+
elsif self.model.instance_variable_get("@peer")
|
118
|
+
yield entity.first.to_java
|
119
|
+
# The map is for compatibility with Java peer persistence.
|
120
|
+
# TODO remove if possible
|
121
|
+
else
|
122
|
+
yield model.from_query(entity.map { |x| x }, @conn_or_db, @resolve)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return all query results.
|
128
|
+
#
|
129
|
+
# @return [Array<Entity>] Query results.
|
130
|
+
def all
|
131
|
+
map { |x| x }
|
132
|
+
end
|
133
|
+
|
134
|
+
# Create a Datomic query from the conditions and filters passed to this
|
135
|
+
# +Query+ object.
|
136
|
+
#
|
137
|
+
# @return [Array(Array, Array)] The first element of the array returned
|
138
|
+
# is the Datomic query composed of Ruby data. The second element is
|
139
|
+
# the arguments that used with the query.
|
140
|
+
def data
|
141
|
+
return peer_data if self.model.instance_variable_get("@peer")
|
142
|
+
|
143
|
+
vars = model.attribute_names.map { |attribute| ~"?#{attribute}" }
|
144
|
+
|
145
|
+
from = conditions.map { |k, _| ~"?#{k}" }
|
146
|
+
|
147
|
+
clauses = model.attribute_names.map { |attribute|
|
148
|
+
[~"?e", model.namespace(model.prefix, attribute), ~"?#{attribute}"]
|
149
|
+
}
|
150
|
+
clauses += filters
|
151
|
+
|
152
|
+
args = conditions.map { |_, v| v }
|
153
|
+
|
154
|
+
query = [
|
155
|
+
:find, ~"?e", *vars,
|
156
|
+
:in, ~"\$", *from,
|
157
|
+
:where, *clauses
|
158
|
+
]
|
159
|
+
|
160
|
+
[query, args]
|
161
|
+
end
|
162
|
+
|
163
|
+
def peer_data
|
164
|
+
if conditions.empty? && filters.empty?
|
165
|
+
args = [model.prefix]
|
166
|
+
query = <<-EOQ
|
167
|
+
[:find ?e
|
168
|
+
:in $ [?include-ns ...]
|
169
|
+
:where
|
170
|
+
[?e ?aid ?v]
|
171
|
+
[?aid :db/ident ?a]
|
172
|
+
[(namespace ?a) ?ns]
|
173
|
+
[(= ?ns ?include-ns)]]
|
174
|
+
EOQ
|
175
|
+
else
|
176
|
+
unless conditions.empty?
|
177
|
+
clauses = conditions.keys.inject("") do |memo, attribute|
|
178
|
+
memo + "[?e " + model.namespace(model.prefix, attribute) + " ?#{attribute} ] "
|
179
|
+
end
|
180
|
+
from = conditions.inject("[") {|memo, kv| memo + "?#{kv.shift} "} +"]"
|
181
|
+
args = conditions.map { |_, v| v }
|
182
|
+
end
|
183
|
+
|
184
|
+
unless filter_attrs.empty?
|
185
|
+
clauses ||= ""
|
186
|
+
clauses = filter_attrs.inject(clauses) do |memo, attribute|
|
187
|
+
memo + "[?e " + model.namespace(model.prefix, attribute) + " ?#{attribute} ] "
|
188
|
+
end
|
189
|
+
end
|
190
|
+
query = "[:find ?e :in $ #{from} :where #{clauses} #{filters.join}]"
|
191
|
+
end
|
192
|
+
|
193
|
+
[query, args]
|
194
|
+
end
|
195
|
+
|
196
|
+
protected
|
197
|
+
|
198
|
+
def conditions=(conditions)
|
199
|
+
@conditions = conditions
|
200
|
+
end
|
201
|
+
|
202
|
+
def filters=(filters)
|
203
|
+
@filters = filters
|
204
|
+
end
|
205
|
+
|
206
|
+
def convert_filter_element(element)
|
207
|
+
if element.is_a?(Symbol)
|
208
|
+
if model.attribute_names.include?(element) || @conditions.keys.include?(element)
|
209
|
+
EDN::Type::Symbol.new("?#{element}")
|
210
|
+
else
|
211
|
+
EDN::Type::Symbol.new(element.to_s)
|
212
|
+
end
|
213
|
+
else
|
214
|
+
element
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def collapse_results(res)
|
219
|
+
return res unless @resolve
|
220
|
+
|
221
|
+
res.group_by(&:first).map do |dbid, results|
|
222
|
+
# extract dbid from results
|
223
|
+
# NOTE: we prefer to_a.drop(1) over block arg decomposition because
|
224
|
+
# result may be a Java::ClojureLang::PersistentVector
|
225
|
+
results = results.map {|result| result.to_a.drop(1) }
|
226
|
+
|
227
|
+
unless results.flatten.empty?
|
228
|
+
# Group values from all results into one result set
|
229
|
+
# [["b", 123], ["c", 123]] #=> [["b", "c"], [123, 123]]
|
230
|
+
grouped_values = results.transpose
|
231
|
+
attr_grouped_values = grouped_values[0...model.attributes.size]
|
232
|
+
enum_grouped_values = grouped_values[model.attributes.size..-1]
|
233
|
+
|
234
|
+
# Attach attribute names to each collection of values
|
235
|
+
# => [[:letters, ["b", "c"]], [:number, [123, 123]]]
|
236
|
+
attr_to_values = model.attributes.keys.zip(attr_grouped_values)
|
237
|
+
|
238
|
+
# Retain cardinality/many attributes as a collection,
|
239
|
+
# but pick only one value for cardinality/one attributes
|
240
|
+
collapsed_values = attr_to_values.map do |attr, values|
|
241
|
+
if model.attributes[attr][:cardinality] == :many
|
242
|
+
values
|
243
|
+
elsif model.attributes[attr][:value_type] == "ref" &&
|
244
|
+
model.enum_names.include?(attr)
|
245
|
+
enum_grouped_values.shift.first
|
246
|
+
else
|
247
|
+
values.first
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Returning a singular result for each dbid
|
252
|
+
[dbid, *collapsed_values]
|
253
|
+
else
|
254
|
+
[dbid]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "diametric"
|
3
|
+
require "diametric/config"
|
4
|
+
|
5
|
+
require "rails"
|
6
|
+
|
7
|
+
require 'diametric/generators/active_model'
|
8
|
+
|
9
|
+
module Rails
|
10
|
+
module Diametric
|
11
|
+
class Railtie < Rails::Railtie
|
12
|
+
|
13
|
+
config.app_generators.orm :diametric
|
14
|
+
|
15
|
+
# Initialize Diametric. This will look for a diametric.yml in the config
|
16
|
+
# directory and configure diametric appropriately.
|
17
|
+
initializer "setup database" do
|
18
|
+
config_file = Rails.root.join("config", "diametric.yml")
|
19
|
+
if config_file.file?
|
20
|
+
begin
|
21
|
+
::Diametric::Config.load_and_connect!(config_file)
|
22
|
+
rescue Exception => e
|
23
|
+
handle_configuration_error(e)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# After initialization we will warn the user if we can't find a diametric.yml and
|
29
|
+
# alert to create one.
|
30
|
+
initializer "warn when configuration is missing" do
|
31
|
+
config.after_initialize do
|
32
|
+
unless Rails.root.join("config", "diametric.yml").file? || ::Diametric::Config.configured?
|
33
|
+
puts "\nDiametric config not found. Create a config file at: config/diametric.yml"
|
34
|
+
puts "to generate one run: rails generate diametric:config\n\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rake_tasks do
|
39
|
+
require "#{File.join(File.dirname(__FILE__), "..", "tasks", "create_schema.rb")}"
|
40
|
+
require "#{File.join(File.dirname(__FILE__), "..", "tasks", "diametric_config.rb")}"
|
41
|
+
end
|
42
|
+
# Rails runs all initializers first before getting into any generator
|
43
|
+
# code, so we have no way in the initializer to know if we are
|
44
|
+
# generating a diametric.yml. So instead of failing, we catch all the
|
45
|
+
# errors and print them out.
|
46
|
+
def handle_configuration_error(e)
|
47
|
+
puts "There is a configuration error with the current diametric.yml."
|
48
|
+
puts e.message
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'diametric/service_base'
|
2
|
+
|
3
|
+
module Diametric
|
4
|
+
class RestService
|
5
|
+
include ::Diametric::ServiceBase
|
6
|
+
class << self
|
7
|
+
def datomic_command(datomic_home)
|
8
|
+
classpath = datomic_classpath(datomic_home)
|
9
|
+
command = ["java -server -Xmx1g", "-cp", classpath, "clojure.main", "-i", "#{datomic_home}/bin/bridge.clj", "--main datomic.rest"].flatten.join(" ")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :datomic_version, :datomic_version_no, :datomic_home, :pid
|
14
|
+
attr_accessor :host, :port, :db_alias, :uri
|
15
|
+
|
16
|
+
def initialize(conf="datomic_version.yml", dest="vendor/datomic")
|
17
|
+
@conf = conf
|
18
|
+
@dest = dest
|
19
|
+
@datomic_version = RestService.datomic_version(conf)
|
20
|
+
@datomic_home = File.join(File.dirname(__FILE__), "../..", dest, @datomic_version)
|
21
|
+
@datomic_version_no = RestService.datomic_version_no(@datomic_version)
|
22
|
+
@pid = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def start(opts={})
|
26
|
+
return if @pid
|
27
|
+
RestService.download(@conf, @dest)
|
28
|
+
command = RestService.datomic_command(@datomic_home)
|
29
|
+
|
30
|
+
require 'socket'
|
31
|
+
@host = opts[:host] ? opts[:host] : Socket.gethostname
|
32
|
+
@port = opts[:port] ? opts[:port] : 9000
|
33
|
+
@db_alias = opts[:db_alias] ? opts[:db_alias] : "free"
|
34
|
+
@uri = opts[:uri] ? opts[:uri] : "datomic:mem://"
|
35
|
+
|
36
|
+
uri = URI("http://#{@host}:#{@port}/")
|
37
|
+
|
38
|
+
unless port_available?(uri)
|
39
|
+
puts "Somebody is using #{@port}. Choose other."
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
temp_pid = spawn("#{command} -p #{@port} #{@db_alias} #{@uri}")
|
44
|
+
|
45
|
+
@pid = temp_pid if ready?(uri)
|
46
|
+
end
|
47
|
+
|
48
|
+
def stop
|
49
|
+
Process.kill("HUP", @pid) if @pid
|
50
|
+
@pid = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def port_available?(uri)
|
54
|
+
response = Net::HTTP.get_response(uri)
|
55
|
+
false
|
56
|
+
rescue Errno::ECONNREFUSED
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def ready?(uri)
|
61
|
+
while true
|
62
|
+
begin
|
63
|
+
response = Net::HTTP.get_response(uri)
|
64
|
+
return true
|
65
|
+
rescue
|
66
|
+
sleep 1
|
67
|
+
redo
|
68
|
+
end
|
69
|
+
end
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Diametric
|
6
|
+
module ServiceBase
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def datomic_conf_file?(file="datomic_version.yml")
|
13
|
+
if Pathname.new(file).relative?
|
14
|
+
file = File.join(File.dirname(__FILE__), "../..", file)
|
15
|
+
end
|
16
|
+
return File.exists?(file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def datomic_version(conf="datomic_version.yml")
|
20
|
+
if datomic_conf_file?(conf)
|
21
|
+
datomic_names = File.read(File.join(File.dirname(__FILE__), "../..", conf))
|
22
|
+
datomic_versions = YAML.load(datomic_names)
|
23
|
+
if ENV['DIAMETRIC_ENV'] && (ENV['DIAMETRIC_ENV'] == "pro")
|
24
|
+
datomic_versions["pro"]
|
25
|
+
else
|
26
|
+
datomic_versions["free"]
|
27
|
+
end
|
28
|
+
else
|
29
|
+
conf
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def datomic_version_no(datomic_version_str)
|
34
|
+
/(\d|\.)+/.match(datomic_version_str)[0]
|
35
|
+
end
|
36
|
+
|
37
|
+
def downloaded?(conf="datomic_version.yml", dest="vendor/datomic")
|
38
|
+
datomic_home = datomic_version(conf)
|
39
|
+
if Pathname.new(dest).relative?
|
40
|
+
dest = File.join(File.dirname(__FILE__), "..", "..", dest)
|
41
|
+
end
|
42
|
+
File.exists?(File.join(dest, datomic_home))
|
43
|
+
end
|
44
|
+
|
45
|
+
def download(conf="datomic_version.yml", dest="vendor/datomic")
|
46
|
+
return true if downloaded?(conf, dest)
|
47
|
+
version = datomic_version(conf)
|
48
|
+
url = "http://downloads.datomic.com/#{datomic_version_no(version)}/#{version}.zip"
|
49
|
+
if Pathname.new(dest).relative?
|
50
|
+
dest = File.join(File.dirname(__FILE__), "../..", dest)
|
51
|
+
end
|
52
|
+
require 'open-uri'
|
53
|
+
require 'zip/zipfilesystem'
|
54
|
+
open(url) do |zip_file|
|
55
|
+
Zip::ZipFile.open(zip_file.path) do |zip_path|
|
56
|
+
zip_path.each do |zip_entry|
|
57
|
+
file_path = File.join(dest, zip_entry.to_s)
|
58
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
59
|
+
zip_path.extract(zip_entry, file_path) { true }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def datomic_classpath(datomic_home)
|
66
|
+
# Find jar archives
|
67
|
+
jars = Dir["#{datomic_home}/lib/*.jar"]
|
68
|
+
jars += Dir["#{datomic_home}/*transactor*.jar"]
|
69
|
+
|
70
|
+
# Setup CLASSPATH
|
71
|
+
classpath = jars.join(File::PATH_SEPARATOR)
|
72
|
+
files = ["samples/clj", "bin", "resources"]
|
73
|
+
classpath += File::PATH_SEPARATOR + files.collect {|f| datomic_home + "/" + f}.join(File::PATH_SEPARATOR)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|