private void WriteLine(ILogItem item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (item.File == null) { return; } string fileFromWorkingDir = TypeForwardedToStringExtension.BackSlashToForwardSlash(item.File); if (!TypeForwardedToPathUtility.IsRelativePath(item.File)) { fileFromWorkingDir = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, item.File); } List <LogItem> logsPerFile; if (!_logs.TryGetValue(fileFromWorkingDir, out logsPerFile)) { logsPerFile = _logs[fileFromWorkingDir] = new List <LogItem>(); } logsPerFile.Add(new LogItem { File = TypeForwardedToStringExtension.BackSlashToForwardSlash(item.File), Line = item.Line, LogLevel = item.LogLevel, Message = item.Message, Phase = item.Phase, }); }
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); } }
public ExtractMetadataWorker(ExtractMetadataInputModel input, bool rebuild, bool useCompatibilityFileName) { _rawInput = input; _validInput = ValidateInput(input); _rebuild = rebuild; _shouldSkipMarkup = input.ShouldSkipMarkup; _preserveRawInlineComments = input.PreserveRawInlineComments; _filterConfigFile = TypeForwardedToStringExtension.ToNormalizedFullPath(input.FilterConfigFile); _useCompatibilityFileName = useCompatibilityFileName; }
private static string GetRelativeResourceKey(string templateName, string relativePath) { if (string.IsNullOrEmpty(templateName)) { return(relativePath); } // Make sure resource keys are combined using '/' return(TypeForwardedToStringExtension.ForwardSlashCombine(TypeForwardedToStringExtension.ToNormalizedPath(Path.GetDirectoryName(templateName)), relativePath)); }
private static string ExportModel(object model, string modelFileRelativePath, ExportSettings settings) { if (model == null) { return(null); } var outputFolder = settings.OutputFolder; string modelPath = Path.Combine(outputFolder ?? string.Empty, settings.PathRewriter(modelFileRelativePath)); JsonUtility.Serialize(modelPath, model); return(TypeForwardedToStringExtension.ToDisplayPath(modelPath)); }
private void PrepareBuild(DocumentBuildContext context, IEnumerable <HostService> hostServices) { var incrementalContext = context.IncrementalBuildContext; var lbv = incrementalContext?.LastBuildVersionInfo; var cbv = incrementalContext?.CurrentBuildVersionInfo; if (ShouldTraceIncrementalInfo) { var ldg = lbv?.Dependency; var cdg = cbv.Dependency; if (ldg != null) { // reregister dependency types from last dependency graph using (new LoggerPhaseScope("RegisterDependencyTypeFromLastBuild", true)) { cdg.RegisterDependencyType(ldg.DependencyTypes.Values); } // restore dependency graph from last dependency graph using (new LoggerPhaseScope("ReportDependencyFromLastBuild", true)) { cdg.ReportDependency(from r in ldg.ReportedBys from i in ldg.GetDependencyReportedBy(r) select i); } } } foreach (var hostService in hostServices) { hostService.SourceFiles = context.AllSourceFiles; foreach (var m in hostService.Models) { if (m.LocalPathFromRepoRoot == null) { m.LocalPathFromRepoRoot = TypeForwardedToStringExtension.ToDisplayPath(Path.Combine(m.BaseDir, m.File)); } if (m.LocalPathFromRoot == null) { m.LocalPathFromRoot = TypeForwardedToStringExtension.ToDisplayPath(Path.Combine(m.BaseDir, m.File)); } } if (ShouldTraceIncrementalInfo) { hostService.DependencyGraph = cbv.Dependency; using (new LoggerPhaseScope("RegisterDependencyTypeFromProcessor", true)) { RegisterDependencyType(hostService); } } } }
private static LoggerFileScope GetFileScope(ImmutableStack <string> parents) { if (!parents.IsEmpty) { var path = TypeForwardedToStringExtension.ToDisplayPath(parents.Peek()); if (!string.IsNullOrEmpty(path)) { return(new LoggerFileScope(path)); } } return(null); }
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 void Exec(SubCommandRunningContext context) { string outputFolder = null; try { var config = new DefaultConfigModel(); var questionContext = new QuestionContext { Quiet = _options.Quiet }; foreach (var question in _selectorQuestions) { question.Process(config, questionContext); } foreach (var question in _overallQuestion) { question.Process(config, questionContext); } if (questionContext.ContainsMetadata) { foreach (var question in _metadataQuestions) { question.Process(config, questionContext); } } foreach (var question in _buildQuestions) { question.Process(config, questionContext); } if (_options.OnlyConfigFile) { GenerateConfigFile(_options.OutputFolder, config); } else { outputFolder = TypeForwardedToStringExtension.ToDisplayPath(Path.GetFullPath(string.IsNullOrEmpty(_options.OutputFolder) ? DefaultOutputFolder : _options.OutputFolder)); GenerateSeedProject(outputFolder, config); } } catch (Exception e) { throw new DocfxInitException($"Error with init docfx project under \"{outputFolder}\" : {e.Message}", e); } }
private static void GenerateConfigFile(string outputFolder, object config) { var path = TypeForwardedToStringExtension.ToDisplayPath(Path.Combine(outputFolder ?? string.Empty, ConfigName)); if (File.Exists(path)) { if (!ProcessOverwriteQuestion($"Config file \"{path}\" already exists, do you want to overwrite this file?")) { return; } } SaveConfigFile(path, config); $"Successfully generated default docfx config file to {path}".WriteLineToConsole(ConsoleColor.Green); }
public override Stream GetResourceStream(string name) { if (IsEmpty) { return(null); } // incase relative path is combined by backslash \ if (!Names.Contains(TypeForwardedToStringExtension.ToNormalizedPath(name.Trim()), ResourceComparer)) { return(null); } var filePath = Path.Combine(_directory, name); return(new FileStream(filePath, FileMode.Open, FileAccess.Read)); }
private static string ComputePluginHash(List <Assembly> assemblyList) { if (assemblyList?.Count > 0) { var builder = new StringBuilder(); foreach (var item in from assembly in assemblyList select assembly.FullName + "@" + assembly.GetCustomAttribute <AssemblyFileVersionAttribute>()?.Version.ToString() into item orderby item select item) { builder.AppendLine(item); } return(TypeForwardedToStringExtension.GetMd5String(builder.ToString())); } return(string.Empty); }
public void SaveToCache(IEnumerable <string> inputProjects, IDictionary <string, List <string> > containedFiles, DateTime triggeredTime, string outputFolder, IList <string> fileRelativePaths, bool shouldSkipMarkup) { var key = TypeForwardedToStringExtension.GetNormalizedFullPathKey(inputProjects); DateTime completeTime = DateTime.UtcNow; BuildInfo info = new BuildInfo { InputFilesKey = key, ContainedFiles = containedFiles, TriggeredUtcTime = triggeredTime, CompleteUtcTime = completeTime, OutputFolder = TypeForwardedToStringExtension.ToNormalizedFullPath(outputFolder), RelatvieOutputFiles = TypeForwardedToStringExtension.GetNormalizedPathList(fileRelativePaths), BuildAssembly = AssemblyName, ShouldSkipMarkup = shouldSkipMarkup }; this.SaveConfig(key, info); }
public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata) { switch (file.Type) { case DocumentType.Article: var filePath = Path.Combine(file.BaseDir, file.File); var swaggerContent = File.ReadAllText(filePath); var swagger = SwaggerJsonParser.Parse(swaggerContent); swagger.Metadata[DocumentTypeKey] = RestApiDocumentType; swagger.Raw = swaggerContent; CheckOperationId(swagger, file.File); var repoInfo = GitUtility.GetGitDetail(filePath); if (repoInfo != null) { swagger.Metadata["source"] = new SourceDetail() { Remote = repoInfo }; } swagger.Metadata = MergeMetadata(swagger.Metadata, metadata); var vm = SwaggerModelConverter.FromSwaggerModel(swagger); var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath); return(new FileModel(file, vm, serializer: Environment.Is64BitProcess?null: new BinaryFormatter()) { Uids = new[] { new UidDefinition(vm.Uid, displayLocalPath) } .Concat(from item in vm.Children select new UidDefinition(item.Uid, displayLocalPath)) .Concat(from tag in vm.Tags select new UidDefinition(tag.Uid, displayLocalPath)).ToImmutableArray(), LocalPathFromRepoRoot = repoInfo?.RelativePath ?? TypeForwardedToStringExtension.ToDisplayPath(filePath), LocalPathFromRoot = displayLocalPath }); case DocumentType.Overwrite: // TODO: Refactor current behavior that overwrite file is read multiple times by multiple processors return(OverwriteDocumentReader.Read(file)); default: throw new NotSupportedException(); } }
private static IEnumerable <string> GetTransitiveProjectReferences(ConcurrentDictionary <string, Project> projectCache, Project project) { var solution = project.Solution; foreach (var pr in project.ProjectReferences) { var refProject = solution.GetProject(pr.ProjectId); var path = TypeForwardedToStringExtension.ToNormalizedFullPath(refProject.FilePath); if (projectCache.ContainsKey(path)) { yield return(path); } else { foreach (var rpr in GetTransitiveProjectReferences(projectCache, refProject)) { yield return(rpr); } } } }
public override FileModel Load(FileAndType file, ImmutableDictionary <string, object> metadata) { string uid = null; Dictionary <string, object> content = null; var metafile = Path.Combine(file.BaseDir, file.File.TrimEnd('.') + ".meta"); if (File.Exists(metafile)) { content = YamlUtility.Deserialize <Dictionary <string, object> >(metafile); if (content != null) { foreach (var item in metadata) { if (!content.ContainsKey(item.Key)) { content[item.Key] = item.Value; } if (item.Key == Constants.PropertyName.Uid) { uid = item.Value as string; } } } } if (content == null) { content = metadata.ToDictionary(p => p.Key, p => p.Value); } var filePath = Path.Combine(file.BaseDir, file.File); var repoDetail = GitUtility.GetGitDetail(filePath); var displayLocalPath = TypeForwardedToPathUtility.MakeRelativePath(EnvironmentContext.BaseDirectory, file.FullPath); return(new FileModel(file, content) { Uids = string.IsNullOrEmpty(uid) ? ImmutableArray <UidDefinition> .Empty : ImmutableArray <UidDefinition> .Empty.Add(new UidDefinition(uid, displayLocalPath)), LocalPathFromRepoRoot = repoDetail?.RelativePath ?? TypeForwardedToStringExtension.ToDisplayPath(Path.Combine(file.BaseDir, file.File)), LocalPathFromRoot = displayLocalPath }); }
public void ProcessTocWithCircularReferenceShouldFail() { var referencedToc = _fileCreator.CreateFile($@" - name: Topic href: TOC.md ", FileType.YamlToc, "sub1"); var subToc = _fileCreator.CreateFile($@" #Topic ##[ReferencedToc](Toc.yml) ", FileType.MarkdownToc, "sub1"); var content = $@" - name: Topic1 href: {subToc} "; var toc = _fileCreator.CreateFile(content, FileType.YamlToc); FileCollection files = new FileCollection(_inputFolder); files.Add(DocumentType.Article, new[] { toc, subToc }); var e = Assert.Throws <DocumentException>(() => BuildDocument(files)); Assert.Equal($"Circular reference to {TypeForwardedToStringExtension.ToDisplayPath(Path.GetFullPath(Path.Combine(_inputFolder, subToc)))} is found in {TypeForwardedToStringExtension.ToDisplayPath(Path.GetFullPath(Path.Combine(_inputFolder, referencedToc)))}", e.Message, true); }
private static Task <Tuple <MetadataItem, bool> > GetProjectMetadataFromCacheAsync(Project project, Compilation compilation, string outputFolder, ProjectDocumentCache documentCache, bool forceRebuild, bool shouldSkipMarkup, bool preserveRawInlineComments, string filterConfigFile, IReadOnlyDictionary <Compilation, IEnumerable <IMethodSymbol> > extensionMethods, bool isReferencedProjectRebuilt) { var projectFilePath = project.FilePath; var k = documentCache.GetDocuments(projectFilePath); return(GetMetadataFromProjectLevelCacheAsync( project, new[] { projectFilePath, filterConfigFile }, s => Task.FromResult(forceRebuild || s.AreFilesModified(k.Concat(new string[] { filterConfigFile })) || isReferencedProjectRebuilt), s => Task.FromResult(compilation), s => { return new Dictionary <string, List <string> > { { TypeForwardedToStringExtension.ToNormalizedFullPath(s.FilePath), k.ToList() } }; }, outputFolder, preserveRawInlineComments, shouldSkipMarkup, filterConfigFile, extensionMethods)); }
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); }
public string GetTemplatesHash() { var sb = new StringBuilder(); using (var templateResource = CreateTemplateResource(_templates)) using (var md5 = MD5.Create()) { foreach (var name in from n in templateResource.Names ?? Enumerable.Empty <string>() orderby n select n) { sb.Append(name); sb.Append(":"); sb.Append( Convert.ToBase64String( md5.ComputeHash( templateResource.GetResourceStream( name)))); sb.Append(";"); } } return(TypeForwardedToStringExtension.GetMd5String(sb.ToString())); }
private Dictionary <string, string> GetListContent(XPathNavigator navigator, string xpath, string contentType, ITripleSlashCommentParserContext context) { var iterator = navigator.Select(xpath); var result = new Dictionary <string, string>(); if (iterator == null) { return(result); } foreach (XPathNavigator nav in iterator) { string name = nav.GetAttribute("name", string.Empty); string description = GetXmlValue(nav); if (!string.IsNullOrEmpty(name)) { if (result.ContainsKey(name)) { string path = context.Source.Remote != null?Path.Combine(context.Source.Remote.LocalWorkingDirectory, context.Source.Remote.RelativePath) : context.Source.Path; Logger.LogWarning($"Duplicate {contentType} '{name}' found in comments, the latter one is ignored.", null, TypeForwardedToStringExtension.ToDisplayPath(path), context.Source.StartLine.ToString()); } else { result.Add(name, description); } } } return(result); }
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); } }
public BuildInfo GetValidConfig(IEnumerable <string> inputProjects) { var key = TypeForwardedToStringExtension.GetNormalizedFullPathKey(inputProjects); return(GetConfig(key)); }
private static void FillProjectDependencyGraph(ConcurrentDictionary <string, Project> projectCache, ConcurrentDictionary <string, List <string> > projectDependencyGraph, Project project) { projectDependencyGraph.GetOrAdd(TypeForwardedToStringExtension.ToNormalizedFullPath(project.FilePath), GetTransitiveProjectReferences(projectCache, project).Distinct().ToList()); }
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); } }
private static ExtractMetadataInputModel ValidateInput(ExtractMetadataInputModel input) { if (input == null) { return(null); } if (input.Items == null || input.Items.Count == 0) { Logger.Log(LogLevel.Warning, "No source project or file to process, exiting..."); return(null); } var items = new Dictionary <string, List <string> >(); // 1. Input file should exists foreach (var pair in input.Items) { if (string.IsNullOrWhiteSpace(pair.Key)) { var value = string.Join(", ", pair.Value); Logger.Log(LogLevel.Warning, $"Empty folder name is found: '{pair.Key}': '{value}'. It is not supported, skipping."); continue; } // HashSet to guarantee the input file path is unique HashSet <string> validFilePath = new HashSet <string>(); foreach (var inputFilePath in pair.Value) { if (!string.IsNullOrEmpty(inputFilePath)) { if (File.Exists(inputFilePath)) { if (IsSupported(inputFilePath)) { var path = TypeForwardedToStringExtension.ToNormalizedFullPath(inputFilePath); validFilePath.Add(path); } else { var value = string.Join(",", SupportedExtensions); Logger.Log(LogLevel.Warning, $"File {inputFilePath} is not supported, supported file extension are: {value}. The file will be ignored."); } } else { Logger.Log(LogLevel.Warning, $"File {inputFilePath} does not exist, will be ignored."); } } } if (validFilePath.Count > 0) { items.Add(pair.Key, validFilePath.ToList()); } } if (items.Count > 0) { var clone = input.Clone(); clone.Items = items; return(clone); } else { return(null); } }
private Manifest BuildCore(DocumentBuildParameters parameters) { using (new LoggerPhaseScope(PhaseName, true)) { Logger.LogInfo($"Max parallelism is {parameters.MaxParallelism}."); Directory.CreateDirectory(parameters.OutputBaseDir); var context = new DocumentBuildContext( Path.Combine(Directory.GetCurrentDirectory(), parameters.OutputBaseDir), parameters.Files.EnumerateFiles(), parameters.ExternalReferencePackages, parameters.XRefMaps, parameters.MaxParallelism, parameters.Files.DefaultBaseDir); if (ShouldTraceIncrementalInfo) { context.IncrementalBuildContext = IncrementalBuildContext.Create(parameters, CurrentBuildInfo, LastBuildInfo, IntermediateFolder); Logger.RegisterListener(context.IncrementalBuildContext.CurrentBuildVersionInfo.BuildMessage.GetListener()); if (context.IncrementalBuildContext.CanVersionIncremental) { context.IncrementalBuildContext.LoadChanges(); Logger.LogVerbose($"Before expanding dependency before build, changes: {JsonUtility.Serialize(context.IncrementalBuildContext.ChangeDict, Formatting.Indented)}"); var dependencyGraph = context.IncrementalBuildContext.LastBuildVersionInfo.Dependency; context.IncrementalBuildContext.ExpandDependency(dependencyGraph, d => dependencyGraph.DependencyTypes[d.Type].Phase == BuildPhase.Build || dependencyGraph.DependencyTypes[d.Type].TriggerBuild); Logger.LogVerbose($"After expanding dependency before build, changes: {JsonUtility.Serialize(context.IncrementalBuildContext.ChangeDict, Formatting.Indented)}"); } } Logger.LogVerbose("Start building document..."); // Start building document... List <HostService> hostServices = null; try { using (var templateProcessor = parameters.TemplateManager?.GetTemplateProcessor(context, parameters.MaxParallelism) ?? TemplateProcessor.DefaultProcessor) { IMarkdownService markdownService; using (new LoggerPhaseScope("CreateMarkdownService", true)) { markdownService = CreateMarkdownService(parameters, templateProcessor.Tokens.ToImmutableDictionary()); } using (new LoggerPhaseScope("Load", true)) { hostServices = GetInnerContexts(parameters, Processors, templateProcessor, markdownService, context).ToList(); } var manifest = BuildCore(hostServices, context, parameters.VersionName).ToList(); // Use manifest from now on using (new LoggerPhaseScope("UpdateContext", true)) { UpdateContext(context); } // Run getOptions from Template using (new LoggerPhaseScope("FeedOptions", true)) { FeedOptions(manifest, context); } // Template can feed back xref map, actually, the anchor # location can only be determined in template using (new LoggerPhaseScope("FeedXRefMap", true)) { FeedXRefMap(manifest, context); } using (new LoggerPhaseScope("UpdateHref", true)) { UpdateHref(manifest, context); } // Afterwards, m.Item.Model.Content is always IDictionary using (new LoggerPhaseScope("ApplySystemMetadata", true)) { ApplySystemMetadata(manifest, context); } // Register global variables after href are all updated IDictionary <string, object> globalVariables; using (new LoggerPhaseScope("FeedGlobalVariables", true)) { globalVariables = FeedGlobalVariables(templateProcessor.Tokens, manifest, context); } // processor to add global variable to the model foreach (var m in templateProcessor.Process(manifest.Select(s => s.Item).ToList(), context, parameters.ApplyTemplateSettings, globalVariables)) { context.ManifestItems.Add(m); } return(new Manifest { Files = context.ManifestItems.ToList(), Homepages = GetHomepages(context), XRefMap = ExportXRefMap(parameters, context), SourceBasePath = TypeForwardedToStringExtension.ToNormalizedPath(EnvironmentContext.BaseDirectory) }); } } finally { if (hostServices != null) { foreach (var item in hostServices) { Cleanup(item); item.Dispose(); } } } } }
private static void GenerateSeedProject(string outputFolder, DefaultConfigModel config) { if (Directory.Exists(outputFolder)) { if (!ProcessOverwriteQuestion($"Output folder \"{outputFolder}\" already exists. Do you still want to generate files into this folder? You can use -o command option to specify the folder name")) { return; } } else { Directory.CreateDirectory(outputFolder); } // 1. Create default files var srcFolder = Path.Combine(outputFolder, "src"); var apiFolder = Path.Combine(outputFolder, "api"); var apidocFolder = Path.Combine(outputFolder, "apidoc"); var articleFolder = Path.Combine(outputFolder, "articles"); var imageFolder = Path.Combine(outputFolder, "images"); var folders = new string[] { srcFolder, apiFolder, apidocFolder, articleFolder, imageFolder }; foreach (var folder in folders) { Directory.CreateDirectory(folder); $"Created folder {TypeForwardedToStringExtension.ToDisplayPath(folder)}".WriteLineToConsole(ConsoleColor.Gray); } // 2. Create default files // a. toc.yml // b. index.md // c. articles/toc.yml // d. articles/index.md // e. .gitignore // f. api/.gitignore // TODO: move api/index.md out to some other folder var tocYaml = Tuple.Create("toc.yml", @"- name: Articles href: articles/ - name: Api Documentation href: api/ homepage: api/index.md "); var indexMarkdownFile = Tuple.Create("index.md", @"# This is the **HOMEPAGE**. Refer to [Markdown](http://daringfireball.net/projects/markdown/) for how to write markdown files. ## Quick Start Notes: 1. Add images to the *images* folder if the file is referencing an image. "); var apiTocFile = Tuple.Create("api/toc.yml", @"- name: TO BE REPLACED - href: index.md "); var apiIndexFile = Tuple.Create("api/index.md", @"# PLACEHOLDER TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! "); var articleTocFile = Tuple.Create("articles/toc.yml", @"- name: Introduction href: intro.md "); var articleMarkdownFile = Tuple.Create("articles/intro.md", @"# Add your introductions here! "); var gitignore = Tuple.Create(".gitignore", $@"############### # folder # ############### /**/DROP/ /**/TEMP/ /**/packages/ /**/bin/ /**/obj/ {config.Build.Destination} "); var apiGitignore = Tuple.Create("api/.gitignore", $@"############### # temp file # ############### *.yml "); var files = new Tuple <string, string>[] { tocYaml, indexMarkdownFile, apiTocFile, apiIndexFile, articleTocFile, articleMarkdownFile, gitignore, apiGitignore }; foreach (var file in files) { var filePath = Path.Combine(outputFolder, file.Item1); var content = file.Item2; var dir = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(dir)) { Directory.CreateDirectory(dir); } File.WriteAllText(filePath, content); $"Created File {TypeForwardedToStringExtension.ToDisplayPath(filePath)}".WriteLineToConsole(ConsoleColor.Gray); } // 2. Create docfx.json var path = Path.Combine(outputFolder ?? string.Empty, ConfigName); SaveConfigFile(path, config); $"Created config file {TypeForwardedToStringExtension.ToDisplayPath(path)}".WriteLineToConsole(ConsoleColor.Gray); $"Successfully generated default docfx project to {TypeForwardedToStringExtension.ToDisplayPath(outputFolder)}".WriteLineToConsole(ConsoleColor.Green); "Please run:".WriteLineToConsole(ConsoleColor.Gray); $"\tdocfx \"{TypeForwardedToStringExtension.ToDisplayPath(path)}\" --serve".WriteLineToConsole(ConsoleColor.White); "To generate a default docfx website.".WriteLineToConsole(ConsoleColor.Gray); }
private Stream GetResourceStreamCore(string name) { // zip entry is case sensitive // incase relative path is combined by backslash \ return(_zipped.GetEntry(TypeForwardedToStringExtension.ToNormalizedPath(name.Trim()))?.Open()); }