/// <inheritdoc cref="Script.DScriptInterpreterBase" /> public Task <Possible <ISourceFile> > TryParseAsync( AbsolutePath pathToParse, AbsolutePath moduleOrConfigPathPromptingParse, ParsingOptions parsingOptions = null) { return(Task.FromResult(Possible.Create((ISourceFile)GetOrCreateSourceFile(pathToParse)))); }
private async Task <Possible <Unit> > GenerateBuildDirectoryAsync() { Contract.Assert(m_buildDirectory.IsValid); AbsolutePath outputDirectory = m_host.GetFolderForFrontEnd(Name); AbsolutePath argumentsFile = outputDirectory.Combine(m_context.PathTable, Guid.NewGuid().ToString()); if (!TryRetrieveCMakeSearchLocations(out IEnumerable <AbsolutePath> searchLocations)) { return(new CMakeGenerationError(m_resolverSettings.ModuleName, m_buildDirectory.ToString(m_context.PathTable))); } SandboxedProcessResult result = await ExecuteCMakeRunner(argumentsFile, searchLocations); string standardError = result.StandardError.CreateReader().ReadToEndAsync().GetAwaiter().GetResult(); if (result.ExitCode != 0) { if (!m_context.CancellationToken.IsCancellationRequested) { Tracing.Logger.Log.CMakeRunnerInternalError( m_context.LoggingContext, m_resolverSettings.Location(m_context.PathTable), standardError); } return(new CMakeGenerationError(m_resolverSettings.ModuleName, m_buildDirectory.ToString(m_context.PathTable))); } FrontEndUtilities.TrackToolFileAccesses(m_host.Engine, m_context, Name, result.AllUnexpectedFileAccesses, outputDirectory); return(Possible.Create(Unit.Void)); }
/// <inheritdoc /> public ValueTask <Possible <ModuleDefinition> > TryGetModuleDefinitionAsync(ModuleDescriptor moduleDescriptor) { Contract.Assume(m_definitions != null, "Init must have been called"); if (m_definitions.TryGetValue(moduleDescriptor, out var result)) { return(ValueTask.FromResult(Possible.Create(result))); } return(ValueTask.FromResult((Possible <ModuleDefinition>) new ModuleNotOwnedByThisResolver(moduleDescriptor))); }
/// <inheritdoc /> public ValueTask <Possible <ModuleDescriptor> > TryGetOwningModuleDescriptorAsync(AbsolutePath specPath) { Contract.Assume(m_descriptorsBySpecPath != null, "Init must have been called"); if (m_descriptorsBySpecPath.TryGetValue(specPath, out var result)) { return(ValueTask.FromResult(Possible.Create(result))); } var notOwnedFailure = new SpecNotOwnedByResolverFailure(specPath.ToString(m_context.PathTable)); return(ValueTask.FromResult((Possible <ModuleDescriptor>)notOwnedFailure)); }
/// <inheritdoc /> public ValueTask <Possible <IReadOnlyCollection <ModuleDescriptor> > > TryGetModuleDescriptorsAsync(ModuleReferenceWithProvenance moduleReference) { Contract.Assume(m_descriptorsByName != null, "Init must have been called"); IReadOnlyCollection <ModuleDescriptor> result; if (m_descriptorsByName.TryGetValue(moduleReference.Name, out var descriptors)) { result = descriptors; } else { result = CollectionUtilities.EmptyArray <ModuleDescriptor>(); } return(ValueTask.FromResult(Possible.Create(result))); }
/// <summary> /// Run the test /// </summary> public bool Run(string testFolder, string specFile, string fullIdentifier, string shortName, string lkgFile, params string[] sdksToResolve) { Contract.Requires(!string.IsNullOrEmpty(testFolder)); Contract.Requires(!string.IsNullOrEmpty(specFile)); Contract.Requires(sdksToResolve != null); // Sadly the frontend doesn't use the engine abstractions file api's so we have to materialize stuff on disk for now... // TODO: Fix this code once the frontend supports a proper virtual FileSystem. // TODO: Change the package semantics to implicit when we expose a way to evaluate a single value var testFileName = Path.GetFileName(specFile); var mainFileName = "testMain.bp"; var testMainFile = Path.Combine(testFolder, mainFileName); Directory.CreateDirectory(testFolder); File.WriteAllText(Path.Combine(testFolder, Names.ModuleConfigBm), I($@"module( {{ name: 'TestPackage', nameResolutionSemantics: NameResolutionSemantics.implicitProjectReferences, projects: [ f`{mainFileName}`, f`{testFileName}`, ], }});")); File.WriteAllText(testMainFile, I($@" export const testFolder = d`{Path.GetDirectoryName(specFile).Replace('\\', '/')}`; @@public export const main = {fullIdentifier}();")); File.Copy(specFile, Path.Combine(testFolder, testFileName)); // Create a fake package for Sdk.TestRunner so that you can safely test packages that have the tests embedded in them. var testRunnerFolder = Path.Combine(testFolder, "Sdk.TestRunner"); Directory.CreateDirectory(testRunnerFolder); File.WriteAllText(Path.Combine(testRunnerFolder, Names.ModuleConfigBm), I($"module({{\n\tname: 'Sdk.TestRunner',\n}});")); File.WriteAllText(Path.Combine(testRunnerFolder, "package" + Names.DotDscExtension), I($@" export interface TestArguments {{ testFiles: File[]; sdkFolders?: (Directory|StaticDirectory)[]; autoFixLkgs?: boolean; }} export interface TestResult {{ xmlResults: File; }} export function test(args: TestArguments): TestResult {{ Contract.fail(""Can't run a DScript UnitTest inside of a DScript UnitTest""); }}")); // Setup Context and configuration var frontEndContext = FrontEndContext.CreateInstanceForTesting(); var pipContext = new SchedulerContext(CancellationToken.None, frontEndContext.StringTable, frontEndContext.PathTable, frontEndContext.SymbolTable, frontEndContext.QualifierTable); var pathTable = frontEndContext.PathTable; var testFolderPath = AbsolutePath.Create(pathTable, testFolder); var configuration = CreateConfiguration(sdksToResolve.Union(new[] { testRunnerFolder }), pathTable, testFolderPath); var engineAbstraction = new TestEngineAbstraction(pathTable, frontEndContext.StringTable, testFolderPath, new PassThroughFileSystem(pathTable)); var frontEndStatistics = new FrontEndStatistics(); if (!CreateFactories( frontEndContext, engineAbstraction, frontEndStatistics, configuration, out var ambientTesting, out var moduleRegistry, out var frontEndFactory)) { return(false); } // Set the timeout to a large number to avoid useless performance collections in tests. using (var performanceCollector = new PerformanceCollector(TimeSpan.FromHours(1))) using (var frontEndHostController = new FrontEndHostController( frontEndFactory, new EvaluationScheduler(1), moduleRegistry, frontEndStatistics, m_tracingLogger, performanceCollector, collectMemoryAsSoonAsPossible: true)) { var frontEndController = (IFrontEndController)frontEndHostController; frontEndController.InitializeHost(frontEndContext, configuration); frontEndController.ParseConfig(configuration); // Populate the graph using (var pipTable = new PipTable( pipContext.PathTable, pipContext.SymbolTable, initialBufferSize: 16384, maxDegreeOfParallelism: 1, debug: true)) { var mountPathExpander = new MountPathExpander(pathTable); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "testFolder"), testFolderPath, allowHashing: true, readable: true, writable: false)); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "src"), testFolderPath.Combine(pathTable, "src"), allowHashing: true, readable: true, writable: true)); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "out"), testFolderPath.Combine(pathTable, "out"), allowHashing: true, readable: true, writable: true)); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "noRead"), testFolderPath.Combine(pathTable, "noRead"), allowHashing: true, readable: false, writable: true)); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "temp"), engineAbstraction.Layout.TempDirectory, allowHashing: true, readable: true, writable: true)); mountPathExpander.Add(pathTable, new SemanticPathInfo(PathAtom.Create(frontEndContext.StringTable, "obj"), engineAbstraction.Layout.ObjectDirectory, allowHashing: true, readable: true, writable: true)); var graph = new PipGraph.Builder( pipTable, pipContext, m_pipLogger, frontEndContext.LoggingContext, configuration, mountPathExpander); using (var cacheLayer = new EngineCache( new InMemoryArtifactContentCache(), new InMemoryTwoPhaseFingerprintStore())) { var cache = Task.FromResult(Possible.Create(cacheLayer)); try { var evaluationFilter = new EvaluationFilter( pipContext.SymbolTable, pipContext.PathTable, new FullSymbol[0], new[] { AbsolutePath.Create(frontEndContext.PathTable, testMainFile), }, CollectionUtilities.EmptyArray <StringId>()); if (!frontEndController.PopulateGraph(cache, graph, engineAbstraction, evaluationFilter, configuration, configuration.Startup)) { HandleDiagnostics(); return(false); } } catch (AggregateException e) { var baseException = e.GetBaseException(); if (baseException is XunitException) { // If it is an XUnit assert, then unwrap the exception and throw that because XUnit other doesn't display the error nicely. ExceptionDispatchInfo.Capture(baseException).Throw(); } throw; } } if (!ValidatePips(frontEndContext, graph, testFolderPath, specFile, shortName, lkgFile, ambientTesting.DontValidatePipsEnabled)) { return(false); } } } HandleDiagnostics(); return(true); }
/// <summary> /// Returns the wrapped cache session only if it is not closed; otherwise returns /// <see cref="CacheClosedFailure"/>. /// </summary> /// <param name="callerName">Optional name of the caller (used for error message only)</param> public Possible <ICacheSession, Failure> Get(string callerName = null) { return(m_cache.IsClosed ? new CacheClosedFailure(m_cache.CacheId, m_cache.CacheSessionId, callerName ?? "<unknown>") : Possible.Create(m_cache)); }
/// <inheritdoc /> public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId, ICacheConfiguration cacheConfiguration = null) { Contract.Requires(cacheData != null); using (var eventing = new InitializeCacheActivity(VerticalCacheAggregator.EventSource, activityId, typeof(VerticalCacheAggregator).FullName)) { eventing.Start(cacheData); var possibleCacheConfig = cacheData.Create <Config>(); if (!possibleCacheConfig.Succeeded) { return(eventing.StopFailure(possibleCacheConfig.Failure)); } Config cacheAggregatorConfig = possibleCacheConfig.Result; // temporary if (cacheAggregatorConfig.PreFetchCasData == true) { throw new NotImplementedException(); } // initialize local cache var maybeCache = await CacheFactory.InitializeCacheAsync(cacheAggregatorConfig.LocalCache, activityId, cacheConfiguration); if (!maybeCache.Succeeded) { return(eventing.StopFailure(maybeCache.Failure)); } ICache local = maybeCache.Result; if (local.IsReadOnly) { Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status"); return(eventing.StopFailure(new VerticalCacheAggregatorNeedsWriteableLocalFailure(local.CacheId))); } if (cacheAggregatorConfig.UseLocalOnly || cacheConfiguration?.UseLocalOnly == true) { return(eventing.Returns(Possible.Create(local))); } maybeCache = await ConstructRemoteCacheAsync(activityId, cacheAggregatorConfig, cacheConfiguration); if (!maybeCache.Succeeded) { eventing.Write(CacheActivity.CriticalDataOptions, new { RemoteCacheFailed = maybeCache.Failure }); if (cacheAggregatorConfig.FailIfRemoteFails) { Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status"); return(eventing.StopFailure(maybeCache.Failure)); } // If the remote cache does not construct, we fall back to just the local. // This is basically like a disconnected state only we are starting disconnnected // and thus are just the local cache now. We can just return the local and // not add the overhead of the aggregator. string failureMessage = string.Format( System.Globalization.CultureInfo.InvariantCulture, RemoteConstructionFailureWarning, local.CacheId); // Note: Compiler is confused and needs help converting ICache to Possible here but not a few lines below. return(eventing.Returns(new MessageForwardingCache(new Failure[] { maybeCache.Failure.Annotate(failureMessage) }, local))); } ICache remote = maybeCache.Result; bool readOnlyRemote = remote.IsReadOnly || cacheAggregatorConfig.RemoteIsReadOnly; var remoteReadCache = cacheAggregatorConfig.RemoteIsWriteOnly ? new MemCache(new CacheId("ReadOnlyEmptyRemote"), strictMetadataCasCoupling: true, isauthoritative: false) : null; try { // instantiate new VerticalCacheAggregator return(eventing.Returns(new VerticalCacheAggregator( local, remote, remoteReadCache, readOnlyRemote, cacheAggregatorConfig.WriteThroughCasData, cacheAggregatorConfig.RemoteContentIsReadOnly))); } catch (Exception e) { string cacheId = local.CacheId + "_" + remote.CacheId; Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status"); Analysis.IgnoreResult(await remote.ShutdownAsync(), justification: "Okay to ignore shutdown status"); return(eventing.StopFailure(new CacheConstructionFailure(cacheId, e))); } } }