public virtual void Write(
			string targetPath,
			Branch branch,
			Dictionary<string, IEnumerable<Tag>> tags,
			Dictionary<string, IEnumerable<Branch>> branches,
			bool requireMetadataAttribute,
			DateTimeOffset generated,
			ICollection<Rule> ruleSet)
		{
			Debug.Assert(string.IsNullOrWhiteSpace(targetPath) == false);
			Debug.Assert(tags != null);
			Debug.Assert(branches != null);
			Debug.Assert(ruleSet != null);

			var unknownBranch = new UnknownBranch(generated);

			var altBranch = branch ?? unknownBranch;
			var commit = altBranch.Commits.First();

			using (var tw = File.CreateText(targetPath))
			{
				this.WriteComment(tw, "This is auto-generated version information attributes by CenterCLR.RelaxVersioner.{0}",
					this.GetType().Assembly.GetName().Version);
				this.WriteComment(tw, "Do not edit.");
				this.WriteComment(tw, "Generated date: {0:R}", generated);
				tw.WriteLine();

				this.WriteBeforeBody(tw, requireMetadataAttribute);

				var namespaces = Utilities.AggregateNamespacesFromRuleSet(ruleSet);
				foreach (var namespaceName in namespaces)
				{
					this.WriteImport(tw, namespaceName);
				}
				tw.WriteLine();

				var commitId = commit.Sha;
				var author = commit.Author;
				var committer = commit.Committer;

				var altBranches = string.Join(
					",",
					branches.GetValue(commitId, Enumerable.Empty<Branch>()).
						Select(b => b.Name));
				var altTags = string.Join(
					",",
					tags.GetValue(commitId, Enumerable.Empty<Tag>()).
						Select(b => b.Name));

				var safeVersion = Utilities.GetSafeVersionFromDate(committer.When);
				var gitLabel = Utilities.GetLabelWithFallback(altBranch, tags, branches) ?? safeVersion;

				var keyValues = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase)
				{
					{"generated", generated},
					{"branch", altBranch},
					{"branches", altBranches},
					{"tags", altTags},
					{"commit", commit},
					{"author", author},
					{"committer", committer},
					{"commitId", commitId},
					{"gitLabel", gitLabel},
					{"safeVersion", safeVersion}
				};

				foreach (var rule in ruleSet)
				{
					var formattedValue = Named.Format(rule.Format, keyValues);
					if (!string.IsNullOrWhiteSpace(rule.Key))
					{
						this.WriteAttributeWithArguments(tw, rule.Name, rule.Key, formattedValue);
					}
					else
					{
						this.WriteAttributeWithArguments(tw, rule.Name, formattedValue);
					}
				}
				tw.WriteLine();

				this.WriteAfterBody(tw, requireMetadataAttribute);

				tw.Flush();
			}
		}
        public virtual void Write(
            string targetPath,
            Branch branch,
            Dictionary <string, IEnumerable <Tag> > tags,
            Dictionary <string, IEnumerable <Branch> > branches,
            bool requireMetadataAttribute,
            DateTimeOffset generated,
            ICollection <Rule> ruleSet)
        {
            Debug.Assert(string.IsNullOrWhiteSpace(targetPath) == false);
            Debug.Assert(tags != null);
            Debug.Assert(branches != null);
            Debug.Assert(ruleSet != null);

            var unknownBranch = new UnknownBranch(generated);

            var altBranch = branch ?? unknownBranch;
            var commit    = altBranch.Commits.FirstOrDefault() ?? unknownBranch.Commits.First();

            var targetFolder = Path.GetDirectoryName(targetPath);

            if (Directory.Exists(targetFolder) == false)
            {
                try
                {
                    // Construct sub folders (ex: obj\Debug).
                    // May fail if parallel-building on MSBuild, ignoring exceptions.
                    Directory.CreateDirectory(targetFolder);
                }
                catch
                {
                }
            }

            using (var tw = File.CreateText(targetPath))
            {
                this.WriteComment(tw, "This is auto-generated version information attributes by CenterCLR.RelaxVersioner.{0}",
                                  this.GetType().Assembly.GetName().Version);
                this.WriteComment(tw, "Do not edit.");
                this.WriteComment(tw, "Generated date: {0:R}", generated);
                tw.WriteLine();

                this.WriteBeforeBody(tw, requireMetadataAttribute);

                var namespaces = Utilities.AggregateNamespacesFromRuleSet(ruleSet);
                foreach (var namespaceName in namespaces)
                {
                    this.WriteImport(tw, namespaceName);
                }
                tw.WriteLine();

                var commitId  = commit.Sha;
                var author    = commit.Author;
                var committer = commit.Committer;

                var altBranches = string.Join(
                    ",",
                    branches.GetValue(commitId, Enumerable.Empty <Branch>()).
                    Select(b => b.Name));
                var altTags = string.Join(
                    ",",
                    tags.GetValue(commitId, Enumerable.Empty <Tag>()).
                    Select(b => b.Name));

                var safeVersion = Utilities.GetSafeVersionFromDate(committer.When);
                var gitLabel    = Utilities.GetLabelWithFallback(altBranch, tags, branches) ?? safeVersion;

                var keyValues = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase)
                {
                    { "generated", generated },
                    { "branch", altBranch },
                    { "branches", altBranches },
                    { "tags", altTags },
                    { "commit", commit },
                    { "author", author },
                    { "committer", committer },
                    { "commitId", commitId },
                    { "gitLabel", gitLabel },
                    { "safeVersion", safeVersion }
                };

                foreach (var rule in ruleSet)
                {
                    var formattedValue = Named.Format(rule.Format, keyValues);
                    if (!string.IsNullOrWhiteSpace(rule.Key))
                    {
                        this.WriteAttributeWithArguments(tw, rule.Name, rule.Key, formattedValue);
                    }
                    else
                    {
                        this.WriteAttributeWithArguments(tw, rule.Name, formattedValue);
                    }
                }
                tw.WriteLine();

                this.WriteAfterBody(tw, requireMetadataAttribute);

                tw.Flush();
            }
        }