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
    }
}

Reply via email to