diametric 0.1.1-java
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 +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
|