magnoline 0.4 → 0.5
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.
- data/CHANGELOG.txt +5 -0
- data/lib/magnolia_i_e.rb +242 -239
- metadata +4 -4
data/CHANGELOG.txt
CHANGED
data/lib/magnolia_i_e.rb
CHANGED
@@ -33,288 +33,291 @@ include Net
|
|
33
33
|
|
34
34
|
# reopening the session manager class to specify different timeouts settings
|
35
35
|
class HTTPAccess2::SessionManager
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
36
|
+
def initialize
|
37
|
+
@proxy = nil
|
38
|
+
@agent_name = nil
|
39
|
+
@from = nil
|
40
|
+
@protocol_version = nil
|
41
|
+
@debug_dev = nil
|
42
|
+
@socket_sync = true
|
43
|
+
@chunk_size = 8192
|
44
|
+
@connect_timeout = 60
|
45
|
+
@connect_retry = 2
|
46
|
+
@send_timeout = 120
|
47
|
+
@receive_timeout = 300000 # For each read_block_size bytes
|
48
|
+
@read_block_size = 8192000
|
49
|
+
@ssl_config = nil
|
50
|
+
@sess_pool = []
|
51
|
+
@sess_pool_mutex = Mutex.new
|
52
|
+
end
|
53
53
|
end
|
54
54
|
|
55
55
|
#
|
56
56
|
# Simple client to import/export content of a magnolia repository.
|
57
57
|
# This is using the import/export servlet accessible in magnolia
|
58
58
|
module MagnoliaClient
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
#
|
60
|
+
# Parse the arguments to instanciate the proper ImportExport object
|
61
|
+
class ImportExportSetUp
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
CMD_IMPORT = "import"
|
64
|
+
CMD_EXPORT = "export"
|
65
|
+
IMPORT_BEHAVIORS = [:new,:remove,:replace]
|
66
66
|
|
67
67
|
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
69
|
+
#
|
70
|
+
# this method does the parsing of the arguments. Validates them
|
71
|
+
# return the ImportExport object
|
72
|
+
def parse(argv)
|
73
|
+
options = CoolOptions.parse!('[options]') do |opt|
|
74
|
+
opt.on 'action STRING','one of import/export'
|
75
|
+
opt.on 'out STRING','path to directory where to put the content of the answer', ""
|
76
|
+
opt.on 'repository-path STRING','path on the repository to take into account', "/help"
|
77
|
+
opt.on 'workspace STRING',' the repository/workspace to take into account', "website"
|
78
|
+
opt.on 'user STRING','user name to authenticate with', 'superuser'
|
79
|
+
opt.on 'password STRING','password', 'superuser'
|
80
|
+
opt.on 'f)import-file STRING','path to the xml file to import', ''
|
81
|
+
opt.on 'server-url STRING','base url of the magnolia service', 'http://localhost:8080/magnoliaAuthor'
|
82
|
+
opt.on 'behavior STRING', 'import behavior. One of new/remove/replace or 0/1/2', "0"
|
83
|
+
opt.on 'verbose', 'give some more processing info on the command line', false
|
84
|
+
opt.on 'console', 'output to standard output, bypass the out option', false
|
85
|
+
opt.on 'buffer', 'Use a buffer to stream the output from the server', false
|
86
|
+
opt.on 'z)batch-file STRING','start a batch execution of actions from a file. Path to that file', nil
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
opt.after do |r|
|
89
|
+
r.out = File.expand_path(r.out)
|
90
|
+
opt.error("Invalid action:"+r.action) unless (r.action == CMD_IMPORT || r.action == CMD_EXPORT)
|
91
|
+
uri = URI.parse(r.server_url)
|
92
|
+
opt.error("host is not reachable:"+uri.host+" on port:"+uri.port.to_s) unless Ping.pingecho(uri.host,10,uri.port)
|
93
|
+
r.behavior = parse_behavior(r.behavior) if r.action == CMD_IMPORT
|
94
|
+
end
|
95
95
|
|
96
|
-
|
96
|
+
end
|
97
97
|
|
98
|
-
|
98
|
+
return get_commands(options)
|
99
99
|
|
100
|
-
|
100
|
+
end
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
102
|
+
#
|
103
|
+
# return the array of commands properly initialized
|
104
|
+
def get_commands(options)
|
105
|
+
commands = Array.new
|
106
|
+
if !options.batch_file
|
107
|
+
commands << get_action(options)
|
108
|
+
else
|
109
|
+
open(File.expand_path(options.batch_file)) do |file|
|
110
|
+
file.each do |l|
|
111
|
+
if not l[0] == '#'
|
112
|
+
opts = l.split(/\s+/)
|
113
113
|
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
options.workspace = opts[0]
|
115
|
+
options.repository_path = opts[1]
|
116
|
+
options.import_file = opts[2] if options.action == CMD_IMPORT
|
117
117
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
124
|
-
commands
|
125
|
-
end
|
118
|
+
commands << get_action(options)
|
119
|
+
else
|
120
|
+
# skip the line. This is a comment
|
121
|
+
end
|
122
|
+
end
|
126
123
|
end
|
124
|
+
commands
|
125
|
+
end
|
126
|
+
end
|
127
127
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
128
|
+
def get_action(options)
|
129
|
+
return Export.new(options) if options.action == CMD_EXPORT
|
130
|
+
return Import.new(options) if options.action == CMD_IMPORT
|
131
|
+
end
|
132
132
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
133
|
+
#
|
134
|
+
# Parse the import behavior, from an integer or a string
|
135
|
+
# Do this while parsing to get proper error output when needed
|
136
|
+
def parse_behavior(value)
|
137
|
+
IMPORT_BEHAVIORS.each_with_index { |behavior, index|
|
138
|
+
return index if value.to_i == index
|
139
|
+
return index if value.to_s == behavior.to_s
|
140
|
+
}
|
141
|
+
raise "Invalid behavior:#{value}"
|
143
142
|
end
|
143
|
+
end
|
144
144
|
|
145
|
-
|
146
|
-
|
147
|
-
|
145
|
+
#
|
146
|
+
# Class that does the actual import export
|
147
|
+
class ImportExportBase
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
MAGNOLIA_BASE_URL = "/.magnolia/pages/"
|
150
|
+
MAGNOLIA_IMPORT_URL = MAGNOLIA_BASE_URL + "import.html"
|
151
|
+
MAGNOLIA_EXPORT_URL = MAGNOLIA_BASE_URL + "export.html"
|
152
152
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
153
|
+
#
|
154
|
+
# No checking of options, this is done in the parser
|
155
|
+
# assign values from the hash to attributes
|
156
|
+
def initialize(options)
|
157
|
+
@console = options.console
|
158
|
+
@action = options.action
|
159
|
+
@server_url = options.server_url
|
160
|
+
@repository_path = options.repository_path
|
161
|
+
@workspace = options.workspace
|
162
|
+
@user = options.user
|
163
|
+
@password = options.password
|
164
|
+
@verbose = options.verbose
|
165
|
+
@options = options
|
166
|
+
@out = outfile_path
|
167
|
+
@buffer = options.buffer
|
168
|
+
end
|
169
169
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
170
|
+
#
|
171
|
+
# compute the outfile path
|
172
|
+
# take special care when the repository_path is the root
|
173
|
+
def outfile_path
|
174
|
+
subr = if @repository_path == '/'
|
175
|
+
''
|
176
|
+
else
|
177
|
+
@repository_path.gsub('/','.')
|
178
|
+
end
|
179
|
+
File.expand_path(@options.out+'/'+@workspace+subr+'.xml')
|
180
|
+
end
|
181
181
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
182
|
+
#
|
183
|
+
# prepare form data. Should return a hash with the needed parameters
|
184
|
+
# this has to be implemented in the subclasses
|
185
|
+
def prepare_form_data
|
186
|
+
raise "Sub classing class need to implement this method"
|
187
|
+
end
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
rescue
|
199
|
-
end
|
200
|
-
}
|
189
|
+
#
|
190
|
+
# trying to fix a bug in http-access2 where all the parameters values are loosing their last char
|
191
|
+
# can't find a reason for that.
|
192
|
+
def pad_data(data)
|
193
|
+
data.each { |key,value| begin
|
194
|
+
if not key==:mgnlFileImport
|
195
|
+
value = value + " ";
|
196
|
+
data[key] = value.to_s
|
201
197
|
end
|
198
|
+
rescue
|
199
|
+
end
|
200
|
+
}
|
201
|
+
end
|
202
202
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
203
|
+
#
|
204
|
+
# main method
|
205
|
+
# this create the necessary http client to simulate interaction and just post the
|
206
|
+
# data collected from subclasses to the form.
|
207
|
+
def exec
|
208
|
+
client = HTTPAccess2::Client.new
|
209
|
+
boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
|
210
|
+
extheader = {'content-type' => "multipart/form-data; boundary=___#{ boundary }___"}
|
211
|
+
client.set_basic_auth(@server_url, @user, @password)
|
212
212
|
|
213
|
-
|
213
|
+
form_data = pad_data(prepare_form_data)
|
214
214
|
|
215
|
-
|
215
|
+
verbose(form_data) if @verbose
|
216
216
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
217
|
+
if @buffer
|
218
|
+
process_with_buffer(client, form_data, extheader)
|
219
|
+
else
|
220
|
+
process_with_no_buffer(client, form_data, extheader)
|
221
|
+
end
|
222
|
+
end
|
223
223
|
|
224
224
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
225
|
+
#
|
226
|
+
# use a simple variable to process the response from the server
|
227
|
+
def process_with_no_buffer(client, form_data, extheader)
|
228
|
+
res = client.post_content(@full_url, form_data, extheader)
|
229
|
+
if @console
|
230
|
+
puts res
|
231
|
+
else
|
232
|
+
f = File.open(@out,'w')
|
233
|
+
f.puts res
|
234
|
+
f.flush
|
235
|
+
f.close
|
236
|
+
puts "Output of action "+@action+" has been written to "+@out if @verbose
|
237
|
+
end
|
238
|
+
end
|
239
239
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
end
|
248
|
-
end
|
249
|
-
else
|
250
|
-
f = File.open(@out,'w')
|
251
|
-
client.post_content(@full_url, form_data, extheader) do |res|
|
252
|
-
res.each do |line|
|
253
|
-
f << line
|
254
|
-
f.flush
|
255
|
-
end
|
256
|
-
end
|
257
|
-
f.flush
|
258
|
-
f.close
|
259
|
-
puts "Output of action "+@action+" has been written to "+@out if @verbose
|
260
|
-
end
|
240
|
+
#
|
241
|
+
# use ruby blocks to process the response from the server
|
242
|
+
def process_with_buffer(client, form_data, extheader)
|
243
|
+
if @console
|
244
|
+
client.post_content(@full_url, form_data, extheader) do |res|
|
245
|
+
res.each('</sv:node>') do |line|
|
246
|
+
puts line
|
261
247
|
end
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
248
|
+
end
|
249
|
+
else
|
250
|
+
f = File.open(@out,'w')
|
251
|
+
client.post_content(@full_url, form_data, extheader) do |res|
|
252
|
+
client.post_content(@full_url, form_data, extheader) do |res|
|
253
|
+
res.each do |line|
|
254
|
+
f << line
|
255
|
+
f.flush
|
256
|
+
end
|
271
257
|
end
|
272
|
-
|
258
|
+
f.flush
|
259
|
+
f.close
|
260
|
+
puts "Output of action "+@action+" has been written to "+@out if @verbose
|
261
|
+
end
|
273
262
|
end
|
274
|
-
|
263
|
+
end
|
264
|
+
|
275
265
|
#
|
276
|
-
#
|
277
|
-
|
266
|
+
# Verbose output before action
|
267
|
+
def verbose(form_data)
|
268
|
+
puts "------------ \tOptions data\t ---------------"
|
269
|
+
puts @options.to_yaml
|
270
|
+
puts "------------ \tPost data\t\t ---------------"
|
271
|
+
puts form_data.to_yaml
|
272
|
+
puts "------------ \tEnd data\t\t ---------------"
|
273
|
+
end
|
278
274
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
end
|
275
|
+
end
|
276
|
+
|
277
|
+
#
|
278
|
+
# Class responsible for import specific code
|
279
|
+
class Import < ImportExportBase
|
285
280
|
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
:mgnlFormat=>false,
|
293
|
-
:command=>@action
|
294
|
-
}
|
295
|
-
end
|
281
|
+
def initialize(options)
|
282
|
+
super(options)
|
283
|
+
@action = "importxml"
|
284
|
+
@full_url = @server_url + MAGNOLIA_IMPORT_URL
|
285
|
+
@import_file = options.import_file
|
286
|
+
end
|
296
287
|
|
288
|
+
def prepare_form_data
|
289
|
+
form = {
|
290
|
+
:mgnlFileImport=>open(@import_file),
|
291
|
+
:mgnlRepository=>@workspace,
|
292
|
+
:mgnlPath=>@repository_path,
|
293
|
+
:mgnlKeepVersions=>false,
|
294
|
+
:mgnlFormat=>false,
|
295
|
+
:mgnlUuidBehavior=>"2",
|
296
|
+
:command=>@action
|
297
|
+
}
|
297
298
|
end
|
299
|
+
|
300
|
+
end
|
298
301
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
+
#
|
303
|
+
# Class responsible for export specific code
|
304
|
+
class Export < ImportExportBase
|
302
305
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
306
|
+
def initialize(options)
|
307
|
+
super(options)
|
308
|
+
@action = "exportxml"
|
309
|
+
@full_url = @server_url + MAGNOLIA_EXPORT_URL
|
310
|
+
end
|
308
311
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
end
|
312
|
+
def prepare_form_data
|
313
|
+
post_data = {
|
314
|
+
:mgnlRepository=>@workspace,
|
315
|
+
:mgnlPath=>@repository_path,
|
316
|
+
:command=>@action,
|
317
|
+
#:mgnlKeepVersions=>false,
|
318
|
+
#:mgnlFormat=>false,
|
319
|
+
:ext=>'.xml'
|
320
|
+
}
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: magnoline
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2007-
|
6
|
+
version: "0.5"
|
7
|
+
date: 2007-05-09 00:00:00 +09:00
|
8
8
|
summary: A command line interface to the Magnolia CMS
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,12 +29,12 @@ post_install_message:
|
|
29
29
|
authors:
|
30
30
|
- Nicolas Modrzyk
|
31
31
|
files:
|
32
|
+
- lib/export.rb
|
32
33
|
- lib/main_client.rb
|
33
34
|
- lib/magnolia_i_e.rb
|
34
35
|
- lib/import.rb
|
35
|
-
- lib/export.rb
|
36
|
-
- test/testsuite.rb
|
37
36
|
- test/cli_test.sh
|
37
|
+
- test/testsuite.rb
|
38
38
|
- README
|
39
39
|
- CHANGELOG.txt
|
40
40
|
- LICENSE.txt
|