2
// RepositoryRegistry.cs
7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
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:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
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.
33
using System.Collections;
34
using Mono.Addins.Setup.ProgressMonitoring;
35
using System.Collections.Generic;
37
namespace Mono.Addins.Setup
40
/// A registry of on-line repositories
43
/// This class can be used to manage on-line repository subscriptions.
45
public class RepositoryRegistry
50
internal RepositoryRegistry (SetupService service)
52
this.service = service;
56
/// Subscribes to an on-line repository
58
/// <param name="monitor">
59
/// Progress monitor where to show progress status and log
61
/// <param name="url">
62
/// URL of the repository
65
/// A repository reference
68
/// The repository index is not downloaded by default. It can be downloaded
69
/// by calling UpdateRepository.
71
public AddinRepository RegisterRepository (IProgressStatus monitor, string url)
73
return RegisterRepository (monitor, url, false);
77
/// Subscribes to an on-line repository
79
/// <param name="monitor">
80
/// Progress monitor where to show progress status and log
82
/// <param name="url">
83
/// URL of the repository
85
/// <param name="updateNow">
86
/// When set to True, the repository index will be downloaded.
89
/// A repository reference
91
public AddinRepository RegisterRepository (IProgressStatus monitor, string url, bool updateNow)
93
if (string.IsNullOrEmpty (url))
94
throw new ArgumentException ("Emtpy url");
96
if (!url.EndsWith (".mrep")) {
97
if (url [url.Length - 1] != '/')
99
url = url + "main.mrep";
102
RepositoryRecord rr = FindRepositoryRecord (url);
106
rr = RegisterRepository (url, false);
110
UpdateRepository (monitor, url);
111
rr = FindRepositoryRecord (url);
112
Repository rep = rr.GetCachedRepository ();
116
service.SaveConfiguration ();
118
} catch (Exception ex) {
120
monitor.ReportError ("The repository could not be registered", ex);
121
if (ContainsRepository (url))
122
RemoveRepository (url);
127
internal RepositoryRecord RegisterRepository (string url, bool isReference)
129
RepositoryRecord rr = FindRepositoryRecord (url);
131
if (rr.IsReference && !isReference) {
132
rr.IsReference = false;
133
service.SaveConfiguration ();
138
rr = new RepositoryRecord ();
140
rr.IsReference = isReference;
142
string name = service.RepositoryCachePath;
143
if (!Directory.Exists (name))
144
Directory.CreateDirectory (name);
145
string host = new Uri (url).Host;
146
if (host.Length == 0)
148
name = Path.Combine (name, host);
149
rr.File = name + "_" + service.Configuration.RepositoryIdCount + ".mrep";
151
rr.Id = "rep" + service.Configuration.RepositoryIdCount;
152
service.Configuration.Repositories.Add (rr);
153
service.Configuration.RepositoryIdCount++;
154
service.SaveConfiguration ();
159
internal RepositoryRecord FindRepositoryRecord (string url)
161
foreach (RepositoryRecord rr in service.Configuration.Repositories)
162
if (rr.Url == url) return rr;
167
/// Removes an on-line repository subscription.
169
/// <param name="url">
170
/// URL of the repository.
172
public void RemoveRepository (string url)
174
RepositoryRecord rep = FindRepositoryRecord (url);
176
return; // Nothing to do
178
foreach (RepositoryRecord rr in service.Configuration.Repositories) {
179
if (rr == rep) continue;
180
Repository newRep = rr.GetCachedRepository ();
181
if (newRep == null) continue;
182
foreach (ReferenceRepositoryEntry re in newRep.Repositories) {
184
// The repository can't be removed because there is another
185
// repository depending on it. Just mark it as a reference.
186
rep.IsReference = true;
192
// There are no other repositories referencing this one, so we can safely delete
194
Repository delRep = rep.GetCachedRepository ();
195
service.Configuration.Repositories.Remove (rep);
196
rep.ClearCachedRepository ();
198
if (delRep != null) {
199
foreach (ReferenceRepositoryEntry re in delRep.Repositories)
200
RemoveRepository (new Uri (new Uri (url), re.Url).ToString ());
203
service.SaveConfiguration ();
208
/// Enables or disables a repository
210
/// <param name='url'>
211
/// URL of the repository
213
/// <param name='enabled'>
214
/// 'true' if the repository has to be enabled.
217
/// Disabled repositories are ignored when calling UpdateAllRepositories.
219
public void SetRepositoryEnabled (string url, bool enabled)
221
RepositoryRecord rep = FindRepositoryRecord (url);
223
return; // Nothing to do
224
rep.Enabled = enabled;
225
Repository crep = rep.GetCachedRepository ();
227
foreach (RepositoryEntry re in crep.Repositories)
228
SetRepositoryEnabled (new Uri (new Uri (url), re.Url).ToString (), enabled);
231
service.SaveConfiguration ();
235
/// Checks if a repository is already subscribed.
237
/// <param name="url">
238
/// URL of the repository
241
/// True if the repository is already subscribed.
243
public bool ContainsRepository (string url)
245
return FindRepositoryRecord (url) != null;
248
ArrayList RepositoryList {
250
if (repoList == null) {
251
ArrayList list = new ArrayList ();
252
foreach (RepositoryRecord rep in service.Configuration.Repositories) {
253
if (!rep.IsReference)
263
/// Gets a list of subscribed repositories
266
/// A list of repositories.
268
public AddinRepository[] GetRepositories ()
270
return (AddinRepository[]) RepositoryList.ToArray (typeof(AddinRepository));
274
/// Updates the add-in index of all subscribed repositories.
276
/// <param name="monitor">
277
/// Progress monitor where to show progress status and log
279
public void UpdateAllRepositories (IProgressStatus monitor)
281
UpdateRepository (monitor, (string)null);
285
/// Updates the add-in index of the provided repository
287
/// <param name="statusMonitor">
288
/// Progress monitor where to show progress status and log
290
/// <param name="url">
291
/// URL of the repository
293
public void UpdateRepository (IProgressStatus statusMonitor, string url)
297
IProgressMonitor monitor = ProgressStatusMonitor.GetProgressMonitor (statusMonitor);
299
monitor.BeginTask ("Updating repositories", service.Configuration.Repositories.Count);
301
int num = service.Configuration.Repositories.Count;
302
for (int n=0; n<num; n++) {
303
RepositoryRecord rr = (RepositoryRecord) service.Configuration.Repositories [n];
304
if (((url == null && rr.Enabled) || rr.Url == url) && !rr.IsReference)
305
UpdateRepository (monitor, new Uri (rr.Url), rr);
308
} catch (Exception ex) {
309
statusMonitor.ReportError ("Could not get information from repository", ex);
314
service.SaveConfiguration ();
317
void UpdateRepository (IProgressMonitor monitor, Uri baseUri, RepositoryRecord rr)
319
Uri absUri = new Uri (baseUri, rr.Url);
320
monitor.BeginTask ("Updating from " + absUri.ToString (), 2);
321
Repository newRep = null;
322
Exception error = null;
325
newRep = (Repository) service.Store.DownloadObject (monitor, absUri.ToString (), typeof(Repository));
326
} catch (Exception ex) {
330
if (newRep == null) {
331
monitor.ReportError ("Could not get information from repository" + ": " + absUri.ToString (), error);
337
foreach (ReferenceRepositoryEntry re in newRep.Repositories) {
338
Uri refRepUri = new Uri (absUri, re.Url);
339
string refRepUrl = refRepUri.ToString ();
340
RepositoryRecord refRep = FindRepositoryRecord (refRepUrl);
342
refRep = RegisterRepository (refRepUrl, true);
343
refRep.Enabled = rr.Enabled;
344
// Update the repo if the modified timestamp changes or if there is no timestamp info
345
if (refRep.LastModified != re.LastModified || re.LastModified == DateTime.MinValue) {
346
refRep.LastModified = re.LastModified;
347
UpdateRepository (monitor, refRepUri, refRep);
351
rr.UpdateCachedRepository (newRep);
355
/// Gets a list of available add-in updates.
358
/// A list of add-in references.
361
/// The list is generated by looking at the add-ins currently installed and checking if there is any
362
/// add-in with a newer version number in any of the subscribed repositories. This method uses cached
363
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
364
/// before using this method to ensure that the latest information is available.
366
public AddinRepositoryEntry[] GetAvailableUpdates ()
368
return GetAvailableAddin (null, null, null, true, RepositorySearchFlags.None);
372
/// Gets a list of available add-in updates.
374
/// <param name="flags">
378
/// A list of add-in references.
381
/// The list is generated by looking at the add-ins currently installed and checking if there is any
382
/// add-in with a newer version number in any of the subscribed repositories. This method uses cached
383
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
384
/// before using this method to ensure that the latest information is available.
386
public AddinRepositoryEntry[] GetAvailableUpdates (RepositorySearchFlags flags)
388
return GetAvailableAddin (null, null, null, true, flags);
392
/// Gets a list of available add-in updates in a specific repository.
394
/// <param name="repositoryUrl">
395
/// The repository URL
398
/// A list of add-in references.
401
/// The list is generated by looking at the add-ins currently installed and checking if there is any
402
/// add-in with a newer version number in the provided repository. This method uses cached
403
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
404
/// before using this method to ensure that the latest information is available.
406
public AddinRepositoryEntry[] GetAvailableUpdates (string repositoryUrl)
408
return GetAvailableAddin (repositoryUrl, null, null, true, RepositorySearchFlags.None);
411
#pragma warning disable 1591
412
[Obsolete ("Use GetAvailableAddinUpdates (id) instead")]
413
public AddinRepositoryEntry[] GetAvailableUpdates (string id, string version)
415
return GetAvailableAddin (null, id, version, true, RepositorySearchFlags.None);
418
[Obsolete ("Use GetAvailableAddinUpdates (repositoryUrl, id) instead")]
419
public AddinRepositoryEntry[] GetAvailableUpdates (string repositoryUrl, string id, string version)
421
return GetAvailableAddin (repositoryUrl, id, version, true, RepositorySearchFlags.None);
423
#pragma warning restore 1591
426
/// Gets a list of available updates for an add-in.
428
/// <param name="id">
429
/// Identifier of the add-in.
432
/// List of updates for the specified add-in.
435
/// The list is generated by checking if there is any
436
/// add-in with a newer version number in any of the subscribed repositories. This method uses cached
437
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
438
/// before using this method to ensure that the latest information is available.
440
public AddinRepositoryEntry[] GetAvailableAddinUpdates (string id)
442
return GetAvailableAddin (null, id, null, true, RepositorySearchFlags.None);
446
/// Gets a list of available updates for an add-in.
448
/// <param name="id">
449
/// Identifier of the add-in.
451
/// <param name='flags'>
455
/// List of updates for the specified add-in.
458
/// The list is generated by checking if there is any
459
/// add-in with a newer version number in any of the subscribed repositories. This method uses cached
460
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
461
/// before using this method to ensure that the latest information is available.
463
public AddinRepositoryEntry[] GetAvailableAddinUpdates (string id, RepositorySearchFlags flags)
465
return GetAvailableAddin (null, id, null, true, flags);
469
/// Gets a list of available updates for an add-in in a specific repository
471
/// <param name="repositoryUrl">
472
/// Identifier of the add-in.
474
/// <param name="id">
475
/// Identifier of the add-in.
478
/// List of updates for the specified add-in.
481
/// The list is generated by checking if there is any
482
/// add-in with a newer version number in the provided repository. This method uses cached
483
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
484
/// before using this method to ensure that the latest information is available.
486
public AddinRepositoryEntry[] GetAvailableAddinUpdates (string repositoryUrl, string id)
488
return GetAvailableAddin (repositoryUrl, id, null, true, RepositorySearchFlags.None);
492
/// Gets a list of available updates for an add-in in a specific repository
494
/// <param name="repositoryUrl">
495
/// Identifier of the add-in.
497
/// <param name="id">
498
/// Identifier of the add-in.
500
/// <param name='flags'>
504
/// List of updates for the specified add-in.
507
/// The list is generated by checking if there is any
508
/// add-in with a newer version number in the provided repository. This method uses cached
509
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
510
/// before using this method to ensure that the latest information is available.
512
public AddinRepositoryEntry[] GetAvailableAddinUpdates (string repositoryUrl, string id, RepositorySearchFlags flags)
514
return GetAvailableAddin (repositoryUrl, id, null, true, flags);
518
/// Gets a list of all available add-ins
521
/// A list of add-ins
524
/// This method uses cached
525
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
526
/// before using this method to ensure that the latest information is available.
528
public AddinRepositoryEntry[] GetAvailableAddins ()
530
return GetAvailableAddin (null, null, null, false, RepositorySearchFlags.None);
534
/// Gets a list of all available add-ins
537
/// The available addins.
539
/// <param name='flags'>
543
/// This method uses cached
544
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
545
/// before using this method to ensure that the latest information is available.
547
public AddinRepositoryEntry[] GetAvailableAddins (RepositorySearchFlags flags)
549
return GetAvailableAddin (null, null, null, false, flags);
553
/// Gets a list of all available add-ins in a repository
555
/// <param name="repositoryUrl">
559
/// A list of add-ins
562
/// This method uses cached
563
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
564
/// before using this method to ensure that the latest information is available.
566
public AddinRepositoryEntry[] GetAvailableAddins (string repositoryUrl)
568
return GetAvailableAddin (repositoryUrl, null, null);
572
/// Gets a list of all available add-ins in a repository
574
/// <param name="repositoryUrl">
577
/// <param name='flags'>
581
/// A list of add-ins
584
/// This method uses cached
585
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
586
/// before using this method to ensure that the latest information is available.
588
public AddinRepositoryEntry[] GetAvailableAddins (string repositoryUrl, RepositorySearchFlags flags)
590
return GetAvailableAddin (repositoryUrl, null, null, false, flags);
594
/// Checks if an add-in is available to be installed
596
/// <param name="id">
597
/// Identifier of the add-in
599
/// <param name="version">
600
/// Version of the add-in (optional, it can be null)
603
/// A list of add-ins
606
/// List of references to add-ins available in on-line repositories. This method uses cached
607
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
608
/// before using this method to ensure that the latest information is available.
610
public AddinRepositoryEntry[] GetAvailableAddin (string id, string version)
612
return GetAvailableAddin (null, id, version);
616
/// Checks if an add-in is available to be installed from a repository
618
/// <param name="repositoryUrl">
621
/// <param name="id">
622
/// Identifier of the add-in
624
/// <param name="version">
625
/// Version of the add-in (optional, it can be null)
628
/// A list of add-ins
631
/// List of references to add-ins available in the repository. This method uses cached
632
/// information from on-line repositories. Make sure you call UpdateRepository or UpdateAllRepositories
633
/// before using this method to ensure that the latest information is available.
635
public AddinRepositoryEntry[] GetAvailableAddin (string repositoryUrl, string id, string version)
637
return GetAvailableAddin (repositoryUrl, id, version, false, RepositorySearchFlags.None);
640
PackageRepositoryEntry[] GetAvailableAddin (string repositoryUrl, string id, string version, bool updates, RepositorySearchFlags flags)
642
List<PackageRepositoryEntry> list = new List<PackageRepositoryEntry> ();
645
if (repositoryUrl != null) {
646
ArrayList repos = new ArrayList ();
647
GetRepositoryTree (repositoryUrl, repos);
650
ee = service.Configuration.Repositories;
652
foreach (RepositoryRecord rr in ee) {
655
Repository rep = rr.GetCachedRepository();
656
if (rep == null) continue;
657
foreach (PackageRepositoryEntry addin in rep.Addins) {
658
if ((id == null || Addin.GetIdName (addin.Addin.Id) == id) && (version == null || addin.Addin.Version == version)) {
660
Addin ainfo = service.Registry.GetAddin (Addin.GetIdName (addin.Addin.Id));
661
if (ainfo == null || Addin.CompareVersions (ainfo.Version, addin.Addin.Version) <= 0)
669
if ((flags & RepositorySearchFlags.LatestVersionsOnly) != 0)
670
FilterOldVersions (list);
672
// Old versions are returned first
674
return list.ToArray ();
677
void FilterOldVersions (List<PackageRepositoryEntry> addins)
679
Dictionary<string,string> versions = new Dictionary<string, string> ();
680
foreach (PackageRepositoryEntry a in addins) {
683
Addin.GetIdParts (a.Addin.Id, out id, out version);
684
if (!versions.TryGetValue (id, out last) || Addin.CompareVersions (last, version) > 0)
685
versions [id] = version;
687
for (int n=0; n<addins.Count; n++) {
688
PackageRepositoryEntry a = addins [n];
690
Addin.GetIdParts (a.Addin.Id, out id, out version);
691
if (versions [id] != version)
692
addins.RemoveAt (n--);
696
void GetRepositoryTree (string url, ArrayList list)
698
RepositoryRecord rr = FindRepositoryRecord (url);
699
if (rr == null) return;
701
if (list.Contains (rr))
705
Repository rep = rr.GetCachedRepository ();
709
Uri absUri = new Uri (url);
710
foreach (ReferenceRepositoryEntry re in rep.Repositories) {
711
Uri refRepUri = new Uri (absUri, re.Url);
712
GetRepositoryTree (refRepUri.ToString (), list);
717
public enum RepositorySearchFlags
720
/// No special search options
725
/// Only the latest version of every add-in is included in the search
727
LatestVersionsOnly = 1,