Hi Jason,
I've attached a modified version of the <version> task, which contains part
of your changes but uses enums for BuildType and RevisionType (making it a
breaking change).
Let me know if you think its ok.
Gert
> -----Original Message-----
> From: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] On
> Behalf Of Morris, Jason
> Sent: donderdag 30 december 2004 7:39
> To: [email protected]
> Subject: RE: [nant-dev] Request for version task patch be
> committed (#1083618)
>
> Has any committers had a chance to look at this yet? Is
> there something
> wrong that is preventing the patch to be committed. If so, please let
> me know so that I can correct them. I would really like the
> changes to
> be in the .85 release of nant/nantcontrib.
>
> Jason
>
> >-----Original Message-----
> >From: [EMAIL PROTECTED]
> >[mailto:[EMAIL PROTECTED] On Behalf
> >Of Morris, Jason
> >Sent: Monday, December 20, 2004 8:25 AM
> >To: [email protected]
> >Subject: RE: [nant-dev] Request for version task patch be
> >committed (#1083618)
> >
> >Nant or nantcontrib developers,
> >
> >I know that recent work is focused on getting .85 out the
> >door, but if anyone could commit this patch, I would be much
> >appreciated. I know that it isn't much of a patch.
> >
> >Also, the patch was submitted to the nant patches instead of
> >the nantcontrib patches...sorry.
> >
> >Jason
> >
> >>-----Original Message-----
> >>From: [EMAIL PROTECTED]
> >>[mailto:[EMAIL PROTECTED] On Behalf Of
> >>Morris, Jason
> >>Sent: Saturday, December 11, 2004 3:24 PM
> >>To: [email protected]
> >>Subject: [nant-dev] Request for version task patch be committed
> >>(#1083618)
> >>
> >>Nant committers,
> >>
> >>I would like my patch (#1083618) that I submitted for the
> NAntContrib
> >><version> task be applied before the 0.85 release.
> >> I mistakenly submitted the patch to the Nant patch tracker
> >instead of
> >>the NAntContrib patch tracker.
> >>
> >>The patch was to correct confusion that I and others on the mailing
> >>list had with figuring out how to use the task. I hope that this
> >>improves things. Also, the patch contains the following changes:
> >>
> >>* Improved in-code documentation to avoid confusion that has been
> >>expressed on the mailing list.
> >>* Refactored code to remove duplication and make design simple
> >>* Added several new properties
> >> - Prefix.Major
> >> - Prefix.Minor
> >> - Prefix.Build
> >> - Prefix.Revision
> >>* Improve BuildType and RevisionType arguments
> >> - Parsing is more forgiving because values are now case
> >>insensitive.
> >> - const defined for each argument value (no more
> >duplicated string
> >>compares)
> >>* Added unit tests (separate patch)
> >>
> >>Patch was created by WinMerge which is GNU/diffutils
> compatible from
> >>version 0.85rc1 (cvs version 1.7)
> >>
> >>Please let me know if there is anything that you require before
> >>submitting this patch.
> >>
> >>Two other changes I would have made, but didn't since they
> would have
> >>introduced breaking changes. One, the path attribute should
> >be renamed
> >>to the filename as that is more appropriate description. Two,
> >startDate
> >>attribute might be renamed to startdate to maintain
> consistence with
> >>attribute naming convention.
> >>
> >>Thanks,
> >>Jason
> >>
> >>
> >>-------------------------------------------------------
> >>SF email is sponsored by - The IT Product Guide Read honest
> & candid
> >>reviews on hundreds of IT Products from real users.
> >>Discover which products truly live up to the hype. Start
> reading now.
> >>http://productguide.itmanagersjournal.com/
> >>_______________________________________________
> >>nant-developers mailing list
> >>[email protected]
> >>https://lists.sourceforge.net/lists/listinfo/nant-developers
> >>
> >
> >
> >-------------------------------------------------------
> >SF email is sponsored by - The IT Product Guide Read honest &
> >candid reviews on hundreds of IT Products from real users.
> >Discover which products truly live up to the hype. Start
> reading now.
> >http://productguide.itmanagersjournal.com/
> >_______________________________________________
> >nant-developers mailing list
> >[email protected]
> >https://lists.sourceforge.net/lists/listinfo/nant-developers
> >
>
>
> -------------------------------------------------------
> The SF.Net email is sponsored by: Beat the post-holiday blues
> Get a FREE limited edition SourceForge.net t-shirt from ThinkGeek.
> It's fun and FREE -- well, almost....http://www.thinkgeek.com/sfshirt
> _______________________________________________
> nant-developers mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/nant-developers
>
>
// NAnt - A .NET build tool
// Copyright (C) 2001-2002 Gerry Shaw
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// John Lam ([EMAIL PROTECTED])
using System;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Util;
namespace NAnt.Contrib.Tasks
{
/// <summary>
/// Increments a four-part version number stored in a text file. The
resulting
/// version number is written back to the file and exposed using NAnt
properties.
/// </summary>
/// <remarks>
/// <para>
/// The version number format in the text file is
/// Major.Minor.Build.Revision, e.g. 1.0.5.25.
/// </para>
/// <list type="table">
/// <item>Major</item><description>set in 'build.number'
file</description>
/// <item>Minor</item><description>set in 'build.number'
file</description>
/// <item>Build</item><description>can be incremented by setting the
<see cref="BuildType" /> parameter</description>
/// <item>Revision</item><description>can be incremented by setting the
<see cref="RevisionType" /> parameter</description>
/// </list>
/// <para>The following NAnt properties are created:</para>
/// <list type="table">
/// <item><c>prefix</c>.version</item><description>complete version
number, i.e. Major.Minor.Build.Revision</description>
/// <item><c>prefix</c>.major</item><description></description>
/// <item><c>prefix</c>.minor</item><description></description>
/// <item><c>prefix</c>.build</item><description></description>
/// <item><c>prefix</c>.revision</item><description></description>
/// </list>
/// </remarks>
[TaskName("version")]
public class VersionTask : Task {
/// <summary>
/// Defines possible algoritms to generate the build number.
/// </summary>
public enum BuildNumberAlgoritm {
/// <summary>
/// Use the number of months since start of project * 100 + current
/// day in month as build number.
/// </summary>
MonthDay,
/// <summary>
/// Increment an existing build number.
/// </summary>
Increment,
/// <summary>
/// Use an existing build number (and do not increment it).
/// </summary>
NoIncrement
}
/// <summary>
/// Defines possible algoritms to generate the revision number.
/// </summary>
public enum RevisionNumberAlgoritm {
/// <summary>
/// Use the number of seconds since the start of today / 10.
/// </summary>
Automatic,
/// <summary>
/// Increment an existing revision number.
/// </summary>
Increment
}
#region Private Instance Fields
private string _prefix = "buildnumber";
private BuildNumberAlgoritm _buildType = BuildNumberAlgoritm.MonthDay;
private RevisionNumberAlgoritm _revisionType =
RevisionNumberAlgoritm.Automatic;
private FileInfo _path;
private DateTime _startDate;
#endregion Private Instance Fields
#region Public Instance Properties
/// <summary>
/// The string to prefix the properties with. The default is
/// <c>'buildnumber.'</c>.
/// </summary>
[TaskAttribute("prefix")]
[StringValidator(AllowEmpty=false)]
public string Prefix {
get { return _prefix; }
set { _prefix = StringUtils.ConvertEmptyToNull(value); }
}
/// <summary>
/// Start of project. Date from which to calculate build number.
/// Required if <see cref="BuildNumberAlgoritm.MonthDay" /> is used as
/// <see cref="BuildType" />.
/// </summary>
[TaskAttribute("startdate")]
public DateTime StartDate {
get { return _startDate; }
set { _startDate = value; }
}
/// <summary>
/// Path to the file containing the current version number. The default
/// file is <c>'build.number'</c> in the project base directory.
/// </summary>
[TaskAttribute("path")]
public FileInfo Path {
get {
if (_path == null) {
_path = new FileInfo(Project.GetFullPath("build.number"));
}
return _path;
}
set { _path = value; }
}
/// <summary>
/// The algorithm for generating build number. The default is
/// <see cref="BuildNumberAlgoritm.MonthDay" />.
/// </summary>
[TaskAttribute("buildtype")]
public BuildNumberAlgoritm BuildType {
get { return _buildType; }
set { _buildType = value; }
}
/// <summary>
/// The algorithm for generating revision number. The default is
/// <see cref="RevisionNumberAlgoritm.Automatic" />.
/// </summary>
[TaskAttribute("revisiontype")]
public RevisionNumberAlgoritm RevisionType {
get { return _revisionType; }
set { _revisionType = value; }
}
#endregion Public Instance Properties
#region Override implementation of Task
protected override void ExecuteTask() {
Version version = CalculateVersion();
Project.Properties[Prefix + ".version"] = version.ToString();
Project.Properties[Prefix + ".major"] = version.Major.ToString();
Project.Properties[Prefix + ".minor"] = version.Minor.ToString();
Project.Properties[Prefix + ".build"] = version.Build.ToString();
Project.Properties[Prefix + ".revision"] =
version.Revision.ToString();
// write version back to file
WriteVersionToFile(version);
Log(Level.Info, "Build number '{0}'.", version.ToString());
}
#endregion Override implementation of Task
#region Private Instance Methods
/// <summary>
/// Reads a version string from <see cref="Path" /> and returns it as a
/// <see cref="Version" /> instance.
/// </summary>
/// <returns>
/// A <see cref="Version" /> instance representing the version string in
/// <see cref="Path" />.
/// </returns>
private Version ReadVersionFromFile() {
string version = null;
// read the version string
try {
using (StreamReader reader = new StreamReader(Path.FullName)) {
version = reader.ReadToEnd();
}
} catch (Exception ex) {
throw new
BuildException(string.Format(CultureInfo.InvariantCulture,
"Unable to read version number from \"{0}\".",
Path.FullName),
Location, ex);
}
// instantiate a Version instance from the version string
try {
return new Version(version);
} catch (Exception ex) {
throw new
BuildException(string.Format(CultureInfo.InvariantCulture,
"Invalid version string \"{0}\" in file \"{1}\".", version,
Path), Location, ex);
}
}
/// <summary>
/// Writes the specified version to <see cref="Path" />.
/// </summary>
/// <param name="version">The version to write to <see cref="Path"
/>.</param>
private void WriteVersionToFile(Version version) {
try {
using (StreamWriter writer = new StreamWriter(Path.FullName)) {
writer.Write(version.ToString());
}
} catch (Exception ex) {
throw new
BuildException(string.Format(CultureInfo.InvariantCulture,
"Unable to write version number to \"{0}\".",
Path.FullName),
Location, ex);
}
}
/// <summary>
/// Calculates the build number based on the number of months since the
/// start date.
/// </summary>
/// <returns>
/// The build number based on the number of months since the start date.
/// </returns>
private int CalculateMonthDayBuildNumber() {
// we need to have a start date defined!
if (StartDate == DateTime.MinValue) {
throw new BuildException("\"startdate\" must be set when the"
+ "\"MonthDay\" algorithm is used.", Location);
}
DateTime today = DateTime.Now;
if (StartDate > today) {
throw new BuildException("Start date cannot be in the future.",
Location);
}
// Calculate difference in years
int years = today.Year - StartDate.Year;
// Calculate difference in months
int months;
if (today.Month < StartDate.Month) {
--years; // borrow from years
months = (today.Month + 12) - StartDate.Month;
} else {
months = today.Month - StartDate.Month;
}
months += years * 12;
// The days is simply today's day
int days = today.Day;
return months * 100 + days;
}
/// <summary>
/// Calculates the number of seconds since midnight.
/// start date.
/// </summary>
/// <returns>
/// The number of seconds since midnight.
/// </returns>
private int CalculateSecondsSinceMidnight() {
DateTime today = DateTime.Now;
return (today.Hour * 3600 + today.Minute * 60 + today.Second) / 10;
}
/// <summary>
/// Calculates the build number of the version number based on
/// <see cref="BuildType" />.
/// </summary>
/// <returns>
/// The build number.
/// </returns>
private int CalculateBuildNumber(int currentBuildNumber) {
switch (BuildType) {
case BuildNumberAlgoritm.MonthDay:
return CalculateMonthDayBuildNumber();
case BuildNumberAlgoritm.Increment:
return currentBuildNumber + 1;
case BuildNumberAlgoritm.NoIncrement:
return currentBuildNumber;
default:
throw new InvalidEnumArgumentException("BuildType",
(int) BuildType, typeof(BuildNumberAlgoritm));
}
}
/// <summary>
/// Calculates the complete version.
/// </summary>
/// <returns>
/// The version.
/// </returns>
private Version CalculateVersion() {
Version version = ReadVersionFromFile();
int newBuildNumber = CalculateBuildNumber(version.Build);
int newRevisionNumber = CalculateRevisionNumber(version,
newBuildNumber);
return new Version(version.Major, version.Minor, newBuildNumber,
newRevisionNumber);
}
/// <summary>
/// Calculates the revision number of the version number based on
RevisionType specified
/// </summary>
/// <returns>
/// The revision number.
/// </returns>
private int CalculateRevisionNumber(Version version, int
newBuildNumber) {
int newRevsionNumber;
// modify revision number according to revision type setting
switch (RevisionType) {
case RevisionNumberAlgoritm.Automatic:
newRevsionNumber = CalculateSecondsSinceMidnight();
break;
case RevisionNumberAlgoritm.Increment:
if (newBuildNumber != version.Build) {
// reset revision number to zero if the build number
// has changed
newRevsionNumber = 0;
} else {
// increment the revision number if this is a revision
// of the same build
newRevsionNumber = version.Revision + 1;
}
break;
default:
throw new InvalidEnumArgumentException("RevisionType",
(int) RevisionType, typeof(RevisionNumberAlgoritm));
}
return newRevsionNumber;
}
#endregion Private Instance Methods
}
}