Laden...
FAQ

[FAQ] Automatisches Vergeben der Revisions- und Buildnummer

Erstellt von Xqgene vor 13 Jahren Letzter Beitrag vor 13 Jahren 26.324 Views
Warnung von Abt vor 3 Jahren

Dieser Artikel ist veraltet und findet kaum noch Verwendung.

Ein moderner Ansatz ist
[Artikel] Automatische, standardisierte Versionsvergabe in und mit .NET

X
Xqgene Themenstarter:in
2.051 Beiträge seit 2004
vor 13 Jahren
[FAQ] Automatisches Vergeben der Revisions- und Buildnummer

Ich hatte schon längere Zeit vor, mein Visual Studio so zu konfigurieren, dass die Revision und Build in der AssemblyInfo.cs automatisch vergeben werden.
Die Build soll einfach hochgezählt werden, die Revison soll aus Subversion übernommen werden.
Nach „langer“ Suche, unter anderem auch hier im Forum, habe ich unten beschriebene Lösung "zusammengefunden". (An der Stelle sei erwähnt, dass ein paar Tipps von JuyJuka kamen.)
Ich dachte, dass meine Sucherei vielleicht jemandem noch nützt. in Form eines FAQ Beitrages, o.ä.
Die Beschreibung ist etwas größer geworden als ich dachte. Also Korrekturlesen wäre ganz angebracht.

Meine Umgebung:

  • VS 2008/VS 2010 RC
  • Subverion 1.6.9 (im Netzwerk, keine Lokale Installation)

Subversion Version soll dabei eigentlich keine Rolle spielen. Zumindest habe ich bei meiner Recherche diese gar nicht beachtet.

Versionsnummer soll im Format Major.Minor.Revision.Build erzeugt werden.
(nicht MS Format: Major.Minor.Build.Revision )

Als erstes muss man MSBuild Community Tasks installieren. Diese kann man von http://msbuildtasks.tigris.org/ runterladen. MSBuild Community Tasks ist Ansammlung von verschiedenen Tools, welche man in den Build Prozess einbinden kann.
Uns interessieren dabei nur drei der vielen nützlichen Tasks: Version, SvnVersion und AssemblyInfo

Version-Task hilft die Buildnummer des Projektes zu zählen, mit Hilfe von SvnVersion-Tasks werden wir die Revision des Projektes aus Subverion auslesen. AssemblyInfo erstellt dann eine AssemblyInvo.cs Datei mit den Versionsinformationen.

Nachdem die MSBuild Community Tasks installiert sind, muss man prüfen, ob ein SvnClient auf dem Rechner vorhanden ist. Diesen braucht man wegen der svnversion.exe. svnversion.exe wird von SvnVersion-Task benutzt, um wie oben bereits beschrieben, die Revision zu ermitteln. Wenn Subversion lokal installiert wurde, dann ist die svnversion.exe (ohne Gewähr 😉 ) bereits vorhanden. Wenn nicht dann soll jetzt ein SvnClient drauf. Ich habe z.B. Silk Subverion Client benutzt (http://www.sliksvn.com/)

Nun wenn alle Voraussetzungen geschaffen sind, kommen wir zum nächsten Abschnitt: Anpassen der Projekt-Datei.

Man öffnet die C#-Projekt-Datei (*.csproj) in einem Text-Editor und geht ans Ende. Sieht etwa so aus (VS 2010)

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

Zuerst muss man VisualStudio anweisen, die MSBuild Community Tasks zu benutzen. Dafür fügt man folgende „Anweisung“ ein


<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"        
        Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')"/> 

gleich unter der Zeile

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

Attribut “Project” zeigt, wo die Community Tasks sich befinden (Standardinstallation)
“Condition” sorgt dafür, dass Projekt geladen werden kann, auch wenn die Community Tasks nicht installiert sind.
Im nächsten Schritt sorgen wir dafür, dass die Build-Nummer automatisch um eins erhöht wird.
Dafür ist Version-Task zuständig. Version-Task speichert in einer Datei die letzte Versionsnummer und erhöht die Build-Nummer bei jedem Aufruf um eins.

<Target Name="Version">
    <Version VersionFile="version.txt" RevisionType="Increment">
      <Output TaskParameter="Major" PropertyName="Major" />
      <Output TaskParameter="Minor" PropertyName="Minor" />
      <Output TaskParameter="Build" PropertyName="Build" />
      <Output TaskParameter="Revision" PropertyName="Revision" />
    </Version> 
</Target>

VersionFile gibt den Namen der Datei an, in der die Version gespeichert wird. Beim ersten Ausführen, wird eine neue Datei erstellt und Version 1.0.0.0 gespeichert. Zweite Ausgabe wäre dann 1.0.0.1, dann 1.0.0.2 usw.
RevisionType=“Increment“ bedeutet, dass die letzte Stelle (Revision nach MS Standard) der Versionsnummer inkrementiert wird.
Damit Projekt beim Kompilieren nicht angemeckert wird (wegen fehlender CommunityTasks), soll man eine Bedingung auch hier eingeben

Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')"

Nach dem Ausführen des Version-Tasks sind Major, Minor, Build und Revision Variablen gesetzt und können weiter, z.B. durch andere Tasks, benutzt werden.

Nächster Part sorgt dafür, dass die Revisionsnummer aus SVN ausgelesen wird und erstellt eine AssemblyInfo.cs Datei.

<Target Name="AssemblyInfo"
        Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(ProgramFiles)\SlikSvn\bin" 
	            Condition="Exists('$(ProgramFiles)\SlikSvn\bin\svnversion.exe')">
      <Output TaskParameter="Revision" PropertyName="Build" />
    </SvnVersion>

    <AssemblyInfo
      CodeLanguage="CS"
      OutputFile="Properties\AssemblyInfo.cs"
      AssemblyTitle="Title"
      AssemblyDescription="Description"
      AssemblyCompany="Company"
      AssemblyProduct="Product"
      AssemblyCopyright="Copyright © 2009"
      ComVisible="false"
      Guid="888ff638-9547-4480-9bf4-4fe25103b35c"
      AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)"
      AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)"
      Condition="$(Revision) != '0'"/>
  </Target>

Bei dem SvnVersion-Task muss Pfad zu dem Verzeichnis mit der svnversion.exe Datei eigegeben werden. Condition sollte selbst erklärend sein.
Interessant ist der Output-Tag. Der besagt, dass der Wert der Eigenschaft „Revision“ des SvnVersion-Tasks in der Variable „Build“ gespeichert werden soll.

Nun kommt der AssemblyInfo-Task endlich ins Spiel. Dieser Tasks erstellt aus den gegebenen Informationen eine Assemblyinfo.cs. Die Felder sind soweit selbsterklärend. Wichtig ist, dass die GUID durch eine eigene ersetzt wird und sich bei den einzelnen Projekten NICHT wiederholt.
Interessante Stellen sind AssemblyVersion/AssemblyFileVersion Eingaben. Die Version wird durch Variablen, welche Version und SvnVersion-Tasks vorbereitet haben, zusammen gesetzt.

Nach dem alle Tasks definiert wurde, bleibt noch zu sagen, wann diese aufgerufen werden sollen. Die AssemblyIfo.cs Datei soll vor dem Erstellen des Projektes erzeugt werden. Deshalb wird der Aufruf der Tasks folgendermaßen angegeben.

<Target Name="BeforeBuild">
    <CallTarget Targets="Version" /> 
    <CallTarget Targets="AssemblyInfo" />
</Target>

Nun die vollständige Projektdatei könnte dann so aussehen

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>9.0.21022</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{ACF93EAD-62EF-4614-AEF4-45B6971957EF}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>WindowsFormsApplication2</RootNamespace>
    <AssemblyName>WindowsFormsApplication2</AssemblyName>
    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <FileUpgradeFlags>
    </FileUpgradeFlags>
    <UpgradeBackupLocation>
    </UpgradeBackupLocation>
    <OldToolsVersion>3.5</OldToolsVersion>
    <PublishUrl>publish\</PublishUrl>
    <Install>true</Install>
    <InstallFrom>Disk</InstallFrom>
    <UpdateEnabled>false</UpdateEnabled>
    <UpdateMode>Foreground</UpdateMode>
    <UpdateInterval>7</UpdateInterval>
    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
    <UpdatePeriodically>false</UpdatePeriodically>
    <UpdateRequired>false</UpdateRequired>
    <MapFileExtensions>true</MapFileExtensions>
    <ApplicationRevision>0</ApplicationRevision>
    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
    <IsWebBootstrapper>false</IsWebBootstrapper>
    <UseApplicationTrust>false</UseApplicationTrust>
    <BootstrapperEnabled>true</BootstrapperEnabled>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core">
      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Xml.Linq">
      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Data.DataSetExtensions">
      <RequiredTargetFramework>3.5</RequiredTargetFramework>
    </Reference>
    <Reference Include="System.Data" />
    <Reference Include="System.Deployment" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="Form1.cs">
      <SubType>Form</SubType>
    </Compile>
    <Compile Include="Form1.Designer.cs">
      <DependentUpon>Form1.cs</DependentUpon>
    </Compile>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <EmbeddedResource Include="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
      <SubType>Designer</SubType>
    </EmbeddedResource>
    <Compile Include="Properties\Resources.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
      <DesignTime>True</DesignTime>
    </Compile>
    <None Include="Properties\Settings.settings">
      <Generator>SettingsSingleFileGenerator</Generator>
      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
    </None>
    <Compile Include="Properties\Settings.Designer.cs">
      <AutoGen>True</AutoGen>
      <DependentUpon>Settings.settings</DependentUpon>
      <DesignTimeSharedInput>True</DesignTimeSharedInput>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
      <Install>false</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
      <Visible>False</Visible>
      <ProductName>.NET Framework 3.5 SP1</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
      <Visible>False</Visible>
      <ProductName>Windows Installer 3.1</ProductName>
      <Install>true</Install>
    </BootstrapperPackage>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <!-- import MSBuildCommunityTasks -->
  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" 
          Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')"/>
  <!-- to manage version number -->
  <Target Name="Version"
		  Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <Version VersionFile="version.txt" RevisionType="Increment">
      <Output TaskParameter="Major" PropertyName="Major" />
      <Output TaskParameter="Minor" PropertyName="Minor" />
      <Output TaskParameter="Revision" PropertyName="Revision" />
      <Output TaskParameter="Build" PropertyName="Build" />
    </Version> 
  </Target>
  <!-- to generate our personnal version info -->
  <Target Name="AssemblyInfo" Condition="Exists('$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets')">
    <SvnVersion LocalPath="$(MSBuildProjectDirectory)" ToolPath="$(ProgramFiles)\SlikSvn\bin" 
	            Condition="Exists('$(ProgramFiles)\SlikSvn\bin\svnversion.exe')">
      <Output TaskParameter="Revision" PropertyName="Build" />
    </SvnVersion>

    <AssemblyInfo
      CodeLanguage="CS"
      OutputFile="Properties\AssemblyInfo.cs"
      AssemblyTitle="Test-WindowsFormsApplication"
      AssemblyDescription="Beispiel für Verwendung der MSBuild Tasks"
      AssemblyCompany="Ich"
      AssemblyProduct="WindowsFormsApplication2"
      AssemblyCopyright="Copyright © 2010"
      ComVisible="false"
      Guid="3AEEC92E-C260-4DD2-8F6D-790182F14CFE"
      AssemblyVersion="$(Major).$(Minor).$(Build).$(Revision)"
      AssemblyFileVersion="$(Major).$(Minor).$(Build).$(Revision)"
      Condition="$(Revision) != '0' "/>
  </Target>

  <Target Name="BeforeBuild">
    <CallTarget Targets="Version" /> 
    <CallTarget Targets="AssemblyInfo" />
  </Target>
  <Target Name="AfterBuild">
  </Target>
</Project>

Die erzeugte Datei sieht dann, wie im Beispiel unten aus. Wictig ist, dass man die erzeugte AssemblyInfo Datei nicht manuell bearbeitet, denn sie wird bei jedem Build-Vorgang überschrieben.

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30128.1
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("Test-WindowsFormsApplication")]
[assembly: AssemblyDescription("Beispiel für Verwendung der MSBuild Tasks")]
[assembly: AssemblyCompany("Ich")]
[assembly: AssemblyProduct("WindowsFormsApplication2")]
[assembly: AssemblyCopyright("Copyright © 2010")]
[assembly: ComVisible(false)]
[assembly: Guid("3AEEC92E-C260-4DD2-8F6D-790182F14CFE")]
[assembly: AssemblyVersion("1.0.1.12")]
[assembly: AssemblyFileVersion("1.0.1.12")]

Als letzter Strich, sollte man die entstandene "version.txt"-Datei auch zum Projekt hinzufügen. Damit wird die Datei auch in die Subversion Datenbank aufgenommen. Das ist wichtig, damit beim öffnen des Projektes auf einem anderen Rechner, die Build-Zählung nicht wieder von Vorne beginnt, sondern fortgesetzt wird.

2.891 Beiträge seit 2004
vor 13 Jahren

Falls man Revisionsnummer, letztes Änderungsdatum und Autor seiner Klassen oder Assemblies programmatisch ermitteln möchte, gibt es dafür eine relativ einfache Lösung: Das SubversionAttribute.

Wir ja sicherlich bekannt ist, wird - wenn man für die Quelltextdateien svn:keywords=Id gesetzt hat - beim Auschecken/Updaten automatisch die Zeichenfolge "$Id$" mit den Revisionseigenschaften (Dateiname, Revision, Änderungsdatum, Autor) substituiert. (Diese SVN-Eigenschaft muss explizit für jede Quelltextdatei gesetzt werden. Bei TortoiseSVN kann man das über auto-props lösen.

Man kann also Revisionsinformationen der Dateien direkt mit in die Programme einkompilieren. Mithilfe des Subversion-Attributs kann man so detailliert Versionsinformationen von Typen und Assemblies abfragen. Dazu einfach eine Assembly/einen Typen mit [Subversion("$Id$")] annotieren und beim nächsten Auschecken/Updaten werden dann an dieser Stelle die jeweiligen Infos eingesetzt.

Während der Ausführung des Programms kann man dann mit den entsprechenden Methoden alle (SubversionAttribute.FindAll(...)) bzw. das neueste (SubversionAttribute.FindLatest(...)) Attribut(e) einer Assembly oder eines Typs zusammensuchen.


using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;

[assembly:Subversion("$Id: SubversionAttribute.cs 27 2010-02-01 12:57:06Z dr $")]
namespace RevisionInfo
{
	/// <summary>
	/// Liefert Informationen aus dem Versionsverwaltungssystem
	/// </summary>
	[Serializable]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Assembly,AllowMultiple=true)]
	[Subversion("$Id: SubversionAttribute.cs 27 2010-02-01 12:57:06Z dr $")]
	public class SubversionAttribute : Attribute
	{
		// Regex zum parsen der ID
		private static readonly Regex regex = new Regex(@"\$ id: \s*"
			+@"(?<headUrl>[^" + Regex.Escape(new string(Path.GetInvalidFileNameChars())) + @"]+) \s+"
			+@"(?<revision>\d+) \s+"
			+@"(?<date>\d\d\d\d-\d\d-\d\d \s+ \d\d:\d\d:\d\dZ) \s+"
			+@"(?<author>\w+)",
			RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Singleline | RegexOptions.ExplicitCapture | RegexOptions.Compiled);


		/// <summary>
		/// Gibt die komprimierte Version von Dateiname, Revision, Änderungsdatum und Autor zurück
		/// </summary>
		public string ID { get; private set; }

		/// <summary>
		/// Gibt den Autor der letzten bekannten Übertragung zurück
		/// </summary>
		public string Author { get; private set; }

		/// <summary>
		/// Gibt den vollständigen URL der Datei im Projektarchiv zurück
		/// </summary>
		public string HeadUrl { get; private set; }

		/// <summary>
		/// Gibt die Revisionsnummer der letzten bekannten Übertragung zurück
		/// </summary>
		public long Revision { get; private set; }

		/// <summary>
		/// Datum der letzten bekannten Übertragung. Dieses Datum hängt von der Information ab, die bei der letzten Aktualisierung der Arbeitskopie erhalten wurde. Es wird nicht das Projektarchiv auf neuere Änderungen abgefragt.
		/// </summary>
		public DateTime Date { get; private set; }

		/// <summary>
		/// Gibt an, ob das SVN-Schlüsselwort substituiert wurde.
		/// </summary>
		public bool IsSubstituted { get; private set; }


		/// <summary>
		/// Erstellt ein neues Subverions-Attribut
		/// </summary>
		/// <param name="id">die Subversion-ID</param>
		public SubversionAttribute(string id)
		{
			this.ID = id;
			this.IsSubstituted = (id.Trim().ToLower()!="$id"+"$");
			if (this.IsSubstituted)
			{
				Match match = regex.Match(id);
				this.HeadUrl = match.Groups["headUrl"].Value;
				this.Revision = Int64.Parse(match.Groups["revision"].Value);
				this.Date = DateTime.Parse(match.Groups["date"].Value);
				this.Author = match.Groups["author"].Value;
			}
		}


		/// <summary>
		/// Sucht das SubversionAttribute, das Informationen über die aktuellste Revision enthält.
		/// </summary>
		/// <param name="assembly">die Assembly, die durchsucht werden soll</param>
		/// <returns>das SubversionAttribute, das Informationen über die aktuellste Revision enthält, oder null</returns>
		public static SubversionAttribute FindLatest(Assembly assembly)
		{
			return FindLatest(assembly);
		}


		/// <summary>
		/// Sucht das SubversionAttribute, das Informationen über die aktuellste Revision enthält.
		/// </summary>
		/// <param name="type">der Typ, der durchsucht werden soll</param>
		/// <returns>das SubversionAttribute, das Informationen über die aktuellste Revision enthält, oder null</returns>
		public static SubversionAttribute FindLatest(Type type)
		{
			return FindLatest(type);
		}


		/// <summary>
		/// Sucht das SubversionAttribute, das Informationen über die aktuellste Revision enthält.
		/// </summary>
		/// <param name="customAttributeProvider">der CustomAttributeProvider zum Ermitteln der Attribute</param>
		/// <returns>das SubversionAttribute, das Informationen über die aktuellste Revision enthält, oder null</returns>
		private static SubversionAttribute FindLatest(ICustomAttributeProvider customAttributeProvider)
		{
			SubversionAttribute[] subversionAttributes = SubversionAttribute.findAll(customAttributeProvider).ToArray();
			if (subversionAttributes.Length>0)
			{
				Comparison<SubversionAttribute> comparer = (first,second) => second.Revision.CompareTo(first.Revision);
				Array.Sort(subversionAttributes,comparer);
				return subversionAttributes[0];
			}
			else
				return null;
		}



		/// <summary>
		/// Sucht alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten
		/// </summary>
		/// <param name="assembly">die Assembly, die durchsucht werden soll</param>
		/// <returns>alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten</returns>
		public static List<SubversionAttribute> FindAll(Assembly assembly)
		{
			return SubversionAttribute.findAll(assembly);
		}


		/// <summary>
		/// Sucht alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten
		/// </summary>
		/// <param name="type">der Typ, der durchsucht werden soll</param>
		/// <returns>alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten</returns>
		public static List<SubversionAttribute> FindAll(Type type)
		{
			return SubversionAttribute.findAll(type);
		}


		/// <summary>
		/// Sucht alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten
		/// </summary>
		/// <param name="customAttributeProvider">der CustomAttributeProvider zum Ermitteln der Attribute</param>
		/// <returns>alle SubversionAttribute, die Informationen über die verwendeten Revisionen erhalten</returns>
		private static List<SubversionAttribute> findAll(ICustomAttributeProvider customAttributeProvider)
		{
			List<SubversionAttribute> result = new List<SubversionAttribute>();
			foreach (SubversionAttribute subversionAttribute in customAttributeProvider.GetCustomAttributes(typeof(SubversionAttribute),false))
				if (subversionAttribute.IsSubstituted)
					result.Add(subversionAttribute);
			return result;
		}


		/// <summary>
		/// Gibt die Zeichenkettenrepräsentation dieses SubversionAttributes zurück
		/// </summary>
		/// <returns>die Zeichenkettenrepräsentation dieses SubversionAttributes</returns>
		public override string ToString()
		{
			return this.ID;
		}
	}
}