public static ToDelimitedString ( this |
||
input | this |
|
delimiter | string | |
return | string |
private bool TryExportResourceFiles(IEnumerable <string> resourceNames, string outputDirectory, bool overwrite, string regexFilter = null) { if (string.IsNullOrEmpty(outputDirectory)) { throw new ArgumentNullException(nameof(outputDirectory)); } if (!resourceNames.Any()) { return(false); } bool isEmpty = true; using (new LoggerPhaseScope("ExportResourceFiles", true)) using (var templateResource = CreateTemplateResource(resourceNames)) { if (templateResource.IsEmpty) { Logger.Log(LogLevel.Warning, $"No resource found for [{TypeForwardedToStringExtension.ToDelimitedString(resourceNames)}]."); } else { foreach (var pair in templateResource.GetResourceStreams(regexFilter)) { var outputPath = Path.Combine(outputDirectory, pair.Key); CopyResource(pair.Value, outputPath, overwrite); Logger.Log(LogLevel.Verbose, $"File {pair.Key} copied to {outputPath}."); isEmpty = false; } } return(!isEmpty); } }
private static void CopyFromCachedResult(BuildInfo buildInfo, IEnumerable <string> inputs, string outputFolder) { var outputFolderSource = buildInfo.OutputFolder; var relativeFiles = buildInfo.RelatvieOutputFiles; if (relativeFiles == null) { Logger.Log(LogLevel.Warning, $"No metadata is generated for '{TypeForwardedToStringExtension.ToDelimitedString(inputs)}'."); return; } Logger.Log(LogLevel.Info, $"'{TypeForwardedToStringExtension.ToDelimitedString(inputs)}' keep up-to-date since '{buildInfo.TriggeredUtcTime.ToString()}', cached result from '{buildInfo.OutputFolder}' is used."); TypeForwardedToPathUtility.CopyFilesToFolder(relativeFiles.Select(s => Path.Combine(outputFolderSource, s)), outputFolderSource, outputFolder, true, s => Logger.Log(LogLevel.Info, s), null); }
public static FileMapping ExpandFileMapping(string baseDirectory, FileMapping fileMapping) { if (fileMapping == null) { return(null); } if (fileMapping.Expanded) { return(fileMapping); } var expandedFileMapping = new FileMapping(); foreach (var item in fileMapping.Items) { // Use local variable to avoid different items influencing each other var src = Path.Combine(baseDirectory, item.SourceFolder ?? string.Empty); var options = GetMatchOptionsFromItem(item); var files = FileGlob.GetFiles(src, item.Files, item.Exclude, options).ToArray(); if (files.Length == 0) { var currentSrcFullPath = string.IsNullOrEmpty(src) ? Directory.GetCurrentDirectory() : Path.GetFullPath(src); Logger.LogInfo($"No files are found with glob pattern {TypeForwardedToStringExtension.ToDelimitedString(item.Files) ?? "<none>"}, excluding {TypeForwardedToStringExtension.ToDelimitedString(item.Exclude) ?? "<none>"}, under directory \"{currentSrcFullPath}\""); CheckPatterns(item.Files); } expandedFileMapping.Add( new FileMappingItem { SourceFolder = src, Files = new FileItems(files), DestinationFolder = item.DestinationFolder }); } expandedFileMapping.Expanded = true; return(expandedFileMapping); }
private async Task SaveAllMembersFromCacheAsync(IEnumerable <string> inputs, string outputFolder, bool forceRebuild) { var projectCache = new ConcurrentDictionary <string, Project>(); // Project<=>Documents var documentCache = new ProjectDocumentCache(); var projectDependencyGraph = new ConcurrentDictionary <string, List <string> >(); DateTime triggeredTime = DateTime.UtcNow; var solutions = inputs.Where(s => IsSupportedSolution(s)); var projects = inputs.Where(s => IsSupportedProject(s)); var sourceFiles = inputs.Where(s => IsSupportedSourceFile(s)); // Exclude not supported files from inputs inputs = solutions.Concat(projects).Concat(sourceFiles); // Add filter config file into inputs and cache if (!string.IsNullOrEmpty(_filterConfigFile)) { inputs = inputs.Concat(new string[] { _filterConfigFile }); documentCache.AddDocument(_filterConfigFile, _filterConfigFile); } // No matter is incremental or not, we have to load solutions into memory await solutions.ForEachInParallelAsync(async path => { documentCache.AddDocument(path, path); var solution = await GetSolutionAsync(path); if (solution != null) { foreach (var project in solution.Projects) { var filePath = project.FilePath; // If the project is csproj/vbproj, add to project dictionary, otherwise, ignore if (IsSupportedProject(filePath)) { projectCache.GetOrAdd(TypeForwardedToStringExtension.ToNormalizedFullPath(project.FilePath), s => project); } else { var value = string.Join(",", SupportedExtensions); Logger.Log(LogLevel.Warning, $"Project {filePath} inside solution {path} is not supported, supported file extension are: {value}. The project will be ignored."); } } } }, 60); // Load additional projects out if it is not contained in expanded solution projects = projects.Except(projectCache.Keys).Distinct(); await projects.ForEachInParallelAsync(async path => { var project = await GetProjectAsync(path); if (project != null) { projectCache.GetOrAdd(path, s => project); } }, 60); foreach (var item in projectCache) { var path = item.Key; var project = item.Value; documentCache.AddDocument(path, path); documentCache.AddDocuments(path, project.Documents.Select(s => s.FilePath)); documentCache.AddDocuments(path, project.MetadataReferences .Where(s => s is PortableExecutableReference) .Select(s => ((PortableExecutableReference)s).FilePath)); FillProjectDependencyGraph(projectCache, projectDependencyGraph, project); } documentCache.AddDocuments(sourceFiles); // Incremental check for inputs as a whole: var applicationCache = ApplicationLevelCache.Get(inputs); if (!forceRebuild) { BuildInfo buildInfo = applicationCache.GetValidConfig(inputs); if (buildInfo != null && buildInfo.ShouldSkipMarkup == _shouldSkipMarkup) { IncrementalCheck check = new IncrementalCheck(buildInfo); // 1. Check if sln files/ project files and its contained documents/ source files are modified var projectModified = check.AreFilesModified(documentCache.Documents); if (!projectModified) { // 2. Check if documents/ assembly references are changed in a project // e.g. <Compile Include="*.cs* /> and file added/deleted foreach (var project in projectCache.Values) { var key = TypeForwardedToStringExtension.ToNormalizedFullPath(project.FilePath); IEnumerable <string> currentContainedFiles = documentCache.GetDocuments(project.FilePath); var previousDocumentCache = new ProjectDocumentCache(buildInfo.ContainedFiles); IEnumerable <string> previousContainedFiles = previousDocumentCache.GetDocuments(project.FilePath); if (previousContainedFiles != null && currentContainedFiles != null) { projectModified = !previousContainedFiles.SequenceEqual(currentContainedFiles); } else { // When one of them is not null, project is modified if (!object.Equals(previousContainedFiles, currentContainedFiles)) { projectModified = true; } } if (projectModified) { break; } } } if (!projectModified) { // Nothing modified, use the result in cache try { CopyFromCachedResult(buildInfo, inputs, outputFolder); return; } catch (Exception e) { Logger.Log(LogLevel.Warning, $"Unable to copy results from cache: {e.Message}. Rebuild starts."); } } } } // Build all the projects to get the output and save to cache List <MetadataItem> projectMetadataList = new List <MetadataItem>(); ConcurrentDictionary <string, bool> projectRebuildInfo = new ConcurrentDictionary <string, bool>(); ConcurrentDictionary <string, Compilation> compilationCache = await GetProjectCompilationAsync(projectCache); var extensionMethods = GetAllExtensionMethods(compilationCache.Values); foreach (var key in GetTopologicalSortedItems(projectDependencyGraph)) { var dependencyRebuilt = projectDependencyGraph[key].Any(r => projectRebuildInfo[r]); var projectMetadataResult = await GetProjectMetadataFromCacheAsync(projectCache[key], compilationCache[key], outputFolder, documentCache, forceRebuild, _shouldSkipMarkup, _preserveRawInlineComments, _filterConfigFile, extensionMethods, dependencyRebuilt); var projectMetadata = projectMetadataResult.Item1; if (projectMetadata != null) { projectMetadataList.Add(projectMetadata); } projectRebuildInfo[key] = projectMetadataResult.Item2; } var csFiles = sourceFiles.Where(s => IsSupportedCSSourceFile(s)); if (csFiles.Any()) { var csContent = string.Join(Environment.NewLine, csFiles.Select(s => File.ReadAllText(s))); var csCompilation = CompilationUtility.CreateCompilationFromCsharpCode(csContent); if (csCompilation != null) { var csMetadata = await GetFileMetadataFromCacheAsync(csFiles, csCompilation, outputFolder, forceRebuild, _shouldSkipMarkup, _preserveRawInlineComments, _filterConfigFile, extensionMethods); if (csMetadata != null) { projectMetadataList.Add(csMetadata.Item1); } } } var vbFiles = sourceFiles.Where(s => IsSupportedVBSourceFile(s)); if (vbFiles.Any()) { var vbContent = string.Join(Environment.NewLine, vbFiles.Select(s => File.ReadAllText(s))); var vbCompilation = CompilationUtility.CreateCompilationFromVBCode(vbContent); if (vbCompilation != null) { var vbMetadata = await GetFileMetadataFromCacheAsync(vbFiles, vbCompilation, outputFolder, forceRebuild, _preserveRawInlineComments, _shouldSkipMarkup, _filterConfigFile, extensionMethods); if (vbMetadata != null) { projectMetadataList.Add(vbMetadata.Item1); } } } var allMemebers = MergeYamlProjectMetadata(projectMetadataList); var allReferences = MergeYamlProjectReferences(projectMetadataList); if (allMemebers == null || allMemebers.Count == 0) { var value = TypeForwardedToStringExtension.ToDelimitedString(projectMetadataList.Select(s => s.Name)); Logger.Log(LogLevel.Warning, $"No metadata is generated for {value}."); applicationCache.SaveToCache(inputs, null, triggeredTime, outputFolder, null, _shouldSkipMarkup); } else { // TODO: need an intermediate folder? when to clean it up? // Save output to output folder var outputFiles = ResolveAndExportYamlMetadata(allMemebers, allReferences, outputFolder, _validInput.IndexFileName, _validInput.TocFileName, _validInput.ApiFolderName, _preserveRawInlineComments, _shouldSkipMarkup, _rawInput.ExternalReferences, _useCompatibilityFileName); applicationCache.SaveToCache(inputs, documentCache.Cache, triggeredTime, outputFolder, outputFiles, _shouldSkipMarkup); } }
internal List <ManifestItem> Process(List <InternalManifestItem> manifest, DocumentBuildContext context, ApplyTemplateSettings settings, IDictionary <string, object> globals = null) { using (new LoggerPhaseScope("Apply Templates", true)) { if (globals == null) { globals = Tokens.ToDictionary(pair => pair.Key, pair => (object)pair.Value); } var documentTypes = manifest.Select(s => s.DocumentType).Distinct(); var notSupportedDocumentTypes = documentTypes.Where(s => s != "Resource" && _templateCollection[s] == null); if (notSupportedDocumentTypes.Any()) { Logger.LogWarning($"There is no template processing document type(s): {TypeForwardedToStringExtension.ToDelimitedString(notSupportedDocumentTypes)}"); } Logger.LogInfo($"Applying templates to {manifest.Count} model(s)..."); if (settings.Options.HasFlag(ApplyTemplateOptions.TransformDocument)) { var templatesInUse = documentTypes.Select(s => _templateCollection[s]).Where(s => s != null).ToList(); ProcessDependencies(settings.OutputFolder, templatesInUse); } else { Logger.LogInfo("Dryrun, no template will be applied to the documents."); } var templateManifest = ProcessCore(manifest, context, settings, globals); return(templateManifest); } }