rubysync 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/HISTORY.txt +4 -0
  2. data/Manifest.txt +25 -12
  3. data/README.txt +0 -2
  4. data/bin/rubysync +20 -6
  5. data/bin/rubysync.rb +333 -0
  6. data/docs/in_pipeline.graffle +2690 -0
  7. data/docs/init_openldap.ldif +11 -0
  8. data/docs/out_pipeline.graffle +3274 -0
  9. data/docs/schema/99rubysync.ldif +27 -0
  10. data/docs/schema/rubysync.schema +16 -0
  11. data/docs/to_sync.txt +15 -0
  12. data/docs/walkthru.txt +186 -0
  13. data/lib/ruby_sync.rb +7 -29
  14. data/lib/ruby_sync/connectors/base_connector.rb +55 -86
  15. data/lib/ruby_sync/connectors/csv_file_connector.rb +16 -4
  16. data/lib/ruby_sync/connectors/ldap_associations.rb +126 -0
  17. data/lib/ruby_sync/connectors/ldap_changelog_connector.rb +127 -0
  18. data/lib/ruby_sync/connectors/ldap_connector.rb +29 -192
  19. data/lib/ruby_sync/connectors/memory_connector.rb +1 -1
  20. data/lib/ruby_sync/connectors/xml_connector.rb +105 -32
  21. data/lib/ruby_sync/event.rb +40 -12
  22. data/lib/ruby_sync/operation.rb +18 -2
  23. data/lib/ruby_sync/pipelines/base_pipeline.rb +44 -6
  24. data/lib/ruby_sync/util/utilities.rb +97 -4
  25. data/lib/rubysync.rb +1 -1
  26. data/rubysync.tmproj +279 -59
  27. data/test/.LCKts_rubysync.rb~ +1 -0
  28. data/test/ruby_sync_test.rb +9 -4
  29. data/test/{test_active_record_vault.rb → tc_active_record_connector.rb} +11 -7
  30. data/test/{test_base_connector.rb → tc_base_connector.rb} +1 -1
  31. data/test/{test_base_pipeline.rb → tc_base_pipeline.rb} +1 -1
  32. data/test/tc_changelog_ldap_connector.rb +93 -0
  33. data/test/{test_csv_file_connector.rb → tc_csv_file_connector.rb} +14 -5
  34. data/test/{test_event.rb → tc_event.rb} +1 -1
  35. data/test/{test_ldap_changelog.rb → tc_ldap_changelog.rb} +1 -1
  36. data/test/{test_ldap_connector.rb → tc_ldap_connector.rb} +20 -22
  37. data/test/{test_ldap_vault.rb → tc_ldap_vault.rb} +2 -2
  38. data/test/{test_ldif.rb → tc_ldif.rb} +1 -1
  39. data/test/{test_memory_connectors.rb → tc_memory_connectors.rb} +10 -6
  40. data/test/{test_rubysync.rb → tc_rubysync.rb} +4 -4
  41. data/test/tc_transformation.rb +71 -0
  42. data/test/{test_utilities.rb → tc_utilities.rb} +28 -1
  43. data/test/tc_xml_connectors.rb +107 -6
  44. data/test/ts_rubysync.rb +11 -6
  45. metadata +33 -28
data/HISTORY.txt CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.0.4 / 2007-09-18
2
+
3
+ * XML Connector now works correctly even if id used isn't a valid XML tag
4
+ * Improved transformations
1
5
 
2
6
  == 0.0.3 / 2007-08-27
3
7
 
data/Manifest.txt CHANGED
@@ -7,6 +7,14 @@ README.txt
7
7
  Rakefile
8
8
  bin/.DS_Store
9
9
  bin/rubysync
10
+ bin/rubysync.rb
11
+ docs/in_pipeline.graffle
12
+ docs/init_openldap.ldif
13
+ docs/out_pipeline.graffle
14
+ docs/schema/99rubysync.ldif
15
+ docs/schema/rubysync.schema
16
+ docs/to_sync.txt
17
+ docs/walkthru.txt
10
18
  examples/.DS_Store
11
19
  examples/ar_client_webapp/README
12
20
  examples/ar_client_webapp/Rakefile
@@ -179,6 +187,8 @@ lib/ruby_sync/connectors/base_connector.rb
179
187
  lib/ruby_sync/connectors/connector_event_processing.rb
180
188
  lib/ruby_sync/connectors/csv_file_connector.rb
181
189
  lib/ruby_sync/connectors/file_connector.rb
190
+ lib/ruby_sync/connectors/ldap_associations.rb
191
+ lib/ruby_sync/connectors/ldap_changelog_connector.rb
182
192
  lib/ruby_sync/connectors/ldap_connector.rb
183
193
  lib/ruby_sync/connectors/memory_connector.rb
184
194
  lib/ruby_sync/connectors/xml_connector.rb
@@ -193,6 +203,7 @@ nbproject/project.properties
193
203
  nbproject/project.xml
194
204
  rubysync.tmproj
195
205
  test/.DS_Store
206
+ test/.LCKts_rubysync.rb~
196
207
  test/data/example1.ldif
197
208
  test/data/example2.ldif
198
209
  test/data/example3.ldif
@@ -202,17 +213,19 @@ test/data/example6.ldif
202
213
  test/data/example7.ldif
203
214
  test/hashlike_tests.rb
204
215
  test/ruby_sync_test.rb
216
+ test/tc_active_record_connector.rb
217
+ test/tc_base_connector.rb
218
+ test/tc_base_pipeline.rb
219
+ test/tc_changelog_ldap_connector.rb
220
+ test/tc_csv_file_connector.rb
221
+ test/tc_event.rb
222
+ test/tc_ldap_changelog.rb
223
+ test/tc_ldap_connector.rb
224
+ test/tc_ldap_vault.rb
225
+ test/tc_ldif.rb
226
+ test/tc_memory_connectors.rb
227
+ test/tc_rubysync.rb
228
+ test/tc_transformation.rb
229
+ test/tc_utilities.rb
205
230
  test/tc_xml_connectors.rb
206
- test/test_active_record_vault.rb
207
- test/test_base_connector.rb
208
- test/test_base_pipeline.rb
209
- test/test_csv_file_connector.rb
210
- test/test_event.rb
211
- test/test_ldap_changelog.rb
212
- test/test_ldap_connector.rb
213
- test/test_ldap_vault.rb
214
- test/test_ldif.rb
215
- test/test_memory_connectors.rb
216
- test/test_rubysync.rb
217
- test/test_utilities.rb
218
231
  test/ts_rubysync.rb
data/README.txt CHANGED
@@ -17,8 +17,6 @@ for your organisation.
17
17
 
18
18
  == FEATURES/PROBLEMS:
19
19
 
20
- * Add support for running continually
21
- * Test suites. Individual tests work but test suites have trouble ???
22
20
 
23
21
  == SYNOPSIS:
24
22
 
data/bin/rubysync CHANGED
@@ -112,6 +112,18 @@ class Controller < SimpleConsole::Controller
112
112
  end
113
113
  end
114
114
 
115
+ def start
116
+ pipeline_name = params[:id]
117
+ pipeline = pipeline_called pipeline_name
118
+ if pipeline
119
+ pipeline.start
120
+ else
121
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
122
+ end
123
+ end
124
+
125
+
126
+
115
127
  # Create a Rubysync project directory
116
128
  def create
117
129
  config_path = params[:id]
@@ -207,6 +219,8 @@ Usage:
207
219
  * once {name}
208
220
  ; Execute the named pipeline within the current
209
221
  ; configuration directory once and then exit
222
+
223
+ * start {name} ; Execute the named pipeline
210
224
 
211
225
  * example ; Show an example of how this command might be used
212
226
 
@@ -236,9 +250,13 @@ puts <<"END"
236
250
  You would then edit the file pipelines/my_pipeline.rb to configure the
237
251
  policy for synchronizing between the two connectors.
238
252
 
239
- You may then execute the pipeline in one-shot mode (daemon mode is coming):
253
+ You may then execute the pipeline in one-shot mode:
240
254
 
241
255
  $ rubysync once my
256
+
257
+ or continually:
258
+
259
+ $ rubysync start my
242
260
  END
243
261
  end
244
262
 
@@ -248,9 +266,6 @@ end
248
266
 
249
267
 
250
268
 
251
- def start
252
- puts "Not yet implemented"
253
- end
254
269
 
255
270
  end
256
271
 
@@ -266,7 +281,6 @@ class #{name.to_s.camelize}Connector < #{type_class_name}
266
281
  end
267
282
  end;
268
283
  end
269
-
270
284
 
271
285
 
272
286
  def pipeline_template name, vault_name, client_name
@@ -298,7 +312,7 @@ class #{name.to_s.camelize}Pipeline < RubySync::Pipelines::BasePipeline
298
312
  # 'first name' => 'givenName'
299
313
  # separate each mapping with a comma.
300
314
  # The following fields were detected on the client:
301
- # #{(client_fields.map {|f| "'#{f}'"}).join(", ")}
315
+ # #{(client_fields.map {|f| "'#{f}'"}).join(",")}
302
316
  map_vault_to_client({
303
317
  #{(vault_fields.map {|f| "#'#{f}' => 'a_client_field'"}).join(",\n\t\t")}
304
318
  })
data/bin/rubysync.rb ADDED
@@ -0,0 +1,333 @@
1
+ #!/opt/local/bin/ruby
2
+
3
+
4
+ # == Synopsis
5
+ #
6
+ # Command line tool for running *rubysync* <em>A Free MetaDirectory.</em>
7
+ #
8
+ # == Usage
9
+ #
10
+ # rubysync command name [options]
11
+ #
12
+ # Valid commands are::
13
+ # * create {name}:: Create a rubysync configuration directory
14
+ #
15
+ # * connector {name} -t {type} [--vault {name}] [--client {name}]
16
+ # ; Create a connector of the given name in
17
+ # ; the current rubysync configuration directory
18
+ #
19
+ # * fields {name} ; list the fields detected by the named connector
20
+ #
21
+ # * pipeline {name} ; Create a rubysync pipeline of the given name
22
+ # ; in the current rubysync configuration directory
23
+ #
24
+ # * once {name}::
25
+ # Execute the named pipeline within the current configuration directory once and then exit
26
+ #
27
+ # * example:: Show an example of how this command might be used
28
+ #
29
+ # == Example
30
+ #
31
+ # This sets up the skeleton of a configuration for importing comma delimeted
32
+ # text files into an xml file.
33
+ # <tt>
34
+ # $ rubysync create xml_demo
35
+ # $ cd xml_demo
36
+ # $ rubysync connector my_csv -t csv_file
37
+ # $ rubysync connector my_xml -t xml
38
+ # </tt>
39
+ #
40
+ # You would then edit the files::
41
+ #
42
+ # * +connectors/my_csv_connector.rb+:: where to get the CSV files, field names, etc
43
+ # * +connectors/my_xml_connector.rb+:: how to connect to your XML file.
44
+ #
45
+ # And enter::
46
+ # <tt>
47
+ # $ rubysync pipeline my_pipeline -C my_csv -V my_xml
48
+ # </tt>
49
+ #
50
+ # You would then edit the file +pipelines/my_pipeline.rb+ to configure the
51
+ # policy for synchronizing between the two connectors.
52
+ #
53
+ # You may then execute the pipeline in one-shot mode (daemon mode is coming)::
54
+ #
55
+ # <tt>
56
+ # $ rubysync once my_pipeline
57
+ # </tt>
58
+ #
59
+ # == Author
60
+ # Ritchie Young, 9 to 5 Magic (http://9to5magic.com.au)
61
+ #
62
+ # == Copyright
63
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
64
+ #
65
+ # This file is part of RubySync.
66
+ #
67
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
68
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
69
+ #
70
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
71
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
72
+ #
73
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
74
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
75
+
76
+
77
+ lib_path = File.dirname(__FILE__) + '/../lib'
78
+ $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
79
+ require "ruby_sync"
80
+ require "simpleconsole"
81
+ require 'rdoc/usage'
82
+
83
+
84
+ class Controller < SimpleConsole::Controller
85
+
86
+ include RubySync::Utilities
87
+
88
+ before_filter :configure_logging
89
+
90
+ params :string => {:p => :pipe,
91
+ :t => :type,
92
+ :V => :vault,
93
+ :C => :client},
94
+ :int =>{:v => :verbose}
95
+
96
+ def default
97
+ #RDoc::usage 'Usage'
98
+ end
99
+
100
+ def example
101
+ #RDoc::usage 'Example'
102
+ end
103
+
104
+ # Run specified pipeline once then exit
105
+ def once
106
+ pipeline_name = params[:id]
107
+ pipeline = pipeline_called pipeline_name
108
+ if pipeline
109
+ pipeline.run_once
110
+ else
111
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
112
+ end
113
+ end
114
+
115
+ def start
116
+ pipeline_name = params[:id]
117
+ pipeline = pipeline_called pipeline_name
118
+ if pipeline
119
+ pipeline.start
120
+ else
121
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
122
+ end
123
+ end
124
+
125
+
126
+
127
+ # Create a Rubysync project directory
128
+ def create
129
+ config_path = params[:id]
130
+ ensure_dir_exists([
131
+ config_path,
132
+ "#{config_path}/pipelines",
133
+ "#{config_path}/connectors",
134
+ "#{config_path}/shared",
135
+ "#{config_path}/shared/pipelines",
136
+ "#{config_path}/shared/connectors",
137
+ "#{config_path}/shared/lib",
138
+ "#{config_path}/log",
139
+ "#{config_path}/db"
140
+ ])
141
+ end
142
+
143
+ # Create a connector configuration file
144
+ def connector
145
+ name = params[:id]
146
+ type = params[:type]
147
+ unless name and type
148
+ puts "Usage: rubysync connector connector_name -t connector_type"
149
+ return
150
+ end
151
+ if base_path
152
+ File.open("#{base_path}/connectors/#{name}_connector.rb", "w") do |file|
153
+ file.puts connector_template(name, type)
154
+ end
155
+ else
156
+ puts 'Change into a config dir and try again or create a config dir with "rubysync create"'
157
+ end
158
+ end
159
+
160
+ # List the fields that the named connector can detect. This is
161
+ # a good way to test if a connector config is functional.
162
+ def fields
163
+ connector_name = params[:id]
164
+ connector = (connector_name)? ::RubySync::Connectors::BaseConnector.class_for(connector_name) : nil
165
+ @field_names = connector && connector.fields || []
166
+ end
167
+
168
+ def pipeline
169
+ name = params[:id]
170
+ vault_name = params[:vault]
171
+ client_name = params[:client]
172
+ unless name
173
+ puts "Usage: rubysync pipeline pipeline_name [-V vault] [-C client]"
174
+ return
175
+ end
176
+ if base_path
177
+ File.open("#{base_path}/pipelines/#{name}_pipeline.rb", "w") do |file|
178
+ file.puts pipeline_template(name, vault_name, client_name)
179
+ end
180
+ else
181
+ puts 'Change into a config dir and try again or create a config dir with "rubysync create"'
182
+ end
183
+
184
+ end
185
+
186
+
187
+ private
188
+
189
+ def configure_logging
190
+ log_levels = [Logger::WARN, Logger::INFO, Logger::DEBUG]
191
+ verbosity = [(params[:verbose]||0), log_levels.size-1].min
192
+ log.level = log_levels[verbosity]
193
+ end
194
+
195
+ end
196
+
197
+
198
+ class View < SimpleConsole::View
199
+
200
+
201
+ def default
202
+ puts <<"END"
203
+ Usage:
204
+
205
+ rubysync command name [options]
206
+
207
+ Valid commands are:
208
+ * create {name}: Create a rubysync configuration directory
209
+
210
+ * connector {name} -t {type} [--vault {name}] [--client {name}]
211
+ ; Create a connector of the given name in
212
+ ; the current rubysync configuration directory
213
+
214
+ * fields {name} ; list the fields detected by the named connector
215
+
216
+ * pipeline {name} ; Create a rubysync pipeline of the given name
217
+ ; in the current rubysync configuration directory
218
+
219
+ * once {name}
220
+ ; Execute the named pipeline within the current
221
+ ; configuration directory once and then exit
222
+
223
+ * start {name} ; Execute the named pipeline
224
+
225
+ * example ; Show an example of how this command might be used
226
+
227
+ END
228
+ end
229
+
230
+
231
+ def example
232
+ puts <<"END"
233
+ This sets up the skeleton of a configuration for importing comma delimeted
234
+ text files into a database. Note, if the application happens to be a Rails
235
+ app then it can also export changes.
236
+
237
+ $ rubysync create db_demo
238
+ $ cd db_demo
239
+ $ rubysync connector my_csv -t csv_file
240
+ $ rubysync connector my_db -t active_record
241
+
242
+ You would then edit the files:
243
+
244
+ connectors/my_csv_connector.rb ;where to get CSV files, field names, etc
245
+ connectors/my_db_connector.rb ;how to connect to your DB or Rails app.
246
+
247
+ And enter:
248
+ $ rubysync pipeline my -C my_csv -V my_db
249
+
250
+ You would then edit the file pipelines/my_pipeline.rb to configure the
251
+ policy for synchronizing between the two connectors.
252
+
253
+ You may then execute the pipeline in one-shot mode:
254
+
255
+ $ rubysync once my
256
+
257
+ or continually:
258
+
259
+ $ rubysync start my
260
+ END
261
+ end
262
+
263
+ def fields
264
+ puts @field_names.join("\n")
265
+ end
266
+
267
+
268
+
269
+
270
+ end
271
+
272
+
273
+ def connector_template name, type
274
+ type_class_name = "RubySync::Connectors::#{type.to_s.camelize}Connector"
275
+ type_class = eval(type_class_name)
276
+ sample_config = (type_class && type_class.respond_to?("sample_config")) ?
277
+ type_class.sample_config : ""
278
+ return <<-"end;"
279
+ class #{name.to_s.camelize}Connector < #{type_class_name}
280
+ #{sample_config}
281
+ end
282
+ end;
283
+ end
284
+
285
+
286
+ def pipeline_template name, vault_name, client_name
287
+ vault = (vault_name)? ::RubySync::Connectors::BaseConnector.class_for(vault_name) : nil
288
+ vault_fields = vault && vault.fields || %w{allow these fields through}
289
+ possible_fields = (vault_fields.map {|n| ":#{n}"}).join(", ")
290
+
291
+ client = (client_name)? ::RubySync::Connectors::BaseConnector.class_for(client_name) : nil
292
+ client_fields = client && client.fields || []
293
+
294
+ vault_specifier = (vault_name)? "vault :#{vault_name}" : "#vault :vault_connector_name"
295
+ client_specifier = (client_name)? "client :#{client_name}" : "#client :client_connector_name"
296
+ return <<-"end;"
297
+ class #{name.to_s.camelize}Pipeline < RubySync::Pipelines::BasePipeline
298
+
299
+ #{client_specifier}
300
+
301
+ #{vault_specifier}
302
+
303
+ # Remove any fields that you don't want to set in the client from the vault
304
+ allow_out #{possible_fields}
305
+
306
+ # Remove any fields that you don't want to set in the vault from the client
307
+ allow_in #{possible_fields}
308
+
309
+ # If the client and vault have different names for the same field, define the
310
+ # the mapping here. For example, if the vault has a field called "first name" and
311
+ # the client has a field called givenName you may put:
312
+ # 'first name' => 'givenName'
313
+ # separate each mapping with a comma.
314
+ # The following fields were detected on the client:
315
+ # #{(client_fields.map {|f| "'#{f}'"}).join(",")}
316
+ map_vault_to_client({
317
+ #{(vault_fields.map {|f| "#'#{f}' => 'a_client_field'"}).join(",\n\t\t")}
318
+ })
319
+
320
+ # "in" means going from client to vault
321
+ #in_transform do
322
+ #end
323
+
324
+ # "out" means going from vault to client
325
+ #out_transform do
326
+ #end
327
+
328
+ end
329
+ end;
330
+ end
331
+
332
+
333
+ SimpleConsole::Application.run(ARGV, Controller, View)