using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Xml; using JetBrains.Annotations; using JetBrains.Util; namespace JetBrains.Platform.PowerShell.Infra.TeamCity { /// /// While running within a TeamCity build, we have three sets of properties available: /// (1) Environment. These are available thru the process environment block. /// (2) System. There's a pointer to the properties file in one of the environment variables. /// (3) Configuration.There's a pointer to the properties file in one of the system properties (see the chain?). /// public class TeamCityProperties { #region Data private IDictionary myConfigurationProperties; private IDictionary mySystemProperties; #endregion #region Attributes public readonly bool IsRunningInTeamCity = !TryGetSystemPropertiesFilePath().IsNullOrEmpty(); #endregion #region Operations [NotNull] public string GetConfigurationProperty([NotNull] string name) { if(name == null) throw new ArgumentNullException("name"); AssertIsRunningInTeamCity(); TryLoadConfigurationPropertiesFile(); return myConfigurationProperties.GetValue(name, string.Format("The configuration property {0} is not defined.", name.QuoteIfNeeded())); } [NotNull] public string GetSystemProperty([NotNull] string name) { if(name == null) throw new ArgumentNullException("name"); name = Regex.Replace(name, @"^system\.", "", RegexOptions.IgnoreCase); // Props are listed without the "system." prefix in the file AssertIsRunningInTeamCity(); TryLoadSystemPropertiesFile(); return mySystemProperties.GetValue(name, string.Format("The system property {0} is not defined.", name.QuoteIfNeeded())); } [CanBeNull] public string TryGetConfigurationProperty([NotNull] string name) { if(name == null) throw new ArgumentNullException("name"); TryLoadConfigurationPropertiesFile(); return myConfigurationProperties != null ? myConfigurationProperties.TryGetValue(name) : null; } [CanBeNull] public string TryGetSystemProperty([NotNull] string name) { if(name == null) throw new ArgumentNullException("name"); name = Regex.Replace(name, @"^system\.", "", RegexOptions.IgnoreCase); // Props are listed without the "system." prefix in the file TryLoadSystemPropertiesFile(); return mySystemProperties != null ? mySystemProperties.TryGetValue(name) : null; } #endregion #region Implementation [NotNull] private static IDictionary ReadJavaPropertiesXml([NotNull] FileSystemPath pathFile) { if(pathFile == null) throw new ArgumentNullException("pathFile"); var xmlDoc = new XmlDocument(); pathFile.ReadStream(xmlDoc.Load); return xmlDoc.SelectElements("//entry").ToDictionary(xmlEntry => xmlEntry.GetAttribute("key"), xmlEntry => xmlEntry.InnerText); } [NotNull] private static FileSystemPath TryGetSystemPropertiesFilePath() { FileSystemPath path = FileSystemPath.TryParse(Environment.GetEnvironmentVariable("TEAMCITY_BUILD_PROPERTIES_FILE")); if(path.IsEmpty) return FileSystemPath.Empty; // Switch to an XML representation of the properties file path = new FileSystemPath(path.FullPath + ".xml"); return path.ExistsFile ? path : FileSystemPath.Empty; } private void AssertIsRunningInTeamCity() { if(!IsRunningInTeamCity) throw new InvalidOperationException("This code is not currently running within a TeamCity build agent process."); } private void TryLoadConfigurationPropertiesFile() { if(!IsRunningInTeamCity) return; if(myConfigurationProperties != null) return; var pathFile = new FileSystemPath(GetSystemProperty("teamcity.configuration.properties.file") + ".xml"); if(!pathFile.ExistsFile) return; myConfigurationProperties = ReadJavaPropertiesXml(pathFile); } private void TryLoadSystemPropertiesFile() { if(!IsRunningInTeamCity) return; if(mySystemProperties != null) return; FileSystemPath pathFile = TryGetSystemPropertiesFilePath(); if(!pathFile.ExistsFile) return; mySystemProperties = ReadJavaPropertiesXml(pathFile); } #endregion } }