RDI 0.1.0.20091020

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/AUTHORS +3 -0
  2. data/ChangeLog +46 -0
  3. data/Credits +21 -0
  4. data/LICENSE +31 -0
  5. data/README +18 -0
  6. data/TODO +17 -0
  7. data/lib/rdi/Installer.rb +678 -0
  8. data/lib/rdi/Model/ContextModifier.rb +20 -0
  9. data/lib/rdi/Model/DependencyDescription.rb +154 -0
  10. data/lib/rdi/Model/DependencyUserChoice.rb +202 -0
  11. data/lib/rdi/Model/Installer.rb +24 -0
  12. data/lib/rdi/Model/LocationSelector.rb +16 -0
  13. data/lib/rdi/Model/ProgressView.rb +16 -0
  14. data/lib/rdi/Model/Tester.rb +20 -0
  15. data/lib/rdi/Model/View.rb +16 -0
  16. data/lib/rdi/Plugins/ContextModifiers/GemPath.desc.rb +13 -0
  17. data/lib/rdi/Plugins/ContextModifiers/GemPath.rb +106 -0
  18. data/lib/rdi/Plugins/ContextModifiers/LibraryPath.rb +74 -0
  19. data/lib/rdi/Plugins/ContextModifiers/RubyLoadPath.rb +76 -0
  20. data/lib/rdi/Plugins/ContextModifiers/SystemPath.rb +74 -0
  21. data/lib/rdi/Plugins/GemCommon.rb +127 -0
  22. data/lib/rdi/Plugins/Installers/Download.rb +72 -0
  23. data/lib/rdi/Plugins/Installers/DownloadAndInstall.desc.rb +11 -0
  24. data/lib/rdi/Plugins/Installers/DownloadAndInstall.rb +54 -0
  25. data/lib/rdi/Plugins/Installers/Gem.desc.rb +13 -0
  26. data/lib/rdi/Plugins/Installers/Gem.rb +67 -0
  27. data/lib/rdi/Plugins/Installers/Icons/Download.png +0 -0
  28. data/lib/rdi/Plugins/Installers/Icons/DownloadAndInstall.png +0 -0
  29. data/lib/rdi/Plugins/Installers/Icons/Gem.png +0 -0
  30. data/lib/rdi/Plugins/Installers/Yum.rb +52 -0
  31. data/lib/rdi/Plugins/ProgressViews/SimpleWxGUI.desc.rb +13 -0
  32. data/lib/rdi/Plugins/ProgressViews/SimpleWxGUI.rb +58 -0
  33. data/lib/rdi/Plugins/ProgressViews/Text.rb +68 -0
  34. data/lib/rdi/Plugins/RubyGemsDepDesc.rb +41 -0
  35. data/lib/rdi/Plugins/Testers/Binaries.rb +56 -0
  36. data/lib/rdi/Plugins/Testers/DynamicLibraries.rb +56 -0
  37. data/lib/rdi/Plugins/Testers/RubyRequires.rb +76 -0
  38. data/lib/rdi/Plugins/Views/SimpleWxGUI/DependenciesLoaderDialog.rb +147 -0
  39. data/lib/rdi/Plugins/Views/SimpleWxGUI/DependencyPanel.rb +301 -0
  40. data/lib/rdi/Plugins/Views/SimpleWxGUI/Icons/Dependency.png +0 -0
  41. data/lib/rdi/Plugins/Views/SimpleWxGUI/Icons/Ignore.png +0 -0
  42. data/lib/rdi/Plugins/Views/SimpleWxGUI/Icons/ValidKO.png +0 -0
  43. data/lib/rdi/Plugins/Views/SimpleWxGUI/Icons/ValidOK.png +0 -0
  44. data/lib/rdi/Plugins/Views/SimpleWxGUI/LocationSelectors/Directory.desc.rb +13 -0
  45. data/lib/rdi/Plugins/Views/SimpleWxGUI/LocationSelectors/Directory.rb +45 -0
  46. data/lib/rdi/Plugins/Views/SimpleWxGUI.desc.rb +13 -0
  47. data/lib/rdi/Plugins/Views/SimpleWxGUI.rb +60 -0
  48. data/lib/rdi/Plugins/Views/Text/LocationSelectors/Directory.rb +44 -0
  49. data/lib/rdi/Plugins/Views/Text.rb +257 -0
  50. data/lib/rdi/Plugins/WxCommon.rb +69 -0
  51. data/lib/rdi/Plugins/WxRubyDepDesc.rb +36 -0
  52. data/lib/rdi/rdi.rb +8 -0
  53. data/test/Common.rb +796 -0
  54. data/test/Flows/BasicFlows.rb +114 -0
  55. data/test/Flows/UIFlows.rb +460 -0
  56. data/test/Plugins/ContextModifiers/GemPath.rb +44 -0
  57. data/test/Plugins/ContextModifiers/LibraryPath.rb +36 -0
  58. data/test/Plugins/ContextModifiers/RubyLoadPath.rb +36 -0
  59. data/test/Plugins/ContextModifiers/SystemPath.rb +36 -0
  60. data/test/Plugins/Installers/Download.rb +65 -0
  61. data/test/Plugins/Installers/DownloadAndInstall.rb +73 -0
  62. data/test/Plugins/Installers/Gem.rb +79 -0
  63. data/test/Plugins/LocationSelectors/Directory.rb +34 -0
  64. data/test/Plugins/Testers/Binaries.rb +46 -0
  65. data/test/Plugins/Testers/DynamicLibraries.rb +46 -0
  66. data/test/Plugins/Testers/RubyRequires.rb +48 -0
  67. data/test/Plugins/Views/SimpleWxGUI.rb +190 -0
  68. data/test/Plugins/Views/Text.rb +112 -0
  69. data/test/Plugins/WxEnv.rb +58 -0
  70. data/test/Plugins/WxEnvApp.rb +53 -0
  71. data/test/Repository/Binaries/DummyBinary +1 -0
  72. data/test/Repository/Libraries/DummyLibrary.so +1 -0
  73. data/test/Repository/RubyGems/DummyGem-0.0.1.20090828.gem +0 -0
  74. data/test/Repository/RubyGems/GemsSources/DummyGem/DummyGem.gemspec.rb +23 -0
  75. data/test/Repository/RubyGems/GemsSources/DummyGem/lib/DummyGemMain.rb +5 -0
  76. data/test/Repository/RubyLibraries/DummyRubyLib.rb +1 -0
  77. data/test/run.rb +23 -0
  78. metadata +145 -0
@@ -0,0 +1,678 @@
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 RDI
7
+
8
+ # Constants reflecting the different installation destinations
9
+ DEST_LOCAL = 0
10
+ DEST_SYSTEM = 1
11
+ DEST_USER = 2
12
+ DEST_TEMP = 3
13
+ DEST_OTHER = 4
14
+
15
+ # The main class that performs operations
16
+ class Installer
17
+
18
+ # == Public API ==
19
+
20
+ # The local ext dir (platform specific, local to the application)
21
+ # String
22
+ attr_reader :ExtDir
23
+
24
+ # The system dir
25
+ # String
26
+ attr_reader :SystemDir
27
+
28
+ # The user dir
29
+ # String
30
+ attr_reader :UserDir
31
+
32
+ # The temporary dir
33
+ # String
34
+ attr_reader :TempDir
35
+
36
+ # The RDI lib dir (useful to parse for files among plugins)
37
+ # String
38
+ attr_reader :RDILibDir
39
+
40
+ # Constructor
41
+ #
42
+ # Parameters:
43
+ # * *iAppRootDir* (_String_): Application's root directory
44
+ # * *iMainInstance* (_Boolean_): Is this instance supposed to be the main one if none was defined before ? [optional = true]
45
+ def initialize(iAppRootDir, iMainInstance = true)
46
+ if ((iMainInstance) and
47
+ (@@MainInstallerInstance == nil))
48
+ @@MainInstallerInstance = self
49
+ end
50
+ @DefaultOptions = {}
51
+
52
+ # Set directories
53
+ @RDILibDir = File.dirname(__FILE__)
54
+ @ExtDir = "#{iAppRootDir}/ext/#{RUBY_PLATFORM}"
55
+ # Initialize all other standard directories
56
+ case RUBY_PLATFORM
57
+ when 'i386-mswin32'
58
+ @UserRootDir = "#{ENV['USERPROFILE']}/RDI"
59
+ @SystemDir = "#{ENV['SystemRoot']}/RDI"
60
+ when 'i386-linux'
61
+ @UserRootDir = "#{File.expand_path('~')}/RDI"
62
+ @SystemDir = "/usr/local/RDI"
63
+ else
64
+ logBug "RDI is not yet compatible with #{RUBY_PLATFORM}. Sorry. Please open a request on http://sourceforge.net/tracker/?group_id=274498&atid=1166451"
65
+ raise RuntimeError, "Incompatible platform: #{RUBY_PLATFORM}"
66
+ end
67
+ require 'tmpdir'
68
+ @TempRootDir = "#{Dir.tmpdir}/RDI"
69
+ @UserDir = "#{@UserRootDir}/#{RUBY_PLATFORM}"
70
+ @TempDir = "#{@TempRootDir}/#{RUBY_PLATFORM}"
71
+ require 'fileutils'
72
+ FileUtils::mkdir_p(@TempDir)
73
+
74
+ # Get all possible plugins
75
+ if (defined?(RUtilAnts::Plugins::PluginsManager) == nil)
76
+ require 'rUtilAnts/Plugins'
77
+ end
78
+ @Plugins = RUtilAnts::Plugins::PluginsManager.new
79
+ # Get the RDI root directory for libraries
80
+ # Get all plugins
81
+ @Plugins.parsePluginsFromDir('ContextModifiers', "#{@RDILibDir}/Plugins/ContextModifiers", 'RDI::ContextModifiers') do |ioPlugin|
82
+ # Cache some attributes
83
+ ioPlugin.LocationSelectorName = ioPlugin.getLocationSelectorName
84
+ end
85
+ @Plugins.parsePluginsFromDir('Installers', "#{@RDILibDir}/Plugins/Installers", 'RDI::Installers') do |ioPlugin|
86
+ ioPlugin.Installer = self
87
+ # Cache some attributes
88
+ ioPlugin.PossibleDestinations = ioPlugin.getPossibleDestinations
89
+ end
90
+ @Plugins.parsePluginsFromDir('Testers', "#{@RDILibDir}/Plugins/Testers", 'RDI::Testers') do |ioPlugin|
91
+ # Cache some attributes
92
+ ioPlugin.AffectingContextModifiers = ioPlugin.getAffectingContextModifiers
93
+ end
94
+ @Plugins.parsePluginsFromDir('Views', "#{@RDILibDir}/Plugins/Views", 'RDI::Views')
95
+ @Plugins.parsePluginsFromDir('ProgressViews', "#{@RDILibDir}/Plugins/ProgressViews", 'RDI::ProgressViews')
96
+ @Plugins.getPluginNames('Views').each do |iViewName|
97
+ @Plugins.parsePluginsFromDir("LocationSelectors_#{iViewName}", "#{@RDILibDir}/Plugins/Views/#{iViewName}/LocationSelectors", "RDI::Views::LocationSelectors::#{iViewName}")
98
+ end
99
+ end
100
+
101
+ # Set default options for ensuring dependencies.
102
+ # Options not specified in the given ones will not be overriden. To cancel existing values, set them explicitly to nil.
103
+ #
104
+ # Parameters:
105
+ # * *iParameters* (<em>map<Symbol,Object></em>): Additional parameters:
106
+ # ** *:AutoInstall* (_Integer_): When set to one of the DEST_* constants, RDI installs automatically to a location flagged with this constant, without the need of user choice [optional = nil]
107
+ # ** *:AutoInstallLocation* (_Object_): Used to provide the location to install to, when :AutoInstall is set to DEST_OTHER only.
108
+ # ** *:PossibleContextModifiers* (<em>map<String,list<list<[String,Object]>>></em>): The list of possible context modifiers sets to try, per dependency ID [optional = nil]
109
+ # ** *:PreferredViews* (<em>list<String></em>): The list of preferred views [optional = nil]
110
+ def setDefaultOptions(iParameters)
111
+ @DefaultOptions.merge!(iParameters)
112
+ end
113
+
114
+ # Get the default location used by a given Installer for a given flavour
115
+ #
116
+ # Parameters:
117
+ # * *iInstallerName* (_String_): Name of the Installer plugin
118
+ # * *iFlavour* (_Integer_): Flavour required
119
+ # Return:
120
+ # * _Object_: Corresponding location, or LocationSelector name in case of DEST_OTHER flavour, or nil if none.
121
+ def getDefaultInstallLocation(iInstallerName, iFlavour)
122
+ rLocation = nil
123
+
124
+ accessPlugin('Installers', iInstallerName) do |iPlugin|
125
+ iPlugin.PossibleDestinations.each do |iDestInfo|
126
+ iDestFlavour, iDestLocation = iDestInfo
127
+ if (iDestFlavour == iFlavour)
128
+ rLocation = iDestLocation
129
+ break
130
+ end
131
+ end
132
+ end
133
+
134
+ return rLocation
135
+ end
136
+
137
+ # Ensure a given Location for a given ContextModifier
138
+ #
139
+ # Parameters:
140
+ # * *iContextModifierName* (_String_): Name of the context modifier
141
+ # * *iLocation* (_Location_): Location to add
142
+ def ensureLocationInContext(iContextModifierName, iLocation)
143
+ accessPlugin('ContextModifiers', iContextModifierName) do |ioPlugin|
144
+ if (!ioPlugin.isLocationInContext?(iLocation))
145
+ logDebug "Add Location #{iLocation} to #{iContextModifierName}."
146
+ ioPlugin.addLocationToContext(iLocation)
147
+ end
148
+ end
149
+ end
150
+
151
+ # The main method: ensure that a dependency is accessible
152
+ #
153
+ # Parameters:
154
+ # * *iDepDescList* (<em>list<DependencyDescription></em>): The list of dependencies's description to ensure
155
+ # * *iParameters* (<em>map<Symbol,Object></em>): Additional parameters:
156
+ # ** *:AutoInstall* (_Integer_): When set to one of the DEST_* constants, RDI installs automatically to a location flagged with this constant, without the need of user choice [optional = nil]
157
+ # ** *:AutoInstallLocation* (_Object_): Used to provide the location to install to, when :AutoInstall is set to DEST_OTHER only.
158
+ # ** *:PossibleContextModifiers* (<em>map<String,list<list<[String,Object]>>></em>): The list of possible context modifiers sets to try, per dependency ID [optional = nil]
159
+ # ** *:PreferredViews* (<em>list<String></em>): The list of preferred views [optional = nil]
160
+ # ** *:PreferredProgressViews* (<em>list<String></em>): The list of preferred progress views [optional = nil]
161
+ # Return:
162
+ # * _Exception_: The error, or nil in case of success
163
+ # * <em>map<String,list<[String,Object]>></em>: The list of context modifiers that have been applied to resolve the dependencies, per dependency ID (can be inconsistent in case of error)
164
+ # * <em>list<DependencyDescription></em>: The list of dependencies that were deliberately ignored (can be inconsistent in case of error)
165
+ # * <em>list<DependencyDescription></em>: The list of dependencies that could not be resolved (can be inconsistent in case of error)
166
+ def ensureDependencies(iDepDescList, iParameters = {})
167
+ rError = nil
168
+ rAppliedContextModifiers = {}
169
+ rIgnoredDeps = []
170
+ rUnresolvedDeps = []
171
+
172
+ lAutoInstall = @DefaultOptions[:AutoInstall]
173
+ if (iParameters.has_key?(:AutoInstall))
174
+ lAutoInstall = iParameters[:AutoInstall]
175
+ end
176
+ lAutoInstallLocation = @DefaultOptions[:AutoInstallLocation]
177
+ if (iParameters.has_key?(:AutoInstallLocation))
178
+ lAutoInstallLocation = iParameters[:AutoInstallLocation]
179
+ end
180
+ lPossibleContextModifiers = @DefaultOptions[:PossibleContextModifiers]
181
+ if (iParameters.has_key?(:PossibleContextModifiers))
182
+ lPossibleContextModifiers = iParameters[:PossibleContextModifiers]
183
+ end
184
+ lPreferredViews = @DefaultOptions[:PreferredViews]
185
+ if (iParameters.has_key?(:PreferredViews))
186
+ lPreferredViews = iParameters[:PreferredViews]
187
+ end
188
+ lPreferredProgressViews = @DefaultOptions[:PreferredProgressViews]
189
+ if (iParameters.has_key?(:PreferredProgressViews))
190
+ lPreferredProgressViews = iParameters[:PreferredProgressViews]
191
+ end
192
+ # First, test if the dependencies are already accessible
193
+ lDepsToResolve = []
194
+ iDepDescList.each do |iDepDesc|
195
+ if (!testDependency(iDepDesc))
196
+ lDepsToResolve << iDepDesc
197
+ end
198
+ end
199
+ if (!lDepsToResolve.empty?)
200
+ # Try resolving those dependencies with additional locations
201
+ lMissingDependencies = []
202
+ # Check if we can try some ContextModifiers that might find the missing dependencies
203
+ if (lPossibleContextModifiers == nil)
204
+ lMissingDependencies = lDepsToResolve
205
+ else
206
+ lMissingDependencies = getMissingDeps(lDepsToResolve, lPossibleContextModifiers, rAppliedContextModifiers)
207
+ end
208
+ if (!lMissingDependencies.empty?)
209
+ # If we ask for auto-installation, go on
210
+ if (lAutoInstall == nil)
211
+ # Ask the user what to do with those missing dependencies
212
+ rDepsUserChoices = askUserForMissingDeps(lMissingDependencies, lPreferredViews)
213
+ # Create a progression view
214
+ setupPreferredProgress(lPreferredProgressViews) do |ioProgressView|
215
+ # Be careful, as ioProgressView can be nil if no view was found
216
+ if (ioProgressView != nil)
217
+ ioProgressView.setRange(rDepsUserChoices.size)
218
+ end
219
+ # Parse what was returned by the user choices
220
+ rDepsUserChoices.each do |iDepUserChoice|
221
+ lDepDesc = iDepUserChoice.DepDesc
222
+ lIgnore = false
223
+ if (iDepUserChoice.Locate)
224
+ if (ioProgressView != nil)
225
+ ioProgressView.setTitle("Locate #{lDepDesc.ID}")
226
+ end
227
+ if (lDepDesc.Testers.size == iDepUserChoice.ResolvedTesters.size)
228
+ # This one was resolved using ContextModifiers.
229
+ # Apply them.
230
+ iDepUserChoice.ResolvedTesters.each do |iTesterName, iCMInfo|
231
+ iCMName, iCMContent = iCMInfo
232
+ accessPlugin('ContextModifiers', iCMName) do |ioPlugin|
233
+ ioPlugin.addLocationToContext(iCMContent)
234
+ end
235
+ end
236
+ # Remember what we applied
237
+ rAppliedContextModifiers[lDepDesc.ID] = iDepUserChoice.ResolvedTesters.values
238
+ else
239
+ rUnresolvedDeps << lDepDesc
240
+ lIgnore = true
241
+ end
242
+ elsif (iDepUserChoice.IdxInstaller != nil)
243
+ if (ioProgressView != nil)
244
+ ioProgressView.setTitle("Install #{lDepDesc.ID}")
245
+ end
246
+ # This one is to be installed
247
+ # Get the installer plugin
248
+ lInstallerName, lInstallerContent, lContextModifiers = lDepDesc.Installers[iDepUserChoice.IdxInstaller]
249
+ accessPlugin('Installers', lInstallerName) do |ioInstallerPlugin|
250
+ lLocation = nil
251
+ if (ioInstallerPlugin.PossibleDestinations[iDepUserChoice.IdxDestination][0] == DEST_OTHER)
252
+ lLocation = iDepUserChoice.OtherLocation
253
+ else
254
+ lLocation = ioInstallerPlugin.PossibleDestinations[iDepUserChoice.IdxDestination][1]
255
+ end
256
+ lInstallEnv = {}
257
+ rError = installDependency(lDepDesc, iDepUserChoice.IdxInstaller, lLocation, lInstallEnv)
258
+ # Get what has been modified in the context
259
+ rAppliedContextModifiers[lDepDesc.ID] = lInstallEnv[:ContextModifiers]
260
+ # If an error occurred, cancel
261
+ if (rError != nil)
262
+ break
263
+ end
264
+ end
265
+ else
266
+ if (ioProgressView != nil)
267
+ ioProgressView.setTitle("Ignore #{lDepDesc.ID}")
268
+ end
269
+ rIgnoredDeps << lDepDesc
270
+ lIgnore = true
271
+ end
272
+ if (ioProgressView != nil)
273
+ ioProgressView.incValue
274
+ end
275
+ if (!lIgnore)
276
+ if (ioProgressView != nil)
277
+ ioProgressView.setTitle("Test #{lDepDesc.ID}")
278
+ end
279
+ # Test if it was installed correctly
280
+ if (!testDependency(lDepDesc))
281
+ # Still missing
282
+ rUnresolvedDeps << lDepDesc
283
+ end
284
+ end
285
+ end
286
+ end
287
+ else
288
+ # Create a progression view
289
+ setupPreferredProgress(lPreferredProgressViews) do |ioProgressView|
290
+ # Be careful, as ioProgressView can be nil if no view was found
291
+ if (ioProgressView != nil)
292
+ ioProgressView.setRange(lMissingDependencies.size)
293
+ end
294
+ lMissingDependencies.each do |iDepDesc|
295
+ if (ioProgressView != nil)
296
+ ioProgressView.setTitle("Installing #{iDepDesc.ID}")
297
+ end
298
+ # Try to find an installer and a location for the lAutoInstall value
299
+ lIdxInstaller = 0
300
+ lLocation = nil
301
+ iDepDesc.Installers.each do |iInstallerInfo|
302
+ iInstallerName, iInstallerContent, iContextModifiersList = iInstallerInfo
303
+ accessPlugin('Installers', iInstallerName) do |iPlugin|
304
+ iPlugin.PossibleDestinations.each do |iDestinationInfo|
305
+ iLocationFlavour, iLocation = iDestinationInfo
306
+ if (iLocationFlavour == lAutoInstall)
307
+ # We found it
308
+ if (iLocationFlavour == DEST_OTHER)
309
+ lLocation = lAutoInstallLocation
310
+ else
311
+ lLocation = iLocation
312
+ end
313
+ break
314
+ end
315
+ end
316
+ end
317
+ if (lLocation != nil)
318
+ break
319
+ end
320
+ lIdxInstaller += 1
321
+ end
322
+ if (lLocation == nil)
323
+ # We were unable to find a correct default location for lAutoInstall
324
+ rError = RuntimeError.new("Unable to find a default location for #{lAutoInstall}.")
325
+ else
326
+ lInstallEnv = {}
327
+ rError = installDependency(iDepDesc, lIdxInstaller, lLocation, lInstallEnv)
328
+ # Get what has been modified in the context
329
+ rAppliedContextModifiers[iDepDesc.ID] = lInstallEnv[:ContextModifiers]
330
+ # Test if it was installed correctly
331
+ if (!testDependency(iDepDesc))
332
+ # Still missing
333
+ rUnresolvedDeps << iDepDesc
334
+ end
335
+ end
336
+ if (rError != nil)
337
+ # An error occurred: cancel
338
+ break
339
+ end
340
+ if (ioProgressView != nil)
341
+ ioProgressView.incValue
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
347
+ end
348
+
349
+ return rError, rAppliedContextModifiers, rIgnoredDeps, rUnresolvedDeps
350
+ end
351
+
352
+ # Check if a dependency is ok
353
+ #
354
+ # Parameters:
355
+ # * *iDepDesc* (_DependencyDescription_): The dependency's description
356
+ # Return:
357
+ # * _Boolean_: Is the dependency accessible in our environment ?
358
+ def testDependency(iDepDesc)
359
+ rSuccess = true
360
+
361
+ # Loop among Testers
362
+ iDepDesc.Testers.each do |iTesterInfo|
363
+ iTesterName, iTesterContent = iTesterInfo
364
+ accessPlugin('Testers', iTesterName) do |iPlugin|
365
+ logDebug "Test dependency #{iTesterContent} using #{iTesterName} ..."
366
+ rSuccess = iPlugin.isContentResolved?(iTesterContent)
367
+ if (rSuccess)
368
+ logDebug "Dependency #{iTesterContent} found."
369
+ else
370
+ logDebug "Dependency #{iTesterContent} not found."
371
+ end
372
+ end
373
+ if (!rSuccess)
374
+ # This Tester answered false. Give up.
375
+ break
376
+ end
377
+ end
378
+
379
+ return rSuccess
380
+ end
381
+
382
+ # Install a given dependency on a given destination
383
+ #
384
+ # Parameters:
385
+ # * *iDepDesc* (_DependencyDescription_): The dependency's description
386
+ # * *iIdxInstaller* (_Integer_): Index of the installer to use in the description
387
+ # * *iLocation* (_Object_): The location to install to
388
+ # * *ioInstallEnvironment* (<em>map<Symbol,Object></em>): The install environment to fill [optional = {}]
389
+ # Return:
390
+ # * _Exception_: The exception, or nil in case of success
391
+ def installDependency(iDepDesc, iIdxInstaller, iLocation, ioInstallEnvironment = {})
392
+ rError = nil
393
+
394
+ # Get the installer information
395
+ iInstallerName, iInstallerContent, iContextModifiersList = iDepDesc.Installers[iIdxInstaller]
396
+ if (iInstallerName == nil)
397
+ logBug "Unable to get installer n.#{iIdxInstaller} in description #{iDepDesc.inspect}"
398
+ rError = RuntimeError.new("Unable to get installer n.#{iIdxInstaller} in description #{iDepDesc.inspect}")
399
+ else
400
+ # Install it
401
+ accessPlugin('Installers', iInstallerName) do |iPlugin|
402
+ logDebug "Install #{iInstallerContent} in #{iLocation} using #{iInstallerName} ..."
403
+ rError = iPlugin.installDependency(iInstallerContent, iLocation, ioInstallEnvironment)
404
+ if (rError == nil)
405
+ logDebug "Plugin #{iInstallerContent} installed correctly."
406
+ else
407
+ logDebug "Plugin #{iInstallerContent} installation ended in error: #{rError}."
408
+ end
409
+ end
410
+ if (rError == nil)
411
+ # Apply context modifiers
412
+ ioInstallEnvironment[:InstallLocation] = iLocation
413
+ # Store the context modifiers list in the environment, as it can be useful for further installations of the same dependency
414
+ ioInstallEnvironment[:ContextModifiers] = []
415
+ iContextModifiersList.each do |iContextModifierInfo|
416
+ iContextModifierName, iContextModifierContent = iContextModifierInfo
417
+ accessPlugin('ContextModifiers', iContextModifierName) do |iPlugin|
418
+ # Transform the content based on the installation environment
419
+ lContextContent = iPlugin.transformContentWithInstallEnv(iContextModifierContent, ioInstallEnvironment)
420
+ # Check if this content is already in the context
421
+ if (!iPlugin.isLocationInContext?(lContextContent))
422
+ # We have to add it.
423
+ logDebug "Add #{lContextContent} to context #{iContextModifierName}"
424
+ iPlugin.addLocationToContext(lContextContent)
425
+ end
426
+ ioInstallEnvironment[:ContextModifiers] << [ iContextModifierName, lContextContent ]
427
+ end
428
+ end
429
+ end
430
+ end
431
+
432
+ return rError
433
+ end
434
+
435
+ # Get access to one of RDI's plugins.
436
+ # An exception is thrown if the plugin does not exist.
437
+ # Used by:
438
+ # * Regression
439
+ # * Views
440
+ #
441
+ # Parameters:
442
+ # * *iCategoryName* (_String_): Category of the plugin to access
443
+ # * *iPluginName* (_String_): Name of the plugin to access
444
+ # * *CodeBlock*: The code called when the plugin is found:
445
+ # ** *ioPlugin* (_Object_): The corresponding plugin
446
+ def accessPlugin(iCategoryName, iPluginName)
447
+ @Plugins.accessPlugin(iCategoryName, iPluginName, :RDIInstaller => self) do |ioPlugin|
448
+ yield(ioPlugin)
449
+ end
450
+ end
451
+
452
+ # Get list of plugins for a given category.
453
+ # Used by:
454
+ # * Regression
455
+ #
456
+ # Parameters:
457
+ # * *iCategoryName* (_String_): Category of the plugin to access
458
+ # Return:
459
+ # * <em>list<String></em>: List of plugin names
460
+ def getPluginNames(iCategoryName)
461
+ return @Plugins.getPluginNames(iCategoryName)
462
+ end
463
+
464
+ # Register a new plugin
465
+ # Used by:
466
+ # * Regression
467
+ #
468
+ # Parameters:
469
+ # * *iCategoryName* (_String_): Category this plugin belongs to
470
+ # * *iPluginName* (_String_): Plugin name
471
+ # * *iFileName* (_String_): File name containing the plugin (can be nil)
472
+ # * *iDesc* (<em>map<Symbol,Object></em>): Plugin's description (can be nil)
473
+ # * *iClassName* (_String_): Name of the plugin class
474
+ # * *iInitCodeBlock* (_Proc_): Code block to call when initializing the real instance (can be nil)
475
+ def registerNewPlugin(iCategoryName, iPluginName, iFileName, iDesc, iClassName, iInitCodeBlock)
476
+ @Plugins.registerNewPlugin(iCategoryName, iPluginName, iFileName, iDesc, iClassName, iInitCodeBlock)
477
+ end
478
+
479
+ # Get the Main instance, if there is one defined, or nil otherwise
480
+ #
481
+ # Return:
482
+ # * _Installer_: The main instance, or nil if none.
483
+ def self.getMainInstance
484
+ return @@MainInstallerInstance
485
+ end
486
+
487
+ # == Private API ==
488
+
489
+ private
490
+
491
+ # The main RDI Installer instance
492
+ # Installer
493
+ @@MainInstallerInstance = nil
494
+
495
+ # Get the missing dependencies after trying previously applied context modifiers
496
+ #
497
+ # Parameters:
498
+ # * *iDepsToResolve* (<em>list<DependencyDescription></em>): The list of dependencies to resolve
499
+ # * *iPossibleContextModifiers* (<em>map<String,list<list<[String,Object]>>></em>): The list of possible context modifiers sets to try, per dependency ID
500
+ # * *ioAppliedContextModifiers* (<em>map<String,list<[String,Object]>></em>): The list of context modifiers that have been applied to resolve the dependencies, per dependency ID
501
+ # Return:
502
+ # * <em>list<DependencyDescription></em>: The list of dependencies that are still missing
503
+ def getMissingDeps(iDepsToResolve, iPossibleContextModifiers, ioAppliedContextModifiers)
504
+ rMissingDeps = []
505
+
506
+ # We might have some install environments to try
507
+ iDepsToResolve.each do |iDepDesc|
508
+ lDepID = iDepDesc.ID
509
+ lCMListsToTry = iPossibleContextModifiers[lDepID]
510
+ lDepResolved = false
511
+ if (lCMListsToTry != nil)
512
+ # We can try several ones. We want at least 1 of those sets to resolve the dependency.
513
+ lCMListsToTry.each do |iCMSetToTry|
514
+ # Try to add the locations to the context
515
+ lAppliedCMs = []
516
+ iCMSetToTry.each do |iContextModifierInfo|
517
+ iName, iContent = iContextModifierInfo
518
+ accessPlugin('ContextModifiers', iName) do |ioPlugin|
519
+ if (!ioPlugin.isLocationInContext?(iContent))
520
+ # We try this one.
521
+ ioPlugin.addLocationToContext(iContent)
522
+ lAppliedCMs << iContextModifierInfo
523
+ end
524
+ end
525
+ end
526
+ # Now, test if this has resolved the dependency (don't try if nothing changed)
527
+ if (!lAppliedCMs.empty?)
528
+ lDepResolved = testDependency(iDepDesc)
529
+ # If we found it, it's ok
530
+ if (lDepResolved)
531
+ ioAppliedContextModifiers[iDepDesc.ID] = lAppliedCMs
532
+ break
533
+ else
534
+ # Rollback those context modifications as they were useless
535
+ lAppliedCMs.each do |iContextModifierInfo|
536
+ iName, iContent = iContextModifierInfo
537
+ accessPlugin('ContextModifiers', iName) do |ioPlugin|
538
+ ioPlugin.removeLocationFromContext(iContent)
539
+ end
540
+ end
541
+ end
542
+ end
543
+ end
544
+ end
545
+ # If none of them resolved the dependency, add the dependency to the missing ones
546
+ if (!lDepResolved)
547
+ rMissingDeps << iDepDesc
548
+ end
549
+ end
550
+
551
+ return rMissingDeps
552
+ end
553
+
554
+ # Ask the user about missing dependencies.
555
+ # This method will use a user interface to know what to do with missing dependencies.
556
+ # For each dependency, choices are:
557
+ # * Install it
558
+ # * Ignore it
559
+ # * Change the context to find it (select directory...)
560
+ # Views are used to ask the user for those.
561
+ # It is possible to specify a list of preferred views. If it is the case, RDI will try first views among this list that already have their dependencies accessible, then RDI will try to install the dependencies of the first one. It will use the first view it can.
562
+ # If not specified, RDI will use arbitrary the first view it can, and eventualy try to install one.
563
+ #
564
+ # Parameters:
565
+ # * *iMissingDependencies* (<em>list<DependencyDescription></em>): The missing dependencies list
566
+ # * *iPreferredViewsList* (<em>list<String></em>): The list of preferred views (can be nil)
567
+ # Return:
568
+ # * <em>list<DependencyUserChoice></em>: The list of dependencies user choices
569
+ def askUserForMissingDeps(iMissingDependencies, iPreferredViewsList)
570
+ rDependenciesUserChoices = []
571
+
572
+ lViewsList = iPreferredViewsList
573
+ if ((iPreferredViewsList == nil) or
574
+ (iPreferredViewsList.empty?))
575
+ # Set all views as being preferred
576
+ lViewsList = @Plugins.getPluginNames('Views')
577
+ end
578
+ if (lViewsList.empty?)
579
+ logBug 'No view was accessible among plugins. Please check your Plugin/Views directory.'
580
+ else
581
+ # Now we try to select 1 view that is accessible without any dependency installation
582
+ lPlugin = nil
583
+ lViewsList.each do |iViewName|
584
+ lPlugin, lError = @Plugins.getPluginInstance('Views', iViewName,
585
+ :OnlyIfExtDepsResolved => true,
586
+ :RDIInstaller => self
587
+ )
588
+ if (lPlugin != nil)
589
+ # Found one
590
+ logDebug "Executing View #{iViewName}"
591
+ break
592
+ end
593
+ end
594
+ if (lPlugin == nil)
595
+ # Now we try to install them
596
+ lViewsList.each do |iViewName|
597
+ lPlugin, lError = @Plugins.getPluginInstance('Views', iViewName,
598
+ :RDIInstaller => self
599
+ )
600
+ if (lPlugin != nil)
601
+ # Found one
602
+ logDebug "Executing View #{iViewName}"
603
+ break
604
+ end
605
+ end
606
+ end
607
+ if (lPlugin == nil)
608
+ logBug 'After trying all preferred views, we are still unable to have one.'
609
+ else
610
+ # Call it
611
+ rDependenciesUserChoices = lPlugin.execute(self, iMissingDependencies)
612
+ end
613
+ end
614
+
615
+ return rDependenciesUserChoices
616
+ end
617
+
618
+ # Setup a progression view based on user preferences.
619
+ # It is possible to specify a list of preferred progress views. If it is the case, RDI will try first views among this list that already have their dependencies accessible, then RDI will try to install the dependencies of the first one. It will use the first view it can.
620
+ # If not specified, RDI will use arbitrary the first progress view it can, and eventualy try to install one.
621
+ #
622
+ # Parameters:
623
+ # * *iPreferredProgressViewsList* (<em>list<String></em>): The list of preferred views (can be nil)
624
+ # * _CodeBlock_: Code to execute once the progress view has been found
625
+ # ** *ioProgressView* (_Object_): The corresponding progress view
626
+ def setupPreferredProgress(iPreferredProgressViewsList)
627
+ lViewsList = iPreferredProgressViewsList
628
+ if ((iPreferredProgressViewsList == nil) or
629
+ (iPreferredProgressViewsList.empty?))
630
+ # Set all views as being preferred
631
+ lViewsList = @Plugins.getPluginNames('ProgressViews')
632
+ end
633
+ if (lViewsList.empty?)
634
+ logDebug 'No progress view was accessible among plugins. Please check your Plugin/ProgressViews directory. Continuing without progress view.'
635
+ else
636
+ # Now we try to select 1 progress view that is accessible without any dependency installation
637
+ lPlugin = nil
638
+ lViewsList.each do |iViewName|
639
+ lPlugin, lError = @Plugins.getPluginInstance('ProgressViews', iViewName,
640
+ :OnlyIfExtDepsResolved => true,
641
+ :RDIInstaller => self
642
+ )
643
+ if (lPlugin != nil)
644
+ # Found one
645
+ logDebug "Executing Progress View #{iViewName}"
646
+ break
647
+ end
648
+ end
649
+ if (lPlugin == nil)
650
+ # Now we try to install them
651
+ lViewsList.each do |iViewName|
652
+ lPlugin, lError = @Plugins.getPluginInstance('ProgressViews', iViewName,
653
+ :RDIInstaller => self
654
+ )
655
+ if (lPlugin != nil)
656
+ # Found one
657
+ logDebug "Executing Progress View #{iViewName}"
658
+ break
659
+ end
660
+ end
661
+ end
662
+ if (lPlugin == nil)
663
+ logDebug 'After trying all preferred progress views, we are still unable to have one. Performing without progression.'
664
+ end
665
+ end
666
+ # Call it
667
+ if (lPlugin == nil)
668
+ yield(nil)
669
+ else
670
+ lPlugin.setupProgress do |ioProgressView|
671
+ yield(ioProgressView)
672
+ end
673
+ end
674
+ end
675
+
676
+ end
677
+
678
+ end
@@ -0,0 +1,20 @@
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 RDI
7
+
8
+ module Model
9
+
10
+ class ContextModifier
11
+
12
+ # The name of the LocationSelector class
13
+ # String
14
+ attr_accessor :LocationSelectorName
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end