rUtilAnts 0.1.0.20091014

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,445 @@
1
+ #--
2
+ # Copyright (c) 2009 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ # This file declares modules that might be shared across several projects.
7
+
8
+ module RUtilAnts
9
+
10
+ module Logging
11
+
12
+ # The logger class singleton
13
+ class Logger
14
+
15
+ # Constants used for GUI dialogs selection
16
+ GUI_WX = 0
17
+
18
+ # Constructor
19
+ #
20
+ # Parameters:
21
+ # * *iLibRootDir* (_String_): The library root directory that will not appear in the logged stack messages
22
+ # * *iBugTrackerURL* (_String_): The application's bug tracker URL, used to report bugs
23
+ # * *iSilentOutputs* (_Boolean_): Do we silent outputs (nothing sent to $stdout or $stderr) ? [optional = false]
24
+ def initialize(iLibRootDir, iBugTrackerURL, iSilentOutputs = false)
25
+ @LibRootDir, @BugTrackerURL = iLibRootDir, iBugTrackerURL
26
+ @DebugMode = false
27
+ @LogFile = nil
28
+ @ErrorsStack = nil
29
+ @MessagesStack = nil
30
+ @DialogsGUI = nil
31
+ @ScreenOutput = (!iSilentOutputs)
32
+ @ScreenOutputErr = (!iSilentOutputs)
33
+ if (!iSilentOutputs)
34
+ # Test if we can write to stdout
35
+ begin
36
+ $stdout << "Launch Logging - stdout\n"
37
+ rescue Exception
38
+ # Redirect to a file if possible
39
+ begin
40
+ lFile = File.open('./stdout', 'w')
41
+ $stdout.reopen(lFile)
42
+ $stdout << "Launch Logging - stdout\n"
43
+ rescue Exception
44
+ # Disable
45
+ @ScreenOutput = false
46
+ end
47
+ end
48
+ # Test if we can write to stderr
49
+ begin
50
+ $stderr << "Launch Logging - stderr\n"
51
+ rescue Exception
52
+ # Redirect to a file if possible
53
+ begin
54
+ lFile = File.open('./stderr', 'w')
55
+ $stderr.reopen(lFile)
56
+ $stderr << "Launch Logging - stderr\n"
57
+ rescue Exception
58
+ # Disable
59
+ @ScreenOutputErr = false
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ # Set the log file to use (can be nil to stop logging into a file)
66
+ #
67
+ # Parameters:
68
+ # * *iFileName* (_String_): Log file name (can be nil)
69
+ def setLogFile(iFileName)
70
+ @LogFile = iFileName
71
+ end
72
+
73
+ # Indicate which GUI to be used to display dialogs.
74
+ #
75
+ # Parameters:
76
+ # * *iGUIToUse* (_Integer_): The GUI constant, or nil if no GUI is provided
77
+ def setGUIForDialogs(iGUIToUse)
78
+ @DialogsGUI = iGUIToUse
79
+ end
80
+
81
+ # Set the debug mode
82
+ #
83
+ # Parameters:
84
+ # * *iDebugMode* (_Boolean_): Are we in debug mode ?
85
+ def activateLogDebug(iDebugMode)
86
+ @DebugMode = iDebugMode
87
+ if (iDebugMode)
88
+ logInfo 'Activated log debug'
89
+ else
90
+ logInfo 'Deactivated log debug'
91
+ end
92
+ end
93
+
94
+ # Set the stack of the errors to fill.
95
+ # If set to nil, errors will be displayed as they appear.
96
+ # If set to a stack, errors will silently be added to the list.
97
+ #
98
+ # Parameters:
99
+ # * *iErrorsStack* (<em>list<String></em>): The stack of errors, or nil to unset it
100
+ def setLogErrorsStack(iErrorsStack)
101
+ @ErrorsStack = iErrorsStack
102
+ end
103
+
104
+ # Set the stack of the messages to fill.
105
+ # If set to nil, messages will be displayed as they appear.
106
+ # If set to a stack, messages will silently be added to the list.
107
+ #
108
+ # Parameters:
109
+ # * *iMessagesStack* (<em>list<String></em>): The stack of messages, or nil to unset it
110
+ def setLogMessagesStack(iMessagesStack)
111
+ @MessagesStack = iMessagesStack
112
+ end
113
+
114
+ # Log an exception
115
+ # This is called when there is a bug due to an exception in the program. It has been set in many places to detect bugs.
116
+ #
117
+ # Parameters:
118
+ # * *iException* (_Exception_): Exception
119
+ # * *iMsg* (_String_): Message to log
120
+ def logExc(iException, iMsg)
121
+ logBug("#{iMsg}
122
+ Exception: #{iException}
123
+ Exception stack:
124
+ #{getSimpleCaller(iException.backtrace, caller).join("\n")}
125
+ ...")
126
+ end
127
+
128
+ # Log a bug
129
+ # This is called when there is a bug in the program. It has been set in many places to detect bugs.
130
+ #
131
+ # Parameters:
132
+ # * *iMsg* (_String_): Message to log
133
+ def logBug(iMsg)
134
+ lCompleteMsg = "Bug: #{iMsg}
135
+ Stack:
136
+ #{getSimpleCaller(caller[0..-2]).join("\n")}"
137
+ # Log into stderr
138
+ if (@ScreenOutputErr)
139
+ $stderr << "!!! BUG !!! #{lCompleteMsg}\n"
140
+ end
141
+ if (@LogFile != nil)
142
+ logFile(lCompleteMsg)
143
+ end
144
+ # Display Bug dialog
145
+ if (showModalWxAvailable?)
146
+ # We require the file here, as we hope it will not be required often
147
+ require 'RUtilAnts/GUI/BugReportDialog'
148
+ showModal(GUI::BugReportDialog, nil, lCompleteMsg, @BugTrackerURL) do |iModalResult, iDialog|
149
+ # Nothing to do
150
+ end
151
+ else
152
+ # Use normal platform dependent message, if the platform has been initialized (otherwise, stick to $stderr)
153
+ if (defined?($rUtilAnts_Platform_Info) != nil)
154
+ $rUtilAnts_Platform_Info.sendMsg("A bug has just occurred.
155
+ Normally you should never see this message, but this application is not bug-less.
156
+ We are sorry for the inconvenience caused.
157
+ If you want to help improving this application, please inform us of this bug:
158
+ take the time to open a ticket at the bugs tracker.
159
+ We will always try our best to correct bugs.
160
+ Thanks.
161
+
162
+ Details:
163
+ #{lCompleteMsg}
164
+ ")
165
+ end
166
+ end
167
+ end
168
+
169
+ # Log an error.
170
+ # Those errors can be normal, as they mainly depend on external factors (lost connection, invalid user file...)
171
+ #
172
+ # Parameters:
173
+ # * *iMsg* (_String_): Message to log
174
+ def logErr(iMsg)
175
+ # Log into stderr
176
+ if (@ScreenOutputErr)
177
+ $stderr << "!!! ERR !!! #{iMsg}\n"
178
+ end
179
+ if (@LogFile != nil)
180
+ logFile(iMsg)
181
+ end
182
+ # Display dialog only if we are not redirecting messages to a stack
183
+ if (@ErrorsStack == nil)
184
+ if (showModalWxAvailable?)
185
+ showModal(Wx::MessageDialog, nil,
186
+ iMsg,
187
+ :caption => 'Error',
188
+ :style => Wx::OK|Wx::ICON_ERROR
189
+ ) do |iModalResult, iDialog|
190
+ # Nothing to do
191
+ end
192
+ elsif (defined?($rUtilAnts_Platform_Info) != nil)
193
+ # Use normal platform dependent message, if the platform has been initialized (otherwise, stick to $stderr)
194
+ $rUtilAnts_Platform_Info.sendMsg(iMsg)
195
+ end
196
+ else
197
+ @ErrorsStack << iMsg
198
+ end
199
+ end
200
+
201
+ # Log a normal message to the user
202
+ # This is used to display a simple message to the user
203
+ #
204
+ # Parameters:
205
+ # * *iMsg* (_String_): Message to log
206
+ def logMsg(iMsg)
207
+ # Log into stderr
208
+ if (@ScreenOutput)
209
+ $stdout << "#{iMsg}\n"
210
+ end
211
+ if (@LogFile != nil)
212
+ logFile(iMsg)
213
+ end
214
+ # Display dialog only if we are not redirecting messages to a stack
215
+ if (@MessagesStack == nil)
216
+ # Display dialog only if showModal exists and that we are currently running the application
217
+ if (showModalWxAvailable?)
218
+ showModal(Wx::MessageDialog, nil,
219
+ iMsg,
220
+ :caption => 'Notification',
221
+ :style => Wx::OK|Wx::ICON_INFORMATION
222
+ ) do |iModalResult, iDialog|
223
+ # Nothing to do
224
+ end
225
+ elsif (defined?($rUtilAnts_Platform_Info) != nil)
226
+ # Use normal platform dependent message, if the platform has been initialized (otherwise, stick to $stderr)
227
+ $rUtilAnts_Platform_Info.sendMsg(iMsg)
228
+ end
229
+ else
230
+ @MessagesStack << iMsg
231
+ end
232
+ end
233
+
234
+ # Log an info.
235
+ # This is just common journal.
236
+ #
237
+ # Parameters:
238
+ # * *iMsg* (_String_): Message to log
239
+ def logInfo(iMsg)
240
+ # Log into stdout
241
+ if (@ScreenOutput)
242
+ $stdout << "#{iMsg}\n"
243
+ end
244
+ if (@LogFile != nil)
245
+ logFile(iMsg)
246
+ end
247
+ end
248
+
249
+ # Log a debugging info.
250
+ # This is used when debug is activated
251
+ #
252
+ # Parameters:
253
+ # * *iMsg* (_String_): Message to log
254
+ def logDebug(iMsg)
255
+ # Log into stdout
256
+ if ((@DebugMode) and
257
+ (@ScreenOutput))
258
+ $stdout << "#{iMsg}\n"
259
+ end
260
+ if (@LogFile != nil)
261
+ logFile(iMsg)
262
+ end
263
+ end
264
+
265
+ private
266
+
267
+ # Check if Wx dialogs environment is set up
268
+ #
269
+ # Return:
270
+ # * _Boolean_: Can we use showModal ?
271
+ def showModalWxAvailable?
272
+ return (
273
+ (defined?(showModal) != nil) and
274
+ (@DialogsGUI == GUI_WX)
275
+ )
276
+ end
277
+
278
+ # Log a message in the log file
279
+ #
280
+ # Parameters:
281
+ # * *iMsg* (_String_): The message to log
282
+ def logFile(iMsg)
283
+ File.open(@LogFile, 'a+') do |oFile|
284
+ oFile << "#{Time.now.gmtime.strftime('%Y/%m/%d %H:%M:%S')} - #{iMsg}\n"
285
+ end
286
+ end
287
+
288
+ # Get a stack trace in a simple format:
289
+ # Remove @LibRootDir paths from it.
290
+ #
291
+ # Parameters:
292
+ # * *iCaller* (<em>list<String></em>): The caller
293
+ # * *iReferenceCaller* (<em>list<String></em>): The reference caller: we will not display lines from iCaller that also belong to iReferenceCaller [optional = nil]
294
+ # Return:
295
+ # * <em>list<String></em>): The simple stack
296
+ def getSimpleCaller(iCaller, iReferenceCaller = nil)
297
+ rSimpleCaller = []
298
+
299
+ lCaller = nil
300
+ # If there is a reference caller, remove the lines from lCaller that are also in iReferenceCaller
301
+ if (iReferenceCaller == nil)
302
+ lCaller = iCaller
303
+ else
304
+ lIdxCaller = iCaller.size - 1
305
+ lIdxRef = iReferenceCaller.size - 1
306
+ while ((lIdxCaller >= 0) and
307
+ (lIdxRef >= 0) and
308
+ (iCaller[lIdxCaller] == iReferenceCaller[lIdxRef]))
309
+ lIdxCaller -= 1
310
+ lIdxRef -= 1
311
+ end
312
+ # Here we have either one of the indexes that is -1, or the indexes point to different lines between the caller and its reference.
313
+ lCaller = iCaller[0..lIdxCaller+1]
314
+ end
315
+ lCaller.each do |iCallerLine|
316
+ lMatch = iCallerLine.match(/^(.*):([[:digit:]]*):in (.*)$/)
317
+ if (lMatch == nil)
318
+ # Did not get which format. Just add it blindly.
319
+ rSimpleCaller << iCallerLine
320
+ else
321
+ rSimpleCaller << "#{File.expand_path(lMatch[1]).gsub(@LibRootDir, '')}:#{lMatch[2]}:in #{lMatch[3]}"
322
+ end
323
+ end
324
+
325
+ return rSimpleCaller
326
+ end
327
+
328
+ end
329
+
330
+ # The following methods are meant to be included in a class to be easily useable.
331
+
332
+ # Initialize the logging features
333
+ #
334
+ # Parameters:
335
+ # * *iLibRootDir* (_String_): The library root directory that will not appear in the logged stack messages
336
+ # * *iBugTrackerURL* (_String_): The application's bug tracker URL, used to report bugs
337
+ # * *iSilentOutputs* (_Boolean_): Do we silent outputs (nothing sent to $stdout or $stderr) ? [optional = false]
338
+ def self.initializeLogging(iLibRootDir, iBugTrackerURL, iSilentOutputs = false)
339
+ $rUtilAnts_Logging_Logger = RUtilAnts::Logging::Logger.new(iLibRootDir, iBugTrackerURL, iSilentOutputs)
340
+ # Add the module accessible from the Kernel
341
+ Object.module_eval('include RUtilAnts::Logging')
342
+ end
343
+
344
+ # Set the log file to use (can be nil to stop logging into a file)
345
+ #
346
+ # Parameters:
347
+ # * *iFileName* (_String_): Log file name (can be nil)
348
+ def setLogFile(iFileName)
349
+ $rUtilAnts_Logging_Logger.setLogFile(iFileName)
350
+ end
351
+
352
+ # Indicate which GUI to be used to display dialogs.
353
+ #
354
+ # Parameters:
355
+ # * *iGUIToUse* (_Integer_): The GUI constant, or nil if no GUI is provided
356
+ def setGUIForDialogs(iGUIToUse)
357
+ $rUtilAnts_Logging_Logger.setGUIForDialogs(iGUIToUse)
358
+ end
359
+
360
+ # Set the debug mode
361
+ #
362
+ # Parameters:
363
+ # * *iDebugMode* (_Boolean_): Are we in debug mode ?
364
+ def activateLogDebug(iDebugMode)
365
+ $rUtilAnts_Logging_Logger.activateLogDebug(iDebugMode)
366
+ end
367
+
368
+ # Set the stack of the errors to fill.
369
+ # If set to nil, errors will be displayed as they appear.
370
+ # If set to a stack, errors will silently be added to the list.
371
+ #
372
+ # Parameters:
373
+ # * *iErrorsStack* (<em>list<String></em>): The stack of errors, or nil to unset it
374
+ def setLogErrorsStack(iErrorsStack)
375
+ $rUtilAnts_Logging_Logger.setLogErrorsStack(iErrorsStack)
376
+ end
377
+
378
+ # Set the stack of the messages to fill.
379
+ # If set to nil, messages will be displayed as they appear.
380
+ # If set to a stack, messages will silently be added to the list.
381
+ #
382
+ # Parameters:
383
+ # * *iMessagesStack* (<em>list<String></em>): The stack of messages, or nil to unset it
384
+ def setLogMessagesStack(iMessagesStack)
385
+ $rUtilAnts_Logging_Logger.setLogMessagesStack(iMessagesStack)
386
+ end
387
+
388
+ # Log an exception
389
+ # This is called when there is a bug due to an exception in the program. It has been set in many places to detect bugs.
390
+ #
391
+ # Parameters:
392
+ # * *iException* (_Exception_): Exception
393
+ # * *iMsg* (_String_): Message to log
394
+ def logExc(iException, iMsg)
395
+ $rUtilAnts_Logging_Logger.logExc(iException, iMsg)
396
+ end
397
+
398
+ # Log a bug
399
+ # This is called when there is a bug in the program. It has been set in many places to detect bugs.
400
+ #
401
+ # Parameters:
402
+ # * *iMsg* (_String_): Message to log
403
+ def logBug(iMsg)
404
+ $rUtilAnts_Logging_Logger.logBug(iMsg)
405
+ end
406
+
407
+ # Log an error.
408
+ # Those errors can be normal, as they mainly depend on external factors (lost connection, invalid user file...)
409
+ #
410
+ # Parameters:
411
+ # * *iMsg* (_String_): Message to log
412
+ def logErr(iMsg)
413
+ $rUtilAnts_Logging_Logger.logErr(iMsg)
414
+ end
415
+
416
+ # Log a normal message to the user
417
+ # This is used to display a simple message to the user
418
+ #
419
+ # Parameters:
420
+ # * *iMsg* (_String_): Message to log
421
+ def logMsg(iMsg)
422
+ $rUtilAnts_Logging_Logger.logMsg(iMsg)
423
+ end
424
+
425
+ # Log an info.
426
+ # This is just common journal.
427
+ #
428
+ # Parameters:
429
+ # * *iMsg* (_String_): Message to log
430
+ def logInfo(iMsg)
431
+ $rUtilAnts_Logging_Logger.logInfo(iMsg)
432
+ end
433
+
434
+ # Log a debugging info.
435
+ # This is used when debug is activated
436
+ #
437
+ # Parameters:
438
+ # * *iMsg* (_String_): Message to log
439
+ def logDebug(iMsg)
440
+ $rUtilAnts_Logging_Logger.logDebug(iMsg)
441
+ end
442
+
443
+ end
444
+
445
+ end
@@ -0,0 +1,132 @@
1
+ #--
2
+ # Copyright (c) 2009 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module RUtilAnts
7
+
8
+ module Misc
9
+
10
+ # Set these methods into the Kernel namespace
11
+ def self.initializeMisc
12
+ Object.module_eval('include RUtilAnts::Misc')
13
+ end
14
+
15
+ # Get a valid file name, taking into account platform specifically prohibited characters in file names.
16
+ #
17
+ # Parameters:
18
+ # * *iFileName* (_String_): The original file name wanted
19
+ # Return:
20
+ # * _String_: The correct file name
21
+ def getValidFileName(iFileName)
22
+ if ((defined?($rUtilAnts_Platform_Info) != nil))
23
+ return iFileName.gsub(/[#{Regexp.escape($rUtilAnts_Platform_Info.getProhibitedFileNamesCharacters)}]/, '_')
24
+ else
25
+ return iFileName
26
+ end
27
+ end
28
+
29
+ # Extract a Zip archive in a given system dependent lib sub-directory
30
+ #
31
+ # Parameters:
32
+ # * *iZipFileName* (_String_): The zip file name to extract content from
33
+ # * *iDirName* (_String_): The name of the directory to store the zip to
34
+ # Return:
35
+ # * _Exception_: Error, or nil in case of success
36
+ def extractZipFile(iZipFileName, iDirName)
37
+ rError = nil
38
+
39
+ # Use RDI if possible to ensure the dependencies on zlib.dll and rubyzip
40
+ if (defined?(RDI) != nil)
41
+ lRDIInstaller = RDI::Installer.getMainInstance
42
+ if (lRDIInstaller != nil)
43
+ # First, test that the DLL exists.
44
+ # If it does not exist, we can't install it, because ZLib.dll is downloadable only in ZIP format (kind of stupid ;-) )
45
+ lDLLDep = nil
46
+ case $rUtilAnts_Platform_Info.os
47
+ when OS_WINDOWS
48
+ lDLLDep = RDI::Model::DependencyDescription.new('ZLib DLL').addDescription( {
49
+ :Testers => [
50
+ {
51
+ :Type => 'DynamicLibraries',
52
+ :Content => [ 'zlib.dll' ]
53
+ }
54
+ ],
55
+ # We can't install this one
56
+ :Installers => []
57
+ } )
58
+ else
59
+ logBug "Sorry, installing ZLib on your platform #{$rUtilAnts_Platform_Info.os} is not yet supported."
60
+ end
61
+ if ((lDLLDep != nil) and
62
+ (!lRDIInstaller.testDependency(lDLLDep)))
63
+ # Try adding the default local location for libraries
64
+ lRDIInstaller.ensureLocationInContext('LibraryPath', lRDIInstaller.getDefaultInstallLocation('Download', RDI::DEST_LOCAL))
65
+ # Try again
66
+ if (!lRDIInstaller.testDependency(lDLLDep))
67
+ logErr "zlib.dll is not installed in your system.\nUnfortunately RDI can't help because the only way to install it is to download it through a ZIP file.\nPlease install it manually from http://zlib.net (you can do it now and click OK once it is installed)."
68
+ end
69
+ end
70
+ # Then, ensure the gem dependency
71
+ rError, lCMApplied, lIgnored, lUnresolved = lRDIInstaller.ensureDependencies(
72
+ [
73
+ RDI::Model::DependencyDescription.new('RubyZip').addDescription( {
74
+ :Testers => [
75
+ {
76
+ :Type => 'RubyRequires',
77
+ :Content => [ 'zip/zipfilesystem' ]
78
+ }
79
+ ],
80
+ :Installers => [
81
+ {
82
+ :Type => 'Gem',
83
+ :Content => 'rubyzip',
84
+ :ContextModifiers => [
85
+ {
86
+ :Type => 'GemPath',
87
+ :Content => '%INSTALLDIR%'
88
+ }
89
+ ]
90
+ }
91
+ ]
92
+ } )
93
+ ]
94
+ )
95
+ if (!lIgnored.empty?)
96
+ rError = RuntimeError.new("Unable to install RubyZip without its dependencies (#{lIgnored.size} ignored dependencies).")
97
+ elsif (!lUnresolved.empty?)
98
+ rError = RuntimeError.new("Unable to install RubyZip without its dependencies (#{lUnresolved.size} unresolved dependencies):\n#{rError}")
99
+ end
100
+ end
101
+ end
102
+ if (rError == nil)
103
+ # Extract content of iFileName to iDirName
104
+ begin
105
+ # We don't put this require in the global scope as it needs first a DLL to be loaded by plugins
106
+ require 'zip/zipfilesystem'
107
+ Zip::ZipInputStream::open(iZipFileName) do |iZipFile|
108
+ while (lEntry = iZipFile.get_next_entry)
109
+ lDestFileName = "#{iDirName}/#{lEntry.name}"
110
+ if (lEntry.directory?)
111
+ FileUtils::mkdir_p(lDestFileName)
112
+ else
113
+ FileUtils::mkdir_p(File.dirname(lDestFileName))
114
+ # If the file already exist, first delete it to replace it with ours
115
+ if (File.exists?(lDestFileName))
116
+ File.unlink(lDestFileName)
117
+ end
118
+ lEntry.extract(lDestFileName)
119
+ end
120
+ end
121
+ end
122
+ rescue Exception
123
+ rError = $!
124
+ end
125
+ end
126
+
127
+ return rError
128
+ end
129
+
130
+ end
131
+
132
+ end
@@ -0,0 +1,30 @@
1
+ #--
2
+ # Copyright (c) 2009 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module RUtilAnts
7
+
8
+ module Platform
9
+
10
+ # OS constants
11
+ OS_WINDOWS = 0
12
+ OS_LINUX = 1
13
+
14
+ # Initialize the platform info
15
+ def self.initializePlatform
16
+ # Require the platform info
17
+ begin
18
+ require "RUtilAnts/Platforms/#{RUBY_PLATFORM}/PlatformInfo"
19
+ rescue Exception
20
+ logBug "Current platform #{RUBY_PLATFORM} is not supported."
21
+ raise RuntimeError, "Current platform #{RUBY_PLATFORM} is not supported."
22
+ end
23
+ # Create the corresponding object
24
+ $rUtilAnts_Platform_Info = PlatformInfo.new
25
+ Object.module_eval('include RUtilAnts::Platform')
26
+ end
27
+
28
+ end
29
+
30
+ end