/// <summary> /// Splits a PATH (with ; or : as separators) into its parts, while /// resolving references to environment variables. /// </summary> /// <param name="project">The <see cref="Project" /> to be used to resolve relative paths.</param> /// <param name="source">The path to translate.</param> /// <param name="logger">The logger.</param> /// <returns> /// A PATH split up its parts, with references to environment variables /// resolved and duplicate entries removed. /// </returns> public static StringCollection TranslatePath(Project project, string source, ITargetLogger logger) { StringCollection result = new StringCollection(); if (source == null) { return(result); } string[] parts = source.Split(':', ';'); for (int i = 0; i < parts.Length; i++) { string part = parts[i]; // on a DOS filesystem, the ':' character might be part of a // drive spec and in that case we need to combine the current // and the next part if (part.Length == 1 && Char.IsLetter(part[0]) && _dosBasedFileSystem && (parts.Length > i + 1)) { string nextPart = parts[i + 1].Trim(); if (nextPart.StartsWith("\\") || nextPart.StartsWith("/")) { part += ":" + nextPart; // skip the next part as we've also processed it i++; } } // expand env variables in part string expandedPart = Environment.ExpandEnvironmentVariables(part); // check if part is a reference to an environment variable // that could not be expanded (does not exist) if (expandedPart.StartsWith("%") && expandedPart.EndsWith("%")) { continue; } // resolve each part in the expanded environment variable to a // full path foreach (string path in expandedPart.Split(Path.PathSeparator)) { try { string absolutePath = project.GetFullPath(path); if (!result.Contains(absolutePath)) { result.Add(absolutePath); } } catch (Exception ex) { logger.Log(Level.Verbose, "Dropping path element '{0}'" + " as it could not be resolved to a full path. {1}", path, ex.Message); } } } return(result); }
/// <summary> /// Pushes a new target frame onto this stack /// </summary> /// <param name="target">The target to push</param> /// <param name="logger">The logger that tasks on this frame shoudl use, if different than the current one</param> /// <returns>An <see cref="IDisposable"/> that, when disposed, pops the frame from the stack</returns> public IDisposable Push(Target target, ITargetLogger logger = null) { if (target == null) { throw new ArgumentNullException("target"); } return(this.PushNewFrame( new TargetStackFrame(target, this.Project, logger ?? this.CurrentFrame.Logger))); }
/// <summary> /// Creates a new frame /// </summary> /// <param name="target">The new target</param> /// <param name="project">The project</param> /// <param name="logger">The logger to be used</param> internal TargetStackFrame( Target target, Project project, ITargetLogger logger) { this.Target = target; this.TargetProperties = new PropertyDictionary(project, PropertyScope.Target); this.TaskCallStack = new TaskCallStack(project); this.Logger = logger; }
/// <summary> /// Executes this target, after acquiring any necessary locks. /// </summary> /// <param name="callStack">The current call stack on which this target will be pused</param> /// <param name="logger">The logger this target and its stasks will use for logging messages</param> /// <param name="arguments">Optionally, the arguments to provide to the target. Should match those required by <see cref="Parameters"/></param> /// <exception cref="ArgumentException">If one of the non-defaulted parameters is not satisfied by an argument.</exception> public void Execute(TargetCallStack callStack, ITargetLogger logger, IList <CallArgument> arguments = null) { if (this.Locked) { lock (this) { this.DoExecute(callStack, logger, arguments); } } else { this.DoExecute(callStack, logger, arguments); } }
/// <summary> /// Invoked by <see cref="Element.AttributeConfigurator" /> for build /// attributes with an underlying <see cref="PathSet" /> type. /// </summary> /// <param name="project">The <see cref="Project" /> to be used to resolve relative paths.</param> /// <param name="path">The string representing a path.</param> /// <param name="logger">The logger.</param> public PathSet(Project project, string path, ITargetLogger logger) { base.Project = project; _translatedElements = PathSet.TranslatePath(project, path, logger); }
/// <summary> /// Executes this target /// </summary> /// <param name="callStack">The current call stack on which this target will be pused</param> /// <param name="logger">The logger this target and its stasks will use for logging messages</param> /// <param name="arguments">Optionally, the arguments to provide to the target. Should match those required by <see cref="Parameters"/></param> /// <exception cref="ArgumentException">If one of the non-defaulted parameters is not satisfied by an argument.</exception> private void DoExecute(TargetCallStack callStack, ITargetLogger logger, IList <CallArgument> arguments = null) { var propertyAccessor = new PropertyAccessor(this.Project, callStack); var sw = Stopwatch.StartNew(); if (IfDefined(propertyAccessor) && !UnlessDefined(propertyAccessor)) { try { using (callStack.Push(this, logger)) { this.PrepareArguments(arguments, callStack); Project.OnTargetStarted(this, new TargetBuildEventArgs(this, sw)); logger.OnTargetLoggingStarted(this, new TargetBuildEventArgs(this, sw)); var paramtersDone = false; // select all the task nodes and execute them foreach (XmlNode childNode in XmlNode) { if (!(childNode.NodeType == XmlNodeType.Element) || !childNode.NamespaceURI.Equals(NamespaceManager.LookupNamespace("nant"))) { continue; } if (childNode.Name.Equals("parameters")) { if (paramtersDone) { throw new BuildException("parameters must appear before all tasks", this.Location); } continue; } else { paramtersDone = true; if (TypeFactory.TaskBuilders.Contains(childNode.Name)) { Task task = Project.CreateTask(childNode, this, callStack); if (task != null) { task.Execute(); } } else if (TypeFactory.DataTypeBuilders.Contains(childNode.Name)) { DataTypeBase dataType = Project.CreateDataTypeBase(childNode, callStack); logger.Log(Level.Verbose, "Adding a {0} reference with id '{1}'.", childNode.Name, dataType.ID); if (!Project.DataTypeReferences.Contains(dataType.ID)) { Project.DataTypeReferences.Add(dataType.ID, dataType); } else { Project.DataTypeReferences[dataType.ID] = dataType; // overwrite with the new reference. } } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, ResourceUtils.GetString("NA1071"), childNode.Name), Project.LocationMap.GetLocation(childNode)); } } } } } finally { _executed = true; sw.Stop(); Project.OnTargetFinished(this, new TargetBuildEventArgs(this, sw)); logger.OnTargetLoggingFinished(this, new TargetBuildEventArgs(this, sw)); } } }
/// <summary> /// Creates a new <see cref="BufferingTargetLogger"/> /// </summary> /// <param name="destination">The destination logger that will be used when this logger is flushed</param> public BufferingTargetLogger(ITargetLogger destination) { this.DestinationLogger = destination; LoggerLocks.AddOrUpdate(destination, new object(), (key, old) => old); this.LoggingQueue = new ConcurrentQueue <Action>(); }