示例#1
0
        private async Task<ITargetDescription> _performCreateTargetDescription(PreflightResult result, ISource source, CancellationToken token, SelfAssemblyMode mode)
        {
            Debug.Assert(result.ErrorMessage == null, "TargetDescription ordered despite the preflight result containing errors.");
            Debug.Assert(result.References.All(r => r.ErrorMessage == null), "TargetDescription ordered despite the preflight result containing errors.");

            RefSpec[] refSpecs;
            switch (mode)
            {
                case SelfAssemblyMode.RecurseIntoFileSystem:
                    var refSpecResolveTasks =
                        result.References
                        .Select(r => _resolveRefSpec(r, token, mode))
                        .ToArray();
                    await Task.WhenAll(refSpecResolveTasks);
                    refSpecs = refSpecResolveTasks.Select(t => t.Result).ToArray();
                    break;
                case SelfAssemblyMode.RegisterOnly:
                    refSpecs = result.References.Select(_forbidFileRefSpec).ToArray();
                    break;
                default:
                    throw new ArgumentOutOfRangeException("mode", mode, Resources.SelfAssemblingPlan_performCreateTargetDescription_mode);
            }
            
            var buildMessages = refSpecs.Where(t => t.ErrorMessage != null).Select(
                    s =>
                    {
                        Debug.Assert(s.ErrorMessage != null);
                        // ReSharper disable PossibleNullReferenceException,AssignNullToNotNullAttribute
                        var refPosition = new SourcePosition(
                            s.ResolvedPath != null ? s.ResolvedPath.ToString() 
                          : result.Path != null    ? result.Path.ToString() 
                          : NoSourcePosition.MissingFileName, 0, 0);
                        return Message.Error(s.ErrorMessage, refPosition, MessageClasses.SelfAssembly);
                        // ReSharper restore PossibleNullReferenceException,AssignNullToNotNullAttribute
                    });

            // Assemble dependencies, including standard library (unless suppressed)
            var deps = refSpecs.Where(r => r.ModuleName != null).Select(r => r.ModuleName);
            if (!result.SuppressStandardLibrary)
                deps = deps.Append(StandardLibrary);

            var reportedFileName = 
                result.Path != null ? result.Path.ToString() 
                : result.ModuleName != null ? result.ModuleName.Id + ".pxs" 
                : null;

            // Typically, duplicate requests are caught much earlier (based on full file paths)
            // But if the user of this self assembling build plan manually adds descriptions
            // that can also be found on the file system, that conflict can in some situations
            // not be detected until full preflight is done.
            // This GetOrAdd is our last line of defense against that scenario and race conditions
            // around targets in general (e.g., when symbolic links or duplicate files are involved)
            return TargetDescriptions.GetOrAdd(result.ModuleName,
                mn => CreateDescription(mn, source, reportedFileName, deps, buildMessages));
        }
示例#2
0
        private async Task<RefSpec> _resolveRefSpec([NotNull] RefSpec refSpec, CancellationToken token, SelfAssemblyMode mode)
        // requires refSpec.ModuleName != null || refSpec.Source != null || refSpec.rawPath != null || refSpec.ResolvedPath != null
        // ensures result == refSpec && (TargetDescriptions.Contains(result) || refSpec.ErrorMessage != null)
        {
            if (refSpec.ErrorMessage != null)
                return refSpec;

            var pathCandidateCount = 0;
            IEnumerator<FileInfo> candidateSequence = null;
            var expectedModuleName = refSpec.ModuleName;
            try
            {
                while (refSpec.ModuleName == null || !TargetDescriptions.Contains(refSpec.ModuleName))
                {
                    if (candidateSequence == null)
                        candidateSequence = _pathCandidates(refSpec, token).GetEnumerator();

                    if (!candidateSequence.MoveNext())
                    {
                        var msg =
                            String.Format(
                                "Failed to find a file that matches the reference specification {0}. {1} path(s) searched.",
                                refSpec, pathCandidateCount);
                        _trace.TraceEvent(TraceEventType.Error, 0, msg);
                        refSpec.ErrorMessage = msg;
                        break;
                    }

                    var candidate = candidateSequence.Current;
                    pathCandidateCount++;

                    refSpec.ResolvedPath = candidate;
                    var result = await _orderPreflight(refSpec, token);

                    if (result.ErrorMessage != null)
                    {
                        _trace.TraceEvent(TraceEventType.Verbose, 0,
                            "Rejected {0} as a candidate for {1} because there were errors during preflight: {2}",
                            candidate, refSpec, result.ErrorMessage);
                    }
                    else if (result.ModuleName == null)
                    {
                        _trace.TraceEvent(TraceEventType.Information, 0,
                            "Rejected {0} as a candidate for {1} because its module name could not be inferred.",
                            candidate, refSpec);
                    }
                    else if (expectedModuleName != null
                        && !Engine.StringsAreEqual(result.ModuleName.Id, expectedModuleName.Id))
                    {
                        _trace.TraceEvent(TraceEventType.Warning, 0,
                            "Rejected {0} as a candidate for {1} because the module name in the file ({2}) doesn't match the module name expected by the reference.",
                            candidate, refSpec, result.ModuleName.Id);
                    }
                    else
                    {
                        refSpec.ModuleName = result.ModuleName;
                        _trace.TraceEvent(TraceEventType.Information, 0, "Accepted match {0} after preflight, ordering corresponding description.", result.ModuleName);
                        await _orderTargetDescription(result, candidate, token, mode);
                    }
                }
            }
            finally
            {
                if (candidateSequence != null)
                    candidateSequence.Dispose();
            }

            Debug.Assert(refSpec.ErrorMessage != null || TargetDescriptions.Contains(refSpec.ModuleName));
            return refSpec;
        }
示例#3
0
 private Task<ITargetDescription> _orderTargetDescription(PreflightResult result, FileInfo candidate, CancellationToken token, SelfAssemblyMode mode)
 {
     if (candidate == null)
         throw new ArgumentNullException("candidate");
     return _targetCreationCache.GetOrAdd(candidate.FullName,
         async (key, actualToken) =>
         {
             var src = Source.FromFile(candidate, Encoding);
             await Task.Yield();
             await _addToSearchPaths(candidate, actualToken);
             return await _performCreateTargetDescription(result, src, actualToken, mode);
         }, token);
 }
示例#4
0
        private async Task<ITargetDescription> _assembleAsync(ISource source, CancellationToken token, SelfAssemblyMode mode)
        {
            token.ThrowIfCancellationRequested();

            // Technically _orderPreflight would be better, but that only works with a resolved path as the key
            var primaryPreflight = await _performPreflight(new RefSpec {Source = source, ResolvedPath = _getPath(source)}, token);

            if (primaryPreflight.ErrorMessage != null)
            {
                var errorMessage = Message.Error(primaryPreflight.ErrorMessage, NoSourcePosition.Instance,
                    MessageClasses.SelfAssembly);

                if (primaryPreflight.ModuleName != null)
                {
                    return CreateDescription(primaryPreflight.ModuleName, Source.FromString(""),
                        NoSourcePosition.MissingFileName,
                        Enumerable.Empty<ModuleName>(),
                        new[] {errorMessage});
                }
                else
                {
                    throw new BuildFailureException(null, "There {2} {0} {1} while trying to determine dependencies.",
                        new[] {errorMessage});
                }
            }
            else
            {
                token.ThrowIfCancellationRequested();
                return await _performCreateTargetDescription(primaryPreflight, source, token, mode);
            }
        }