~ubuntu-branches/ubuntu/karmic/mono-addins/karmic

« back to all changes in this revision

Viewing changes to Mono.Addins/Mono.Addins.Database/AddinDatabase.cs

  • Committer: Bazaar Package Importer
  • Author(s): Mirco Bauer
  • Date: 2007-07-14 12:07:48 UTC
  • Revision ID: james.westby@ubuntu.com-20070714120748-2elczfsjlrdsrpms
Tags: upstream-0.2
ImportĀ upstreamĀ versionĀ 0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// AddinDatabase.cs
 
3
//
 
4
// Author:
 
5
//   Lluis Sanchez Gual
 
6
//
 
7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
// 
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
// 
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
 
 
30
using System;
 
31
using System.Threading;
 
32
using System.Collections;
 
33
using System.Collections.Specialized;
 
34
using System.IO;
 
35
using System.Xml;
 
36
using System.Reflection;
 
37
using Mono.Addins.Description;
 
38
 
 
39
namespace Mono.Addins.Database
 
40
{
 
41
        class AddinDatabase
 
42
        {
 
43
                const string VersionTag = "000";
 
44
 
 
45
                ArrayList addinSetupInfos;
 
46
                internal static bool RunningSetupProcess;
 
47
                bool fatalDatabseError;
 
48
                Hashtable cachedAddinSetupInfos = new Hashtable ();
 
49
                AddinScanResult currentScanResult;
 
50
                AddinHostIndex hostIndex;
 
51
                FileDatabase fileDatabase;
 
52
                string addinDbDir;
 
53
                DatabaseConfiguration config = null;
 
54
                AddinRegistry registry;
 
55
                
 
56
                public AddinDatabase (AddinRegistry registry)
 
57
                {
 
58
                        this.registry = registry;
 
59
                        addinDbDir = Path.Combine (registry.RegistryPath, "addin-db-" + VersionTag);
 
60
                        fileDatabase = new FileDatabase (AddinDbDir);
 
61
                }
 
62
                
 
63
                string AddinDbDir {
 
64
                        get { return addinDbDir; }
 
65
                }
 
66
                
 
67
                public string AddinCachePath {
 
68
                        get { return Path.Combine (AddinDbDir, "addin-data"); }
 
69
                }
 
70
                
 
71
                public string AddinFolderCachePath {
 
72
                        get { return Path.Combine (AddinDbDir, "addin-dir-data"); }
 
73
                }
 
74
                
 
75
                public string AddinPrivateDataPath {
 
76
                        get { return Path.Combine (AddinDbDir, "addin-priv-data"); }
 
77
                }
 
78
                
 
79
                string HostIndexFile {
 
80
                        get { return Path.Combine (AddinDbDir, "host-index"); }
 
81
                }
 
82
                
 
83
                string ConfigFile {
 
84
                        get { return Path.Combine (AddinDbDir, "config.xml"); }
 
85
                }
 
86
                
 
87
                internal bool IsGlobalRegistry {
 
88
                        get {
 
89
                                return registry.RegistryPath == AddinRegistry.GlobalRegistryPath;
 
90
                        }
 
91
                }
 
92
                
 
93
                public void Clear ()
 
94
                {
 
95
                        if (Directory.Exists (AddinCachePath))
 
96
                                Directory.Delete (AddinCachePath, true);
 
97
                        if (Directory.Exists (AddinFolderCachePath))
 
98
                                Directory.Delete (AddinFolderCachePath, true);
 
99
                }
 
100
                
 
101
                public ExtensionNodeSet FindNodeSet (string addinId, string id)
 
102
                {
 
103
                        return FindNodeSet (addinId, id, new Hashtable ());
 
104
                }
 
105
                
 
106
                ExtensionNodeSet FindNodeSet (string addinId, string id, Hashtable visited)
 
107
                {
 
108
                        if (visited.Contains (addinId))
 
109
                                return null;
 
110
                        visited.Add (addinId, addinId);
 
111
                        Addin addin = GetInstalledAddin (addinId, true, false);
 
112
                        if (addin == null) {
 
113
                                foreach (Addin root in GetAddinRoots ()) {
 
114
                                        if (root.Id == addinId) {
 
115
                                                addin = root;
 
116
                                                break;
 
117
                                        }
 
118
                                }
 
119
                                if (addin == null)
 
120
                                        return null;
 
121
                        }
 
122
                        AddinDescription desc = addin.Description;
 
123
                        if (desc == null)
 
124
                                return null;
 
125
                        foreach (ExtensionNodeSet nset in desc.ExtensionNodeSets)
 
126
                                if (nset.Id == id)
 
127
                                        return nset;
 
128
                        
 
129
                        // Not found in the add-in. Look on add-ins on which it depends
 
130
                        
 
131
                        foreach (Dependency dep in desc.MainModule.Dependencies) {
 
132
                                AddinDependency adep = dep as AddinDependency;
 
133
                                if (adep == null) continue;
 
134
                                
 
135
                                string aid = Addin.GetFullId (desc.Namespace, adep.AddinId, adep.Version);
 
136
                                ExtensionNodeSet nset = FindNodeSet (aid, id, visited);
 
137
                                if (nset != null)
 
138
                                        return nset;
 
139
                        }
 
140
                        return null;
 
141
                }
 
142
                
 
143
                public AddinDescription GetDescription (string id)
 
144
                {
 
145
                        InternalCheck ();
 
146
                        IDisposable dblock = fileDatabase.LockRead ();
 
147
                        try {
 
148
                                string path = GetDescriptionPath (id);
 
149
                                AddinDescription desc = AddinDescription.ReadBinary (fileDatabase, path);
 
150
                                if (desc != null)
 
151
                                        desc.OwnerDatabase = this;
 
152
                                return desc;
 
153
                        }
 
154
                        catch (FileNotFoundException) {
 
155
                                throw new InvalidOperationException ("Add-in not found: " + id);
 
156
                        } finally {
 
157
                                dblock.Dispose ();
 
158
                        }
 
159
                }
 
160
                
 
161
                public ArrayList GetInstalledAddins ()
 
162
                {
 
163
                        if (addinSetupInfos != null)
 
164
                                return addinSetupInfos;
 
165
                        
 
166
                        InternalCheck ();
 
167
                        using (fileDatabase.LockRead ()) {
 
168
                                return InternalGetInstalledAddins ();
 
169
                        }
 
170
                }
 
171
                
 
172
                public ArrayList GetAddinRoots ()
 
173
                {
 
174
                        ArrayList list = new ArrayList ();
 
175
                        foreach (string file in fileDatabase.GetDirectoryFiles (AddinCachePath, "*.mroot")) {
 
176
                                list.Add (new Addin (this, file));
 
177
                        }
 
178
                        return list;
 
179
                }
 
180
                
 
181
                ArrayList InternalGetInstalledAddins ()
 
182
                {
 
183
                        if (addinSetupInfos != null)
 
184
                                return addinSetupInfos;
 
185
 
 
186
                        addinSetupInfos = new ArrayList ();
 
187
                        
 
188
                        foreach (string file in fileDatabase.GetDirectoryFiles (AddinCachePath, "*.maddin")) {
 
189
                                addinSetupInfos.Add (new Addin (this, file));
 
190
                        }
 
191
                        return addinSetupInfos;
 
192
                }
 
193
                
 
194
                public Addin GetInstalledAddin (string id)
 
195
                {
 
196
                        return GetInstalledAddin (id, false, false);
 
197
                }
 
198
                
 
199
                public Addin GetInstalledAddin (string id, bool exactVersionMatch)
 
200
                {
 
201
                        return GetInstalledAddin (id, exactVersionMatch, false);
 
202
                }
 
203
                
 
204
                public Addin GetInstalledAddin (string id, bool exactVersionMatch, bool enabledOnly)
 
205
                {
 
206
                        Addin sinfo = null;
 
207
                        object ob = cachedAddinSetupInfos [id];
 
208
                        if (ob != null) {
 
209
                                sinfo = ob as Addin;
 
210
                                if (sinfo != null) {
 
211
                                        if (!enabledOnly || sinfo.Enabled)
 
212
                                                return sinfo;
 
213
                                        if (exactVersionMatch)
 
214
                                                return null;
 
215
                                }
 
216
                                else if (enabledOnly)
 
217
                                        // Ignore the 'not installed' flag when disabled add-ins are allowed
 
218
                                        return null;
 
219
                        }
 
220
                
 
221
                        InternalCheck ();
 
222
                        
 
223
                        using (fileDatabase.LockRead ())
 
224
                        {
 
225
                                string path = GetDescriptionPath (id);
 
226
                                if (sinfo == null && fileDatabase.Exists (path)) {
 
227
                                        sinfo = new Addin (this, path);
 
228
                                        cachedAddinSetupInfos [id] = sinfo;
 
229
                                        if (!enabledOnly || sinfo.Enabled)
 
230
                                                return sinfo;
 
231
                                        if (exactVersionMatch) {
 
232
                                                // Cache lookups with negative result
 
233
                                                cachedAddinSetupInfos [id] = this;
 
234
                                                return null;
 
235
                                        }
 
236
                                }
 
237
                                
 
238
                                // Exact version not found. Look for a compatible version
 
239
                                if (!exactVersionMatch) {
 
240
                                        sinfo = null;
 
241
                                        string version, name, bestVersion = null;
 
242
                                        Addin.GetIdParts (id, out name, out version);
 
243
                                        
 
244
                                        // FIXME: Not very efficient, will load all descriptions
 
245
                                        foreach (Addin ia in InternalGetInstalledAddins ()) 
 
246
                                        {
 
247
                                                if (Addin.GetIdName (ia.Id) == name && 
 
248
                                                    (!enabledOnly || ia.Enabled) &&
 
249
                                                    (version.Length == 0 || ia.SupportsVersion (version)) && 
 
250
                                                    (bestVersion == null || Addin.CompareVersions (bestVersion, ia.Version) > 0)) 
 
251
                                                {
 
252
                                                        bestVersion = ia.Version;
 
253
                                                        sinfo = ia;
 
254
                                                }
 
255
                                        }
 
256
                                        if (sinfo != null) {
 
257
                                                cachedAddinSetupInfos [id] = sinfo;
 
258
                                                return sinfo;
 
259
                                        }
 
260
                                }
 
261
                                
 
262
                                // Cache lookups with negative result
 
263
                                // Ignore the 'not installed' flag when disabled add-ins are allowed
 
264
                                if (enabledOnly)
 
265
                                        cachedAddinSetupInfos [id] = this;
 
266
                                return null;
 
267
                        }
 
268
                }
 
269
                
 
270
                public Addin GetInstalledAddin (string id, string version)
 
271
                {
 
272
                        foreach (Addin ia in GetInstalledAddins ()) {
 
273
                                if ((id == null || ia.Id == id) && (version == null || ia.Version == version))
 
274
                                        return ia;
 
275
                        }
 
276
                        return null;
 
277
                }
 
278
                
 
279
                public void Shutdown ()
 
280
                {
 
281
                        addinSetupInfos = null;
 
282
                }
 
283
                
 
284
                public Addin GetAddinForHostAssembly (string assemblyLocation)
 
285
                {
 
286
                        InternalCheck ();
 
287
                        Addin ainfo = null;
 
288
                        
 
289
                        object ob = cachedAddinSetupInfos [assemblyLocation];
 
290
                        if (ob != null) {
 
291
                                ainfo = ob as Addin;
 
292
                                if (ainfo != null)
 
293
                                        return ainfo;
 
294
                                else
 
295
                                        return null;
 
296
                        }
 
297
 
 
298
                        AddinHostIndex index = GetAddinHostIndex ();
 
299
                        string addin, addinFile;
 
300
                        if (index.GetAddinForAssembly (assemblyLocation, out addin, out addinFile)) {
 
301
                                ainfo = new Addin (this, addin, addinFile);
 
302
                                cachedAddinSetupInfos [assemblyLocation] = ainfo;
 
303
                        }
 
304
                        
 
305
                        return ainfo;
 
306
                }
 
307
                
 
308
                
 
309
                public bool IsAddinEnabled (string id)
 
310
                {
 
311
                        Addin ainfo = GetInstalledAddin (id);
 
312
                        if (ainfo != null)
 
313
                                return ainfo.Enabled;
 
314
                        else
 
315
                                return false;
 
316
                }
 
317
                
 
318
                internal bool IsAddinEnabled (string id, bool exactVersionMatch)
 
319
                {
 
320
                        if (!exactVersionMatch)
 
321
                                return IsAddinEnabled (id);
 
322
                        Addin ainfo = GetInstalledAddin (id, exactVersionMatch, false);
 
323
                        if (ainfo == null)
 
324
                                return false;
 
325
                        return Configuration.IsEnabled (id, ainfo.AddinInfo.EnabledByDefault);
 
326
                }
 
327
                
 
328
                public void EnableAddin (string id)
 
329
                {
 
330
                        EnableAddin (id, true);
 
331
                }
 
332
                
 
333
                internal void EnableAddin (string id, bool exactVersionMatch)
 
334
                {
 
335
                        Addin ainfo = GetInstalledAddin (id, exactVersionMatch, false);
 
336
                        if (ainfo == null)
 
337
                                // It may be an add-in root
 
338
                                return;
 
339
 
 
340
                        if (IsAddinEnabled (id))
 
341
                                return;
 
342
                        
 
343
                        // Enable required add-ins
 
344
                        
 
345
                        foreach (Dependency dep in ainfo.AddinInfo.Dependencies) {
 
346
                                if (dep is AddinDependency) {
 
347
                                        AddinDependency adep = dep as AddinDependency;
 
348
                                        string adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, adep.Version);
 
349
                                        EnableAddin (adepid, false);
 
350
                                }
 
351
                        }
 
352
 
 
353
                        Configuration.SetStatus (id, true, ainfo.AddinInfo.EnabledByDefault);
 
354
                        SaveConfiguration ();
 
355
 
 
356
                        if (AddinManager.IsInitialized && AddinManager.Registry.RegistryPath == registry.RegistryPath)
 
357
                                AddinManager.SessionService.ActivateAddin (id);
 
358
                }
 
359
                
 
360
                public void DisableAddin (string id)
 
361
                {
 
362
                        Addin ai = GetInstalledAddin (id, true);
 
363
                        if (ai == null)
 
364
                                throw new InvalidOperationException ("Add-in '" + id + "' not installed.");
 
365
 
 
366
                        if (!IsAddinEnabled (id))
 
367
                                return;
 
368
                        
 
369
                        Configuration.SetStatus (id, false, ai.AddinInfo.EnabledByDefault);
 
370
                        SaveConfiguration ();
 
371
                        
 
372
                        // Disable all add-ins which depend on it
 
373
                        
 
374
                        try {
 
375
                                string idName = Addin.GetIdName (id);
 
376
                                
 
377
                                foreach (Addin ainfo in GetInstalledAddins ()) {
 
378
                                        foreach (Dependency dep in ainfo.AddinInfo.Dependencies) {
 
379
                                                AddinDependency adep = dep as AddinDependency;
 
380
                                                if (adep == null)
 
381
                                                        continue;
 
382
                                                
 
383
                                                string adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, null);
 
384
                                                if (adepid != idName)
 
385
                                                        continue;
 
386
                                                
 
387
                                                // The add-in that has been disabled, might be a requeriment of this one, or maybe not
 
388
                                                // if there is an older version available. Check it now.
 
389
                                                
 
390
                                                adepid = Addin.GetFullId (ainfo.AddinInfo.Namespace, adep.AddinId, adep.Version);
 
391
                                                Addin adepinfo = GetInstalledAddin (adepid, false, true);
 
392
                                                
 
393
                                                if (adepinfo == null) {
 
394
                                                        DisableAddin (ainfo.Id);
 
395
                                                        break;
 
396
                                                }
 
397
                                        }
 
398
                                }
 
399
                        }
 
400
                        catch {
 
401
                                // If something goes wrong, enable the add-in again
 
402
                                Configuration.SetStatus (id, true, ai.AddinInfo.EnabledByDefault);
 
403
                                SaveConfiguration ();
 
404
                                throw;
 
405
                        }
 
406
 
 
407
                        if (AddinManager.IsInitialized && AddinManager.Registry.RegistryPath == registry.RegistryPath)
 
408
                                AddinManager.SessionService.UnloadAddin (id);
 
409
                }               
 
410
 
 
411
                internal string GetDescriptionPath (string id)
 
412
                {
 
413
                        return Path.Combine (AddinCachePath, id + ".maddin");
 
414
                }
 
415
                
 
416
                void InternalCheck ()
 
417
                {
 
418
                        // If the database is broken, don't try to regenerate it at every check.
 
419
                        if (fatalDatabseError)
 
420
                                return;
 
421
 
 
422
                        bool update = false;
 
423
                        using (fileDatabase.LockRead ()) {
 
424
                                if (!Directory.Exists (AddinCachePath)) {
 
425
                                        update = true;
 
426
                                }
 
427
                        }
 
428
                        if (update)
 
429
                                Update (null);
 
430
                }
 
431
                
 
432
                void GenerateAddinExtensionMapsInternal (IProgressStatus monitor, ArrayList addinsToUpdate, ArrayList removedAddins)
 
433
                {
 
434
                        AddinUpdateData updateData = new AddinUpdateData (this);
 
435
                        
 
436
                        // Clear cached data
 
437
                        cachedAddinSetupInfos.Clear ();
 
438
                        
 
439
                        // Collect all information
 
440
                        
 
441
                        Hashtable addinHash = new Hashtable ();
 
442
                        
 
443
                        if (monitor.LogLevel > 1)
 
444
                                monitor.Log ("Generating add-in extension maps");
 
445
                        
 
446
                        Hashtable changedAddins = null;
 
447
                        ArrayList descriptionsToSave = new ArrayList ();
 
448
                        ArrayList files = new ArrayList ();
 
449
                        
 
450
                        bool partialGeneration = addinsToUpdate != null;
 
451
                        
 
452
                        // Get the files to be updated
 
453
                        
 
454
                        if (partialGeneration) {
 
455
                                changedAddins = new Hashtable ();
 
456
                                foreach (string s in addinsToUpdate) {
 
457
                                        changedAddins [s] = s;
 
458
                                        string mp = GetDescriptionPath (s);
 
459
                                        if (fileDatabase.Exists (mp))
 
460
                                                files.Add (mp);
 
461
                                        else
 
462
                                                files.AddRange (fileDatabase.GetObjectSharedFiles (this.AddinCachePath, s, ".mroot"));
 
463
                                }
 
464
                                foreach (string s in removedAddins)
 
465
                                        changedAddins [s] = s;
 
466
                        }
 
467
                        else {
 
468
                                files.AddRange (fileDatabase.GetDirectoryFiles (AddinCachePath, "*.maddin"));
 
469
                                files.AddRange (fileDatabase.GetDirectoryFiles (AddinCachePath, "*.mroot"));
 
470
                        }
 
471
                        
 
472
                        // Load the descriptions.
 
473
                        foreach (string file in files) {
 
474
                        
 
475
                                AddinDescription conf;
 
476
                                if (!ReadAddinDescription (monitor, file, out conf)) {
 
477
                                        SafeDelete (monitor, file);
 
478
                                        continue;
 
479
                                }
 
480
 
 
481
                                // If the original file does not exist, the description can be deleted
 
482
                                if (!File.Exists (conf.AddinFile)) {
 
483
                                        SafeDelete (monitor, file);
 
484
                                        continue;
 
485
                                }
 
486
                                
 
487
                                // Remove old data from the description. If changedAddins==null, removes all data.
 
488
                                // Otherwise, removes data only from the addins in the table.
 
489
                                
 
490
                                conf.UnmergeExternalData (changedAddins);
 
491
                                descriptionsToSave.Add (conf);
 
492
                                
 
493
                                // Register extension points and node sets from root add-ins
 
494
                                if (conf.IsRoot) {
 
495
                                        foreach (ExtensionPoint ep in conf.ExtensionPoints)
 
496
                                                updateData.RegisterAddinRootExtensionPoint (conf, ep);
 
497
                                        foreach (ExtensionNodeSet ns in conf.ExtensionNodeSets)
 
498
                                                updateData.RegisterAddinRootNodeSet (conf, ns);
 
499
                                }
 
500
                                else
 
501
                                        addinHash [conf.AddinId] = conf;
 
502
                        }
 
503
                        
 
504
                        foreach (AddinDescription conf in addinHash.Values) {
 
505
                                CollectExtensionData (conf, updateData);
 
506
                        }
 
507
                        
 
508
                        updateData.ResolveExtensions (monitor, addinHash);
 
509
                        
 
510
                        // Update the extension points defined by this add-in                   
 
511
                        foreach (ExtensionPoint ep in updateData.GetUnresolvedExtensionPoints ()) {
 
512
                                AddinDescription am = (AddinDescription) addinHash [ep.RootAddin];
 
513
                                ExtensionPoint amep = am.ExtensionPoints [ep.Path];
 
514
                                if (amep != null) {
 
515
                                        amep.MergeWith (am.AddinId, ep);
 
516
                                        amep.RootAddin = ep.RootAddin;
 
517
                                }
 
518
                        }
 
519
 
 
520
                        // Now update the node sets
 
521
                        foreach (ExtensionPoint ep in updateData.GetUnresolvedExtensionSets ()) {
 
522
                                AddinDescription am = (AddinDescription) addinHash [ep.RootAddin];
 
523
                                ExtensionNodeSet nset = am.ExtensionNodeSets [ep.Path];
 
524
                                if (nset != null)
 
525
                                        nset.MergeWith (am.AddinId, ep.NodeSet);
 
526
                        }
 
527
                        
 
528
                        // Save the maps
 
529
                        foreach (AddinDescription conf in descriptionsToSave)
 
530
                                conf.SaveBinary (fileDatabase);
 
531
                        
 
532
                        if (monitor.LogLevel > 1) {
 
533
                                monitor.Log ("Addin relation map generated.");
 
534
                                monitor.Log ("  Addins Updated: " + descriptionsToSave.Count);
 
535
                                monitor.Log ("  Extension points: " + updateData.RelExtensionPoints);
 
536
                                monitor.Log ("  Extensions: " + updateData.RelExtensions);
 
537
                                monitor.Log ("  Extension nodes: " + updateData.RelExtensionNodes);
 
538
                                monitor.Log ("  Node sets: " + updateData.RelNodeSetTypes);
 
539
                        }
 
540
                }
 
541
                
 
542
                // Collects extension data in a hash table. The key is the path, the value is a list
 
543
                // of add-ins ids that extend that path
 
544
                
 
545
                void CollectExtensionData (AddinDescription conf, AddinUpdateData updateData)
 
546
                {
 
547
                        foreach (ExtensionNodeSet nset in conf.ExtensionNodeSets) {
 
548
                                try {
 
549
                                        updateData.RegisterNodeSet (conf, nset);
 
550
                                        updateData.RelNodeSetTypes++;
 
551
                                } catch (Exception ex) {
 
552
                                        throw new InvalidOperationException ("Error reading node set: " + nset.Id, ex);
 
553
                                }
 
554
                        }
 
555
                        
 
556
                        foreach (ExtensionPoint ep in conf.ExtensionPoints) {
 
557
                                try {
 
558
                                        updateData.RegisterExtensionPoint (conf, ep);
 
559
                                        updateData.RelExtensionPoints++;
 
560
                                } catch (Exception ex) {
 
561
                                        throw new InvalidOperationException ("Error reading extension point: " + ep.Path, ex);
 
562
                                }
 
563
                        }
 
564
                        
 
565
                        foreach (ModuleDescription module in conf.AllModules) {
 
566
                                foreach (Extension ext in module.Extensions) {
 
567
                                        updateData.RelExtensions++;
 
568
                                        updateData.RegisterExtension (conf, module, ext);
 
569
                                        AddChildExtensions (conf, module, updateData, ext.Path, ext.ExtensionNodes, false);
 
570
                                }
 
571
                        }
 
572
                }
 
573
                
 
574
                void AddChildExtensions (AddinDescription conf, ModuleDescription module, AddinUpdateData updateData, string path, ExtensionNodeDescriptionCollection nodes, bool conditionChildren)
 
575
                {
 
576
                        // Don't register conditions as extension nodes.
 
577
                        if (!conditionChildren)
 
578
                                updateData.RegisterExtension (conf, module, path);
 
579
                        
 
580
                        foreach (ExtensionNodeDescription node in nodes) {
 
581
                                if (node.NodeName == "ComplexCondition")
 
582
                                        continue;
 
583
                                updateData.RelExtensionNodes++;
 
584
                                string id = node.GetAttribute ("id");
 
585
                                if (id.Length != 0)
 
586
                                        AddChildExtensions (conf, module, updateData, path + "/" + id, node.ChildNodes, node.NodeName == "Condition");
 
587
                        }
 
588
                }
 
589
 
 
590
                internal void ResetCachedData ()
 
591
                {
 
592
                        addinSetupInfos = null;
 
593
                        hostIndex = null;
 
594
                        cachedAddinSetupInfos.Clear ();
 
595
                }
 
596
                
 
597
                
 
598
                public bool AddinDependsOn (string id1, string id2)
 
599
                {
 
600
                        Addin addin1 = GetInstalledAddin (id1, false);
 
601
                        
 
602
                        // We can assumbe that if the add-in is not returned here, it may be a root addin.
 
603
                        if (addin1 == null)
 
604
                                return false;
 
605
 
 
606
                        id2 = Addin.GetIdName (id2);
 
607
                        foreach (Dependency dep in addin1.AddinInfo.Dependencies) {
 
608
                                AddinDependency adep = dep as AddinDependency;
 
609
                                if (adep == null)
 
610
                                        continue;
 
611
                                string depid = Addin.GetFullId (addin1.AddinInfo.Namespace, adep.AddinId, null);
 
612
                                if (depid == id2)
 
613
                                        return true;
 
614
                                else if (AddinDependsOn (depid, id2))
 
615
                                        return true;
 
616
                        }
 
617
                        return false;
 
618
                }
 
619
                
 
620
                public void Repair (IProgressStatus monitor)
 
621
                {
 
622
                        using (fileDatabase.LockWrite ()) {
 
623
                                try {
 
624
                                        if (Directory.Exists (AddinCachePath))
 
625
                                                Directory.Delete (AddinCachePath, true);
 
626
                                        if (Directory.Exists (AddinFolderCachePath))
 
627
                                                Directory.Delete (AddinFolderCachePath, true);
 
628
                                        if (File.Exists (HostIndexFile))
 
629
                                                File.Delete (HostIndexFile);
 
630
                                }
 
631
                                catch (Exception ex) {
 
632
                                        monitor.ReportError ("The add-in registry could not be rebuilt. It may be due to lack of write permissions to the directory: " + AddinDbDir, ex);
 
633
                                }
 
634
                        }
 
635
                        Update (monitor);
 
636
                }
 
637
                
 
638
                public void Update (IProgressStatus monitor)
 
639
                {
 
640
                        if (monitor == null)
 
641
                                monitor = new ConsoleProgressStatus (false);
 
642
 
 
643
                        if (RunningSetupProcess)
 
644
                                return;
 
645
                        
 
646
                        fatalDatabseError = false;
 
647
                        
 
648
                        DateTime tim = DateTime.Now;
 
649
                        
 
650
                        Hashtable installed = new Hashtable ();
 
651
                        bool changesFound = CheckFolders (monitor);
 
652
                        
 
653
                        if (monitor.IsCanceled)
 
654
                                return;
 
655
                        
 
656
                        if (monitor.LogLevel > 1)
 
657
                                monitor.Log ("Folders checked (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
 
658
                        
 
659
                        if (changesFound) {
 
660
                                // Something has changed, the add-ins need to be re-scanned, but it has
 
661
                                // to be done in an external process
 
662
                                
 
663
                                using (fileDatabase.LockRead ()) {
 
664
                                        foreach (Addin ainfo in InternalGetInstalledAddins ()) {
 
665
                                                installed [ainfo.Id] = ainfo.Id;
 
666
                                        }
 
667
                                }
 
668
                                
 
669
                                RunScannerProcess (monitor);
 
670
                        
 
671
                                ResetCachedData ();
 
672
                        }
 
673
                        
 
674
                        if (fatalDatabseError)
 
675
                                monitor.ReportError ("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", null);
 
676
                        
 
677
                        // Update the currently loaded add-ins
 
678
                        if (changesFound && AddinManager.IsInitialized && AddinManager.Registry.RegistryPath == registry.RegistryPath) {
 
679
                                Hashtable newInstalled = new Hashtable ();
 
680
                                foreach (Addin ainfo in GetInstalledAddins ()) {
 
681
                                        newInstalled [ainfo.Id] = ainfo.Id;
 
682
                                }
 
683
                                
 
684
                                foreach (string aid in installed.Keys) {
 
685
                                        if (!newInstalled.Contains (aid))
 
686
                                                AddinManager.SessionService.UnloadAddin (aid);
 
687
                                }
 
688
                                
 
689
                                foreach (string aid in newInstalled.Keys) {
 
690
                                        if (!installed.Contains (aid)) {
 
691
                                                AddinManager.SessionService.ActivateAddin (aid);
 
692
                                        }
 
693
                                }
 
694
                        }
 
695
                }
 
696
                
 
697
                void RunScannerProcess (IProgressStatus monitor)
 
698
                {
 
699
                        IProgressStatus scanMonitor = monitor;
 
700
                        ArrayList pparams = new ArrayList ();
 
701
                        pparams.Add (null); // scan folder
 
702
                        
 
703
                        bool retry = false;
 
704
                        do {
 
705
                                try {
 
706
                                        if (monitor.LogLevel > 1)
 
707
                                                monitor.Log ("Looking for addins");
 
708
                                        SetupProcess.ExecuteCommand (scanMonitor, registry.RegistryPath, AddinManager.StartupDirectory, "scan", (string[]) pparams.ToArray (typeof(string)));
 
709
                                        retry = false;
 
710
                                }
 
711
                                catch (Exception ex) {
 
712
                                        ProcessFailedException pex = ex as ProcessFailedException;
 
713
                                        if (pex != null) {
 
714
                                                // Get the last logged operation.
 
715
                                                if (pex.LastLog.StartsWith ("scan:")) {
 
716
                                                        // It crashed while scanning a file. Add the file to the ignore list and try again.
 
717
                                                        string file = pex.LastLog.Substring (5);
 
718
                                                        pparams.Add (file);
 
719
                                                        monitor.ReportWarning ("Could not scan file: " + file);
 
720
                                                        retry = true;
 
721
                                                        continue;
 
722
                                                }
 
723
                                        }
 
724
                                        fatalDatabseError = true;
 
725
                                        // If the process has crashed, try to do a new scan, this time using verbose log,
 
726
                                        // to give the user more information about the origin of the crash.
 
727
                                        if (pex != null && !retry) {
 
728
                                                monitor.ReportError ("Add-in scan operation failed. The Mono runtime may have encountered an error while trying to load an assembly.", null);
 
729
                                                if (monitor.LogLevel <= 1) {
 
730
                                                        // Re-scan again using verbose log, to make it easy to find the origin of the error.
 
731
                                                        retry = true;
 
732
                                                        scanMonitor = new ConsoleProgressStatus (true);
 
733
                                                }
 
734
                                        } else
 
735
                                                retry = false;
 
736
                                        
 
737
                                        if (!retry) {
 
738
                                                monitor.ReportError ("Add-in scan operation failed", (ex is ProcessFailedException ? null : ex));
 
739
                                                monitor.Cancel ();
 
740
                                                return;
 
741
                                        }
 
742
                                }
 
743
                        }
 
744
                        while (retry);
 
745
                }
 
746
                
 
747
                bool DatabaseInfrastructureCheck (IProgressStatus monitor)
 
748
                {
 
749
                        // Do some sanity check, to make sure the basic database infrastructure can be created
 
750
                        
 
751
                        bool hasChanges = false;
 
752
                        
 
753
                        try {
 
754
                        
 
755
                                if (!Directory.Exists (AddinCachePath)) {
 
756
                                        Directory.CreateDirectory (AddinCachePath);
 
757
                                        hasChanges = true;
 
758
                                }
 
759
                        
 
760
                                if (!Directory.Exists (AddinFolderCachePath)) {
 
761
                                        Directory.CreateDirectory (AddinFolderCachePath);
 
762
                                        hasChanges = true;
 
763
                                }
 
764
                        
 
765
                                // Make sure we can write in those folders
 
766
 
 
767
                                Util.CheckWrittableFloder (AddinCachePath);
 
768
                                Util.CheckWrittableFloder (AddinFolderCachePath);
 
769
                                
 
770
                                fatalDatabseError = false;
 
771
                        }
 
772
                        catch (Exception ex) {
 
773
                                monitor.ReportError ("Add-in cache directory could not be created", ex);
 
774
                                fatalDatabseError = true;
 
775
                                monitor.Cancel ();
 
776
                        }
 
777
                        return hasChanges;
 
778
                }
 
779
                
 
780
                
 
781
                internal bool CheckFolders (IProgressStatus monitor)
 
782
                {
 
783
                        using (fileDatabase.LockRead ()) {
 
784
                                AddinScanResult scanResult = new AddinScanResult ();
 
785
                                scanResult.CheckOnly = true;
 
786
                                InternalScanFolders (monitor, scanResult);
 
787
                                return scanResult.ChangesFound;
 
788
                        }
 
789
                }
 
790
                
 
791
                internal void ScanFolders (IProgressStatus monitor, string folderToScan, StringCollection filesToIgnore)
 
792
                {
 
793
                        AddinScanResult res = new AddinScanResult ();
 
794
                        res.FilesToIgnore = filesToIgnore;
 
795
                        ScanFolders (monitor, res);
 
796
                }
 
797
                
 
798
                internal void ScanFolders (IProgressStatus monitor, AddinScanResult scanResult)
 
799
                {
 
800
                        IDisposable checkLock = null;
 
801
                        
 
802
                        if (scanResult.CheckOnly)
 
803
                                checkLock = fileDatabase.LockRead ();
 
804
                        else {
 
805
                                // All changes are done in a transaction, which won't be committed until
 
806
                                // all files have been updated.
 
807
                                
 
808
                                if (!fileDatabase.BeginTransaction ()) {
 
809
                                        // The database is already being updated. Can't do anything for now.
 
810
                                        return;
 
811
                                }
 
812
                        }
 
813
                        
 
814
                        EventInfo einfo = typeof(AppDomain).GetEvent ("ReflectionOnlyAssemblyResolve");
 
815
                        ResolveEventHandler resolver = new ResolveEventHandler (OnResolveAddinAssembly);
 
816
                        
 
817
                        try
 
818
                        {
 
819
                                // Perform the add-in scan
 
820
                                
 
821
                                if (!scanResult.CheckOnly) {
 
822
                                        AppDomain.CurrentDomain.AssemblyResolve += resolver;
 
823
                                        if (einfo != null) einfo.AddEventHandler (AppDomain.CurrentDomain, resolver);
 
824
                                }
 
825
                                
 
826
                                InternalScanFolders (monitor, scanResult);
 
827
                                
 
828
                                if (!scanResult.CheckOnly)
 
829
                                        fileDatabase.CommitTransaction ();
 
830
                        }
 
831
                        catch {
 
832
                                if (!scanResult.CheckOnly)
 
833
                                        fileDatabase.RollbackTransaction ();
 
834
                                throw;
 
835
                        }
 
836
                        finally {
 
837
                                currentScanResult = null;
 
838
                                
 
839
                                if (scanResult.CheckOnly)
 
840
                                        checkLock.Dispose ();
 
841
                                else {
 
842
                                        AppDomain.CurrentDomain.AssemblyResolve -= resolver;
 
843
                                        if (einfo != null) einfo.RemoveEventHandler (AppDomain.CurrentDomain, resolver);
 
844
                                }
 
845
                        }
 
846
                }
 
847
                
 
848
                void InternalScanFolders (IProgressStatus monitor, AddinScanResult scanResult)
 
849
                {
 
850
                        DateTime tim = DateTime.Now;
 
851
                        
 
852
                        DatabaseInfrastructureCheck (monitor);
 
853
                        if (monitor.IsCanceled)
 
854
                                return;
 
855
                        
 
856
                        try {
 
857
                                scanResult.HostIndex = GetAddinHostIndex ();
 
858
                        }
 
859
                        catch (Exception ex) {
 
860
                                if (scanResult.CheckOnly) {
 
861
                                        scanResult.ChangesFound = true;
 
862
                                        return;
 
863
                                }
 
864
                                monitor.ReportError ("Add-in root index is corrupt. The add-in database will be regenerated.", ex);
 
865
                                scanResult.RegenerateAllData = true;
 
866
                        }
 
867
                        
 
868
                        AddinScanner scanner = new AddinScanner (this);
 
869
                        
 
870
                        // Check if any of the previously scanned folders has been deleted
 
871
                        
 
872
                        foreach (string file in Directory.GetFiles (AddinFolderCachePath, "*.data")) {
 
873
                                AddinScanFolderInfo folderInfo;
 
874
                                bool res = ReadFolderInfo (monitor, file, out folderInfo);
 
875
                                if (!res || !Directory.Exists (folderInfo.Folder)) {
 
876
                                        if (res) {
 
877
                                                // Folder has been deleted. Remove the add-ins it had.
 
878
                                                scanner.UpdateDeletedAddins (monitor, folderInfo, scanResult);
 
879
                                        }
 
880
                                        else {
 
881
                                                // Folder info file corrupt. Regenerate all.
 
882
                                                scanResult.ChangesFound = true;
 
883
                                                scanResult.RegenerateRelationData = true;
 
884
                                        }
 
885
                                        
 
886
                                        if (!scanResult.CheckOnly)
 
887
                                                SafeDelete (monitor, file);
 
888
                                        else
 
889
                                                return;
 
890
                                }
 
891
                        }
 
892
                        
 
893
                        // Look for changes in the add-in folders
 
894
                        
 
895
                        foreach (string dir in registry.AddinDirectories) {
 
896
                                if (dir == registry.DefaultAddinsFolder)
 
897
                                        scanner.ScanFolderRec (monitor, dir, scanResult);
 
898
                                else
 
899
                                        scanner.ScanFolder (monitor, dir, scanResult);
 
900
                                if (scanResult.CheckOnly) {
 
901
                                        if (scanResult.ChangesFound || monitor.IsCanceled)
 
902
                                                return;
 
903
                                }
 
904
                        }
 
905
                        
 
906
                        if (scanResult.CheckOnly)
 
907
                                return;
 
908
                        
 
909
                        // Scan the files which have been modified
 
910
                        
 
911
                        currentScanResult = scanResult;
 
912
 
 
913
                        foreach (FileToScan file in scanResult.FilesToScan)
 
914
                                scanner.ScanFile (monitor, file.File, file.AddinScanFolderInfo, scanResult);
 
915
 
 
916
                        // Save folder info
 
917
                        
 
918
                        foreach (AddinScanFolderInfo finfo in scanResult.ModifiedFolderInfos)
 
919
                                SaveFolderInfo (monitor, finfo);
 
920
 
 
921
                        if (monitor.LogLevel > 1)
 
922
                                monitor.Log ("Folders scan completed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
 
923
 
 
924
                        SaveAddinHostIndex ();
 
925
                        ResetCachedData ();
 
926
                        
 
927
                        if (!scanResult.ChangesFound) {
 
928
                                if (monitor.LogLevel > 1)
 
929
                                        monitor.Log ("No changes found");
 
930
                                return;
 
931
                        }
 
932
                        
 
933
                        tim = DateTime.Now;
 
934
                        try {
 
935
                                if (scanResult.RegenerateRelationData)
 
936
                                        scanResult.AddinsToUpdateRelations = null;
 
937
                                
 
938
                                GenerateAddinExtensionMapsInternal (monitor, scanResult.AddinsToUpdateRelations, scanResult.RemovedAddins);
 
939
                        }
 
940
                        catch (Exception ex) {
 
941
                                fatalDatabseError = true;
 
942
                                monitor.ReportError ("The add-in database could not be updated. It may be due to file corruption. Try running the setup repair utility", ex);
 
943
                        }
 
944
                        
 
945
                        if (monitor.LogLevel > 1)
 
946
                                monitor.Log ("Add-in relations analyzed (" + (int) (DateTime.Now - tim).TotalMilliseconds + " ms)");
 
947
                        
 
948
                        SaveAddinHostIndex ();
 
949
                }
 
950
                
 
951
                public void ParseAddin (IProgressStatus progressStatus, string file, string outFile, bool inProcess)
 
952
                {
 
953
                        if (!inProcess) {
 
954
                                SetupProcess.ExecuteCommand (progressStatus, registry.RegistryPath, AddinManager.StartupDirectory, "get-desc", Path.GetFullPath (file), outFile);
 
955
                                return;
 
956
                        }
 
957
                        
 
958
                        using (fileDatabase.LockRead ())
 
959
                        {
 
960
                                // First of all, check if the file belongs to a registered add-in
 
961
                                AddinScanFolderInfo finfo;
 
962
                                if (GetFolderInfoForPath (progressStatus, Path.GetDirectoryName (file), out finfo) && finfo != null) {
 
963
                                        AddinFileInfo afi = finfo.GetAddinFileInfo (file);
 
964
                                        if (afi != null && afi.AddinId != null) {
 
965
                                                AddinDescription adesc;
 
966
                                                if (afi.IsRoot)
 
967
                                                        GetHostDescription (progressStatus, afi.AddinId, file, out adesc);
 
968
                                                else
 
969
                                                        GetAddinDescription (progressStatus, afi.AddinId, out adesc);
 
970
                                                if (adesc != null)
 
971
                                                        adesc.Save (outFile);
 
972
                                                return;
 
973
                                        }
 
974
                                }
 
975
                                
 
976
                                
 
977
                                AddinScanner scanner = new AddinScanner (this);
 
978
                                
 
979
                                SingleFileAssemblyResolver res = new SingleFileAssemblyResolver (progressStatus, registry, scanner);
 
980
                                ResolveEventHandler resolver = new ResolveEventHandler (res.Resolve);
 
981
 
 
982
                                EventInfo einfo = typeof(AppDomain).GetEvent ("ReflectionOnlyAssemblyResolve");
 
983
                                
 
984
                                try {
 
985
                                        AppDomain.CurrentDomain.AssemblyResolve += resolver;
 
986
                                        if (einfo != null) einfo.AddEventHandler (AppDomain.CurrentDomain, resolver);
 
987
                                
 
988
                                        AddinDescription desc = scanner.ScanSingleFile (progressStatus, file, new AddinScanResult ());
 
989
                                        if (desc != null)
 
990
                                                desc.Save (outFile);
 
991
                                }
 
992
                                finally {
 
993
                                        AppDomain.CurrentDomain.AssemblyResolve -= resolver;
 
994
                                        if (einfo != null) einfo.RemoveEventHandler (AppDomain.CurrentDomain, resolver);
 
995
                                }
 
996
                        }
 
997
                }
 
998
                
 
999
                Assembly OnResolveAddinAssembly (object s, ResolveEventArgs args)
 
1000
                {
 
1001
                        string file = currentScanResult.GetAssemblyLocation (args.Name);
 
1002
                        if (file != null)
 
1003
                                return Util.LoadAssemblyForReflection (file);
 
1004
                        else
 
1005
                                return null;
 
1006
                }
 
1007
                
 
1008
                public string GetFolderConfigFile (string path)
 
1009
                {
 
1010
                        path = Path.GetFullPath (path);
 
1011
                        
 
1012
                        string s = path.Replace ("_", "__");
 
1013
                        s = s.Replace (Path.DirectorySeparatorChar, '_');
 
1014
                        s = s.Replace (Path.AltDirectorySeparatorChar, '_');
 
1015
                        s = s.Replace (Path.VolumeSeparatorChar, '_');
 
1016
                        
 
1017
                        return Path.Combine (AddinFolderCachePath, s + ".data");
 
1018
                }
 
1019
                
 
1020
                internal void UninstallAddin (IProgressStatus monitor, string addinId, AddinScanResult scanResult)
 
1021
                {
 
1022
                        scanResult.AddRemovedAddin (addinId);
 
1023
                        string file = GetDescriptionPath (addinId);
 
1024
                        DeleteAddin (monitor, file, scanResult);
 
1025
                }
 
1026
                
 
1027
                internal void UninstallRootAddin (IProgressStatus monitor, string addinId, string addinFile, AddinScanResult scanResult)
 
1028
                {
 
1029
                        string file = fileDatabase.GetSharedObjectFile (AddinCachePath, addinId, ".mroot", addinFile);
 
1030
                        DeleteAddin (monitor, file, scanResult);
 
1031
                }
 
1032
                
 
1033
                void DeleteAddin (IProgressStatus monitor, string file, AddinScanResult scanResult)
 
1034
                {
 
1035
                        if (!fileDatabase.Exists (file))
 
1036
                                return;
 
1037
                        
 
1038
                        // Add-in already existed. The dependencies of the old add-in need to be re-analized
 
1039
 
 
1040
                        AddinDescription desc;
 
1041
                        if (ReadAddinDescription (monitor, file, out desc)) {
 
1042
                                Util.AddDependencies (desc, scanResult);
 
1043
                                if (desc.IsRoot)
 
1044
                                        scanResult.HostIndex.RemoveHostData (desc.AddinId, desc.AddinFile);
 
1045
                        } else
 
1046
                                // If we can't get information about the old assembly, just regenerate all relation data
 
1047
                                scanResult.RegenerateRelationData = true;
 
1048
 
 
1049
                        SafeDelete (monitor, file);
 
1050
                        SafeDeleteDir (monitor, Path.Combine (AddinPrivateDataPath, Path.GetFileNameWithoutExtension (file)));
 
1051
                }
 
1052
                
 
1053
                public bool GetHostDescription (IProgressStatus monitor, string addinId, string fileName, out AddinDescription description)
 
1054
                {
 
1055
                        try {
 
1056
                                description = AddinDescription.ReadHostBinary (fileDatabase, AddinCachePath, addinId, fileName);
 
1057
                                if (description != null)
 
1058
                                        description.OwnerDatabase = this;
 
1059
                                return true;
 
1060
                        }
 
1061
                        catch (Exception ex) {
 
1062
                                if (monitor == null)
 
1063
                                        throw;
 
1064
                                description = null;
 
1065
                                monitor.ReportError ("Could not read folder info file", ex);
 
1066
                                return false;
 
1067
                        }
 
1068
                }
 
1069
                
 
1070
                public bool GetAddinDescription (IProgressStatus monitor, string addinId, out AddinDescription description)
 
1071
                {
 
1072
                        string file = GetDescriptionPath (addinId);
 
1073
                        return ReadAddinDescription (monitor, file, out description);
 
1074
                }
 
1075
                
 
1076
                public bool ReadAddinDescription (IProgressStatus monitor, string file, out AddinDescription description)
 
1077
                {
 
1078
                        try {
 
1079
                                description = AddinDescription.ReadBinary (fileDatabase, file);
 
1080
                                if (description != null)
 
1081
                                        description.OwnerDatabase = this;
 
1082
                                return true;
 
1083
                        }
 
1084
                        catch (Exception ex) {
 
1085
                                if (monitor == null)
 
1086
                                        throw;
 
1087
                                description = null;
 
1088
                                monitor.ReportError ("Could not read folder info file", ex);
 
1089
                                return false;
 
1090
                        }
 
1091
                }
 
1092
                
 
1093
                public bool SaveDescription (IProgressStatus monitor, AddinDescription desc, string replaceFileName)
 
1094
                {
 
1095
                        try {
 
1096
                                if (replaceFileName != null)
 
1097
                                        desc.SaveBinary (fileDatabase, replaceFileName);
 
1098
                                else if (desc.IsRoot)
 
1099
                                        desc.SaveHostBinary (fileDatabase, AddinCachePath);
 
1100
                                else
 
1101
                                        desc.SaveBinary (fileDatabase, GetDescriptionPath (desc.AddinId));
 
1102
                                return true;
 
1103
                        }
 
1104
                        catch (Exception ex) {
 
1105
                                monitor.ReportError ("Add-in info file could not be saved", ex);
 
1106
                                return false;
 
1107
                        }
 
1108
                }
 
1109
                
 
1110
                public bool AddinDescriptionExists (string addinId)
 
1111
                {
 
1112
                        return fileDatabase.Exists (GetDescriptionPath (addinId));
 
1113
                }
 
1114
                
 
1115
                public bool HostDescriptionExists (string addinId, string sourceFile)
 
1116
                {
 
1117
                        return fileDatabase.SharedObjectExists (AddinCachePath, addinId, ".mroot", sourceFile);
 
1118
                }
 
1119
                
 
1120
                public bool ReadFolderInfo (IProgressStatus monitor, string file, out AddinScanFolderInfo folderInfo)
 
1121
                {
 
1122
                        try {
 
1123
                                folderInfo = AddinScanFolderInfo.Read (fileDatabase, file);
 
1124
                                return true;
 
1125
                        }
 
1126
                        catch (Exception ex) {
 
1127
                                folderInfo = null;
 
1128
                                monitor.ReportError ("Could not read folder info file", ex);
 
1129
                                return false;
 
1130
                        }
 
1131
                }
 
1132
                
 
1133
                public bool GetFolderInfoForPath (IProgressStatus monitor, string path, out AddinScanFolderInfo folderInfo)
 
1134
                {
 
1135
                        try {
 
1136
                                folderInfo = AddinScanFolderInfo.Read (fileDatabase, AddinFolderCachePath, path);
 
1137
                                return true;
 
1138
                        }
 
1139
                        catch (Exception ex) {
 
1140
                                folderInfo = null;
 
1141
                                monitor.ReportError ("Could not read folder info file", ex);
 
1142
                                return false;
 
1143
                        }
 
1144
                }
 
1145
 
 
1146
                public bool SaveFolderInfo (IProgressStatus monitor, AddinScanFolderInfo folderInfo)
 
1147
                {
 
1148
                        try {
 
1149
                                folderInfo.Write (fileDatabase, AddinFolderCachePath);
 
1150
                                return true;
 
1151
                        }
 
1152
                        catch (Exception ex) {
 
1153
                                monitor.ReportError ("Could not write folder info file", ex);
 
1154
                                return false;
 
1155
                        }
 
1156
                }
 
1157
                
 
1158
                public bool DeleteFolderInfo (IProgressStatus monitor, AddinScanFolderInfo folderInfo)
 
1159
                {
 
1160
                        return SafeDelete (monitor, folderInfo.FileName);
 
1161
                }
 
1162
                
 
1163
                public bool SafeDelete (IProgressStatus monitor, string file)
 
1164
                {
 
1165
                        try {
 
1166
                                fileDatabase.Delete (file);
 
1167
                                return true;
 
1168
                        }
 
1169
                        catch (Exception ex) {
 
1170
                                if (monitor.LogLevel > 1) {
 
1171
                                        monitor.Log ("Could not delete file: " + file);
 
1172
                                        monitor.Log (ex.ToString ());
 
1173
                                }
 
1174
                                return false;
 
1175
                        }
 
1176
                }
 
1177
                
 
1178
                public bool SafeDeleteDir (IProgressStatus monitor, string dir)
 
1179
                {
 
1180
                        try {
 
1181
                                fileDatabase.DeleteDir (dir);
 
1182
                                return true;
 
1183
                        }
 
1184
                        catch (Exception ex) {
 
1185
                                if (monitor.LogLevel > 1) {
 
1186
                                        monitor.Log ("Could not delete directory: " + dir);
 
1187
                                        monitor.Log (ex.ToString ());
 
1188
                                }
 
1189
                                return false;
 
1190
                        }
 
1191
                }
 
1192
                
 
1193
                AddinHostIndex GetAddinHostIndex ()
 
1194
                {
 
1195
                        if (hostIndex != null)
 
1196
                                return hostIndex;
 
1197
                        
 
1198
                        using (fileDatabase.LockRead ()) {
 
1199
                                if (fileDatabase.Exists (HostIndexFile))
 
1200
                                        hostIndex = AddinHostIndex.Read (fileDatabase, HostIndexFile);
 
1201
                                else
 
1202
                                        hostIndex = new AddinHostIndex ();
 
1203
                        }
 
1204
                        return hostIndex;
 
1205
                }
 
1206
                
 
1207
                void SaveAddinHostIndex ()
 
1208
                {
 
1209
                        if (hostIndex != null)
 
1210
                                hostIndex.Write (fileDatabase, HostIndexFile);
 
1211
                }
 
1212
                
 
1213
                internal string GetUniqueAddinId (string file, string oldId, string ns, string version)
 
1214
                {
 
1215
                        string baseId = "__" + Path.GetFileNameWithoutExtension (file);
 
1216
 
 
1217
                        if (Path.GetExtension (baseId) == ".addin")
 
1218
                                baseId = Path.GetFileNameWithoutExtension (baseId);
 
1219
                        
 
1220
                        string name = baseId;
 
1221
                        string id = Addin.GetFullId (ns, name, version);
 
1222
                        
 
1223
                        // If the old Id is already an automatically generated one, reuse it
 
1224
                        if (oldId != null && oldId.StartsWith (id))
 
1225
                                return name;
 
1226
                        
 
1227
                        int n = 1;
 
1228
                        while (fileDatabase.Exists (GetDescriptionPath (id))) {
 
1229
                                name = baseId + "_" + n;
 
1230
                                id = Addin.GetFullId (ns, name, version);
 
1231
                                n++;
 
1232
                        }
 
1233
                        return name;
 
1234
                }
 
1235
                
 
1236
                public void ResetConfiguration ()
 
1237
                {
 
1238
                        if (File.Exists (ConfigFile))
 
1239
                                File.Delete (ConfigFile);
 
1240
                }
 
1241
                
 
1242
                DatabaseConfiguration Configuration {
 
1243
                        get {
 
1244
                                if (config == null) {
 
1245
                                        using (fileDatabase.LockRead ()) {
 
1246
                                                if (fileDatabase.Exists (ConfigFile))
 
1247
                                                        config = DatabaseConfiguration.Read (ConfigFile);
 
1248
                                                else
 
1249
                                                        config = new DatabaseConfiguration ();
 
1250
                                        }
 
1251
                                }
 
1252
                                return config;
 
1253
                        }
 
1254
                }
 
1255
                
 
1256
                void SaveConfiguration ()
 
1257
                {
 
1258
                        if (config != null) {
 
1259
                                using (fileDatabase.LockWrite ()) {
 
1260
                                        config.Write (ConfigFile);
 
1261
                                }
 
1262
                        }
 
1263
                }
 
1264
        }
 
1265
        
 
1266
        class SingleFileAssemblyResolver
 
1267
        {
 
1268
                AddinScanResult scanResult;
 
1269
                AddinScanner scanner;
 
1270
                AddinRegistry registry;
 
1271
                IProgressStatus progressStatus;
 
1272
                
 
1273
                public SingleFileAssemblyResolver (IProgressStatus progressStatus, AddinRegistry registry, AddinScanner scanner)
 
1274
                {
 
1275
                        this.scanner = scanner;
 
1276
                        this.registry = registry;
 
1277
                        this.progressStatus = progressStatus;
 
1278
                }
 
1279
                
 
1280
                public Assembly Resolve (object s, ResolveEventArgs args)
 
1281
                {
 
1282
                        if (scanResult == null) {
 
1283
                                scanResult = new AddinScanResult ();
 
1284
                                scanResult.LocateAssembliesOnly = true;
 
1285
                        
 
1286
                                foreach (string dir in registry.AddinDirectories)
 
1287
                                        scanner.ScanFolder (progressStatus, dir, scanResult);
 
1288
                        }
 
1289
                
 
1290
                        string afile = scanResult.GetAssemblyLocation (args.Name);
 
1291
                        if (afile != null)
 
1292
                                return Util.LoadAssemblyForReflection (afile);
 
1293
                        else
 
1294
                                return null;
 
1295
                }
 
1296
        }
 
1297
}
 
1298
 
 
1299