示例#1
0
        /// <summary>
        /// Validates that a task's outputs are sane. If so, predicts output directories.
        /// </summary>
        /// <param name="projectFullPath">The absolute path to the project instance. Can be null if the project was not loaded
        /// from this</param>
        /// <param name="inputs">The inputs specified in SourceFiles on a copy task.</param>
        /// <param name="outputs">
        /// The outputs specified in the DestinationFolder or DestinationFiles attribute on a copy task.
        /// </param>
        /// <param name="copyTaskSpecifiesDestinationFolder">True if the user has specified DestinationFolder.</param>
        /// <param name="buildOutputDirectories">Collection to fill with output folder predictions.</param>
        private static void ProcessOutputs(
            string projectFullPath,
            FileExpressionList inputs,
            FileExpressionList outputs,
            bool copyTaskSpecifiesDestinationFolder,
            HashSet <string> buildOutputDirectories)
        {
            for (int i = 0; i < inputs.DedupedFiles.Count; i++)
            {
                string predictedOutputDirectory;

                // If the user specified a destination folder, they could have specified an expression that evaluates to
                // either exactly one or N folders. We need to handle each case.
                if (copyTaskSpecifiesDestinationFolder)
                {
                    if (outputs.DedupedFiles.Count == 0)
                    {
                        // Output files couldn't be parsed, bail out.
                        break;
                    }

                    // If output directories isn't 1 or N, bail out.
                    if (inputs.DedupedFiles.Count != outputs.DedupedFiles.Count && outputs.DedupedFiles.Count > 1)
                    {
                        break;
                    }

                    predictedOutputDirectory = outputs.DedupedFiles.Count == 1 ? outputs.DedupedFiles[0] : outputs.DedupedFiles[i];
                }
                else
                {
                    if (i >= outputs.DedupedFiles.Count)
                    {
                        break;
                    }

                    // The output list is a set of files. Predict their directories.
                    predictedOutputDirectory = Path.GetDirectoryName(outputs.DedupedFiles[i]);
                }

                // If the predicted directory is not absolute, let's try to make it absolute using the project full path
                if (!TryMakePathAbsoluteIfNeeded(predictedOutputDirectory, projectFullPath, out string absolutePathPrediction))
                {
                    // The project full path is not available, so just ignore this prediction
                    continue;
                }

                buildOutputDirectories.Add(absolutePathPrediction);
            }
        }
示例#2
0
        /// <summary>
        /// Parses the input and output files for copy tasks of given target.
        /// </summary>
        private static void ParseCopyTask(
            ProjectTargetInstance target,
            ProjectInstance projectInstance,
            HashSet <BuildInput> buildInputs,
            HashSet <string> buildOutputDirectories)
        {
            // Get all Copy tasks from targets.
            List <ProjectTaskInstance> tasks = target.Tasks
                                               .Where(task => string.Equals(task.Name, CopyTaskName, StringComparison.Ordinal))
                                               .ToList();

            if (tasks.Any() && projectInstance.EvaluateConditionCarefully(target.Condition))
            {
                foreach (ProjectTaskInstance task in tasks)
                {
                    if (projectInstance.EvaluateConditionCarefully(task.Condition))
                    {
                        var inputs = new FileExpressionList(
                            task.Parameters[CopyTaskSourceFiles],
                            projectInstance,
                            task);
                        if (inputs.Expressions.Count == 0)
                        {
                            continue;
                        }

                        buildInputs.UnionWith(inputs.DedupedFiles.
                                              Select(file => new BuildInput(Path.Combine(projectInstance.Directory, file), false)));

                        bool hasDestinationFolder = task.Parameters.TryGetValue(
                            CopyTaskDestinationFolder,
                            out string destinationFolder);
                        bool hasDestinationFiles = task.Parameters.TryGetValue(
                            CopyTaskDestinationFiles,
                            out string destinationFiles);

                        if (hasDestinationFiles || hasDestinationFolder)
                        {
                            // Having both is an MSBuild violation, which it will complain about.
                            if (hasDestinationFolder && hasDestinationFiles)
                            {
                                continue;
                            }

                            string destination = destinationFolder ?? destinationFiles;

                            var outputs = new FileExpressionList(destination, projectInstance, task);

                            // When using batch tokens, the user should specify exactly one total token, and it must appear in both the input and output.
                            // Doing otherwise should be a BuildCop error. If not using batch tokens, then any number of other tokens is fine.
                            if ((outputs.NumBatchExpressions == 1 && outputs.Expressions.Count == 1 &&
                                 inputs.NumBatchExpressions == 1 && inputs.Expressions.Count == 1) ||
                                (outputs.NumBatchExpressions == 0 && inputs.NumBatchExpressions == 0))
                            {
                                ProcessOutputs(projectInstance.FullPath, inputs, outputs, hasDestinationFolder, buildOutputDirectories);
                            }
                            else
                            {
                                // Ignore case we cannot handle.
                            }
                        }
                        else
                        {
                            // Ignore malformed case.
                        }
                    }
                }
            }
        }