19

Hii, there are many others had already post so many question about this..But here the scenario is different.

I need to extract the first three digits ie. $(major).$(Minor).$(Build) from version number. how can i do this??..i tried AssemblyInfo Task..but that task is just for overwriting the version number.not to extract the version number.

I need to extract first three number and assign them to some property.for further use.

well,i can overwrite them using FileUpdate task.like ::

<FileUpdate 
    Files="@(AssemblyFile)" 
    Regex='(\d+)\.(\d+)\.(\d+)\.(\d+)' 
    ReplacementText='$1.$2.$3.$(Revision)'>
</FileUpdate>

now how can i use their value ie. $1,$2,$3 to assign to properties.???

Thanx.

vegemite4me
  • 6,621
  • 5
  • 53
  • 79
Divya mohan Singh
  • 485
  • 2
  • 7
  • 18

8 Answers8

33

You can read lines from files, get the string using regex and change it if you need. And if you're using MSBuild 4.0 you can use Property Functions, which give you an access to .NET API. This example should give you first three numbers of the AssemblyVersion.

<Target Name="ReadAssemblyVersion">

    <ReadLinesFromFile File="$(VersionFile)">
        <Output TaskParameter="Lines"
                ItemName="ItemsFromFile"/>
    </ReadLinesFromFile>

    <PropertyGroup>
        <Pattern>\[assembly: AssemblyVersion\(.(\d+)\.(\d+)\.(\d+)</Pattern>
        <In>@(ItemsFromFile)</In>
        <Out>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern)))</Out>
    </PropertyGroup>

    <Message Text="Output : $(Out.Remove(0, 28))"/>

</Target>

http://blogs.msdn.com/b/visualstudio/archive/2010/04/02/msbuild-property-functions.aspx

Alex Isayenko
  • 679
  • 8
  • 7
19

Awesome thread, building upon the work of Alex and RobPol, I was able to define extended msbuild properties that is inspired by semver.org (Major, Minor, Patch, PreRelease). I chose to parse the AssemblyInformalVersion since that is the only attribute compatible with SemVer. Here is My example:

<PropertyGroup>
    <In>$([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs'))</In>
    <Pattern>\[assembly: AssemblyInformationalVersion\("(?&lt;Major&gt;\d+)\.(?&lt;Minor&gt;\d+)\.(?&lt;Patch&gt;[\d]+)(?&lt;PreReleaseInfo&gt;[0-9A-Za-z-.]+)?</Pattern>
    <AssemblyVersionMajor>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups["Major"].Value)</AssemblyVersionMajor>
    <AssemblyVersionMinor>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups["Minor"].Value)</AssemblyVersionMinor>
    <AssemblyVersionPatch>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups["Patch"].Value)</AssemblyVersionPatch>
    <AssemblyVersionPreRelease>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups["PreReleaseInfo"].Value)</AssemblyVersionPreRelease>
</PropertyGroup>

You can test the output of this operation by adding the following to your .csproj:

  <Target Name="AfterBuild">
    <Message Text="$(AssemblyVersionMajor)"></Message>
    <Message Text="$(AssemblyVersionMinor)"></Message>
    <Message Text="$(AssemblyVersionPatch)"></Message>
    <Message Text="$(AssemblyVersionPreRelease)"></Message>
</Target>

Ex: Snippet from my AssemblyInfo.cs:

[assembly: AssemblyInformationalVersion("0.9.1-beta")]

Will output: Major: '0', Minor: '9', Patch: '1', PreRelease: '-beta'

Emil G
  • 1,211
  • 1
  • 14
  • 26
11

Building on Alex's answer, I used RegEx to read the AssemblyVersion (and other information) and use that in my WiX/MSI filename and version strings. Hopefully my answer isn't too noisy.

Here is the top of my .wixproj file. Points of interest are the first PropertyGroup, OutputName, and DefineConstants:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup>
        <In>$([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\..\MyApplication\Properties\AssemblyInfoCommon.cs'))</In>
        <Pattern>^\s*\[assembly: AssemblyVersion\(\D*(\d+)\.(\d+)\.(\d+)</Pattern>
        <AssemblyVersionMajor>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[1].Value)</AssemblyVersionMajor>
        <AssemblyVersionMinor>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[2].Value)</AssemblyVersionMinor>
        <AssemblyVersionBuild>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[3].Value)</AssemblyVersionBuild>
        <Pattern>^\s*\[assembly: AssemblyDescription\(\s*"([^"]+)"</Pattern>
        <AssemblyDescription>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[1].Value)</AssemblyDescription>
        <Pattern>^\s*\[assembly: AssemblyProduct\(\s*"([^"]+)"</Pattern>
        <AssemblyProduct>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[1].Value)</AssemblyProduct>
        <Pattern>^\s*\[assembly: AssemblyCompany\(\s*"([^"]+)"</Pattern>
        <AssemblyCompany>$([System.Text.RegularExpressions.Regex]::Match($(In), $(Pattern), System.Text.RegularExpressions.RegexOptions.Multiline).Groups[1].Value)</AssemblyCompany>
    </PropertyGroup>
    <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
        <ProductVersion>3.7</ProductVersion>
        <ProjectGuid>MYGUID00-840B-4055-8251-F2B83BC5DBB9</ProjectGuid>
        <SchemaVersion>2.0</SchemaVersion>
        <OutputName>$(AssemblyProduct)-$(AssemblyVersionMajor).$(AssemblyVersionMinor).$(AssemblyVersionBuild)</OutputName>
        <OutputType>Package</OutputType>
        <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
        <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
        <OutputPath>bin\$(Configuration)\</OutputPath>
        <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
        <DefineConstants>Debug;AssemblyVersionMajor=$(AssemblyVersionMajor);AssemblyVersionMinor=$(AssemblyVersionMinor);AssemblyVersionBuild=$(AssemblyVersionBuild);AssemblyDescription=$(AssemblyDescription);AssemblyProduct=$(AssemblyProduct);AssemblyCompany=$(AssemblyCompany)</DefineConstants>
        <SuppressValidation>False</SuppressValidation>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
        <OutputPath>bin\$(Configuration)\</OutputPath>
        <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
        <DefineConstants>AssemblyVersionMajor=$(AssemblyVersionMajor);AssemblyVersionMinor=$(AssemblyVersionMinor);AssemblyVersionBuild=$(AssemblyVersionBuild);AssemblyDescription=$(AssemblyDescription);AssemblyProduct=$(AssemblyProduct);AssemblyCompany=$(AssemblyCompany)</DefineConstants>
    </PropertyGroup>

And then in a .wxi file I have this:

<?define MajorVersion="$(var.AssemblyVersionMajor)" ?>
<?define MinorVersion="$(var.AssemblyVersionMinor)" ?>
<?define BuildVersion="$(var.AssemblyVersionBuild)" ?>
<?define VersionNumber="$(var.MajorVersion).$(var.MinorVersion).$(var.BuildVersion)" ?>

And finally in my Product.wxs:

<?include Definitions.wxi ?>
<Product Id="$(var.GuidProduct)" Name="$(var.AssemblyProduct) $(var.VersionNumber)" Language="!(loc.LANG)"
         Version="$(var.VersionNumber)" Manufacturer="$(var.AssemblyCompany)" UpgradeCode="$(var.GuidUpgrade)">
    <Package Id="$(var.GuidPackage)" InstallerVersion="301" Compressed="yes" InstallScope="perMachine"
             Keywords="!(loc.Keywords)" Description="$(var.AssemblyProduct)" Comments="$(var.AssemblyDescription)" />
Robpol86
  • 1,594
  • 21
  • 18
2

If you want to be able to process your AssemblyInfo file with 100% accuracy you can use a C# task + Roslyn.

public class ReadAssemblyInfo : Task {
    [Required]
    public string AssemblyInfoFilePath { get; set; }

    [Output]
    public TaskItem AssemblyVersion { get; set; }

    [Output]
    public TaskItem AssemblyInformationalVersion { get; set; }

    [Output]
    public TaskItem AssemblyFileVersion { get; set; }

    public override bool Execute() {
        using (var reader = new StreamReader(AssemblyInfoFilePath)) {
            var text = reader.ReadToEnd();

            var tree = CSharpSyntaxTree.ParseText(text);
            var root = (CompilationUnitSyntax)tree.GetRoot();

            var attributeLists = root.DescendantNodes().OfType<AttributeListSyntax>();
            foreach (var p in attributeLists) {
                foreach (var attribute in p.Attributes) {
                    var identifier = attribute.Name as IdentifierNameSyntax;
                    
                    if (identifier != null) {
                        var value = ParseAttribute("AssemblyInformationalVersion", identifier, attribute);
                        if (value != null) {
                            SetMetadata(AssemblyInformationalVersion = new TaskItem(value.ToString()), value);
                            break;
                        }

                        value = ParseAttribute("AssemblyVersion", identifier, attribute);
                        if (value != null) {
                            SetMetadata(AssemblyVersion = new TaskItem(value.ToString()), value);
                            break;
                        }

                        value = ParseAttribute("AssemblyFileVersion", identifier, attribute);
                        if (value != null) {
                            SetMetadata(AssemblyFileVersion = new TaskItem(value.ToString()), value);
                            break;
                        }
                    }
                }
            }
        }

        return !Log.HasLoggedErrors;
    }

    private void SetMetadata(TaskItem taskItem, Version version) {
        taskItem.SetMetadata(nameof(version.Major), version.Major.ToString());
        taskItem.SetMetadata(nameof(version.Minor), version.Minor.ToString());
        taskItem.SetMetadata(nameof(version.Build), version.Build.ToString());
        taskItem.SetMetadata(nameof(version.Revision), version.Revision.ToString());
    }

    private static Version ParseAttribute(string attributeName, IdentifierNameSyntax identifier, AttributeSyntax attribute) {
        if (identifier.Identifier.Text.IndexOf(attributeName, StringComparison.Ordinal) >= 0) {
            AttributeArgumentSyntax listArgument = attribute.ArgumentList.Arguments[0];

            var rawText = listArgument.Expression.GetText().ToString();
            if (!string.IsNullOrWhiteSpace(rawText)) {
                rawText = rawText.Replace("\"", "");
                Version version;
                if (Version.TryParse(rawText, out version)) {
                    return version;
                }
            }
        }
        return null;
    }
}
Horizon
  • 81
  • 5
Michael Baker
  • 3,338
  • 26
  • 29
1

I just found this on google, might help:

http://msdn.microsoft.com/en-us/library/system.reflection.assemblyname.version%28v=VS.90%29.aspx

Particularly:

//For AssemblyFileVersion
Assembly asm = Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(asm.Location);
string version = fvi.FileVersion
//For AssemblyVersion
string revision = Assembly.GetExecutingAssembly().GetName().Version.Revision;
lanoxx
  • 12,249
  • 13
  • 87
  • 142
0

You can use MSBuild.Community.Tasks.AssemblyInfo.AssemblyVersion to access AssemblyVersion and AssemblyFileVersion from AssemblyInfo.cs.

Indeed this task can only be used to set the version.

Maybe this post is usefull.

Community
  • 1
  • 1
Filburt
  • 17,626
  • 12
  • 64
  • 115
  • 1
    thanx filburt, but this task is not been used for reading the assemblyversion or assemblyfileversion. It can only overwrite them by the property. – Divya mohan Singh Jan 12 '10 at 06:49
  • Maybe this might help: http://weblogs.asp.net/dmckinstry/archive/2007/02/06/poor-man-s-assemblyinfo-check-in-msbuild.aspx – Filburt Jan 12 '10 at 07:56
0

I use the RegexMatch-task from the MSBuild.Community.Tasks.

You can write the output of the match to an itemgroup, although you want to read it into 3 properties, as above, a custom task would then be prefered.

Bart Janson
  • 233
  • 3
  • 9
-3

The only solution is to write a custom build task, and parse the version number manually in the code.

Gerrie Schenck
  • 22,148
  • 20
  • 68
  • 95
  • Isn't there any other solution .?? which i can done with regular expression?? or if there is any Task for it?? – Divya mohan Singh Jan 11 '10 at 14:22
  • Well I've written my own task for it and I've used simple string methods to parse the version number but I'm sure you can do it with regex too. But you'll have to write your own task for this anyway, unless you find an out-of-the-box solution. – Gerrie Schenck Jan 11 '10 at 14:32