[runtime] Disable some tests in full-aot mode which cannot be AOTed because of type...
[mono.git] / mcs / tools / mdoc / Mono.Documentation / webdoc.cs
index 57179978208fa069b299f4b049d10b362866d5f8..75d65a244b05105fd3f9fae787a0eca2b0d17166 100644 (file)
@@ -33,8 +33,11 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Web;
+using System.Xml.Linq;
 
 using Monodoc;
+using Monodoc.Generators;
+using Monodoc.Caches;
 using Mono.Documentation;
 
 using Mono.Options;
@@ -46,52 +49,105 @@ namespace Mono.Documentation
 {
        public class MDocExportWebdocHtml : MDocCommand
        {
+               class Options {
+                       public Dictionary<string, List<string>> Formats = new Dictionary<string, List<string>>();
+                       public List<string> Sources = new List<string>();
+                       public bool UseSystemSources = true;
+                       public bool ForceUpdate = false;
+                       public string OutputDirectory = null;
+               }
+
                public override void Run (IEnumerable<string> args)
                {
-                       string dir = null;
-                       bool forceUpdate = false;
+                       var opts = new Options ();
+                       var formatOptions = MDocAssembler.CreateFormatOptions (this, opts.Formats);
                        var options = new OptionSet () {
                                { "force-update",
                                        "Always generate new files.  If not specified, will only generate " +
                                        "files if the write time of the output directory is older than the " +
                                        "write time of the source .tree/.zip files.",
-                                       v => forceUpdate = v != null },
+                                       v => opts.ForceUpdate = v != null },
+                               formatOptions [0],
+                               formatOptions [1],
                                { "o|out=",
-                                       "The {PREFIX} to place the generated files and directories.  " + 
+                                       "The {PREFIX} to place the generated files and directories.  " +
                                        "Default: \"`dirname FILE`/cache/\".\n" +
-                                       "Underneath {PREFIX}, `basename FILE .tree` directories will be " + 
+                                       "Underneath {PREFIX}, `basename FILE .tree` directories will be " +
                                        "created which will contain the pre-generated HTML content.",
-                                       v => dir = v },
+                                       v => opts.OutputDirectory = v },
+                               { "r=",
+                                       "A {SOURCE} file to use for reference purposes.\n" +
+                                       "Extension methods are searched for among all {SOURCE}s which are referenced.\n" +
+                                       "This option may be specified multiple times.",
+                                       v => opts.Sources.Add (v) },
+                               { "use-system-sources",
+                                       "Use the system-wide .source files for reference purposes. " +
+                                       "Default is " + (opts.UseSystemSources ? "enabled" : "disabled") + ".",
+                                       v => opts.UseSystemSources = v != null },
                        };
-                       List<string> files = Parse (options, args, "export-html-webdoc", 
+                       Parse (options, args, "export-html-webdoc",
                                        "[OPTIONS]+ FILES",
                                        "Export mdoc documentation within FILES to HTML for use by ASP.NET webdoc.\n\n" +
-                                       "FILES are .tree or .zip files as produced by 'mdoc assemble'.");
-                       if (files == null)
-                               return;
-                       if (files.Count == 0)
+                                       "FILES are .tree or .zip files as produced by 'mdoc assemble', or .source files\n" +
+                                       "which reference .tree and .zip files produced by 'mdoc assemble'.\n\n" +
+                                       "See mdoc(5) or mdoc-assemble(1) for information about the .source file format.");
+                       if (opts.Formats.Values.All (files => files.Count == 0))
                                Error ("No files specified.");
-                       HelpSource.use_css = true;
-                       HelpSource.FullHtml = false;
-                       SettingsHandler.Settings.EnableEditing = false;
-                       foreach (var basePath in 
-                                       files.Select (f => 
+                       ProcessSources (opts);
+                       foreach (var p in opts.Formats)
+                               ProcessFiles (opts, p.Key, p.Value);
+               }
+
+               void ProcessSources (Options opts)
+               {
+                       foreach (var p in opts.Formats) {
+                               var files = p.Value;
+                               foreach (var f in files.Where (f => f.EndsWith (".source")).ToList ()) {
+                                       files.Remove (f);
+                                       foreach (var tfi in GetTreeFilesFromSource (f)) {
+                                               List<string> treeFiles;
+                                               if (!opts.Formats.TryGetValue (tfi.Key, out treeFiles))
+                                                       opts.Formats.Add (tfi.Key, treeFiles = new List<string> ());
+                                               treeFiles.Add (tfi.Value);
+                                       }
+                               }
+                       }
+               }
+
+               IEnumerable<KeyValuePair<string, string>> GetTreeFilesFromSource (string sourceFile)
+               {
+                       try {
+                               var source = XElement.Load (sourceFile);
+                               return source.Descendants ("source")
+                                       .Select (e => new KeyValuePair<string, string>(e.Attribute ("provider").Value,
+                                                               Path.Combine (Path.GetDirectoryName (sourceFile), e.Attribute ("basefile").Value + ".tree")));
+                       }
+                       catch (Exception e) {
+                               Message (TraceLevel.Error, "mdoc: error parsing file {0}: {1}", sourceFile, e.Message);
+                               return new KeyValuePair<string, string>[0];
+                       }
+               }
+
+               void ProcessFiles (Options opts, string format, List<string> files)
+               {
+                       foreach (var basePath in
+                                       files.Select (f =>
                                                        Path.Combine (Path.GetDirectoryName (f), Path.GetFileNameWithoutExtension (f)))
                                        .Distinct ()) {
                                string treeFile = basePath + ".tree";
                                string zipFile  = basePath + ".zip";
                                if (!Exists (treeFile) || !Exists (zipFile))
                                        continue;
-                               string outDir = dir != null 
-                                       ? Path.Combine (dir, Path.GetFileName (basePath))
+                               string outDir = opts.OutputDirectory != null
+                                       ? Path.Combine (opts.OutputDirectory, Path.GetFileName (basePath))
                                        : XmlDocUtils.GetCacheDirectory (basePath);
-                               if (!forceUpdate && Directory.Exists (outDir) &&
+                               if (!opts.ForceUpdate && Directory.Exists (outDir) &&
                                                        MaxWriteTime (treeFile, zipFile) < Directory.GetLastWriteTime (outDir))
                                        continue;
                                Message (TraceLevel.Warning, "Processing files: {0}, {1}", treeFile, zipFile);
                                Directory.CreateDirectory (outDir);
                                ExtractZipFile (zipFile, outDir);
-                               GenerateCache (basePath, treeFile, outDir);
+                               GenerateCache (opts, basePath, format, outDir);
                        }
                }
 
@@ -123,32 +179,31 @@ namespace Mono.Documentation
                        }
                }
 
-               void GenerateCache (string basePath, string treeFile, string outDir)
+               void GenerateCache (Options opts, string basePath, string format, string outDir)
                {
-                       Tree tree = new Tree (null, treeFile);
-                       RootTree docRoot = RootTree.LoadTree ();
-                       string helpSourceName = Path.GetFileName (basePath);
-                       HelpSource hs = docRoot.HelpSources.Cast<HelpSource> ()
-                               .FirstOrDefault (h => h.Name == helpSourceName);
+                       var hs = RootTree.GetHelpSource (format, basePath);
                        if (hs == null) {
-                               throw new Exception ("Only installed .tree and .zip files are supported.");
+                               Error ("Unable to find a HelpSource for provider '{0}' and file '{1}.tree'.", format, basePath);
+                       }
+                       var tree = hs.Tree;
+                       RootTree docRoot = null;
+                       if (!opts.UseSystemSources)
+                               docRoot = RootTree.LoadTree (null, null, opts.Sources);
+                       else {
+                               docRoot = RootTree.LoadTree ();
+                               foreach (var source in opts.Sources)
+                                       docRoot.AddSourceFile (source);
                        }
-                       foreach (Node node in tree.TraverseDepthFirst<Node, Node> (t => t, t => t.Nodes.Cast<Node> ())) {
-                               var url = node.URL;
+                       hs.RootTree = docRoot;
+                       var generator = new HtmlGenerator (new NullCache ());
+                       foreach (Node node in tree.RootNode.TraverseDepthFirst<Node, Node> (t => t, t => t.ChildNodes)) {
+                               var url = node.PublicUrl;
                                Message (TraceLevel.Info, "\tProcessing URL: {0}", url);
                                if (string.IsNullOrEmpty (url))
                                        continue;
                                var file = XmlDocUtils.GetCachedFileName (outDir, url);
                                using (var o = File.AppendText (file)) {
-                                       Node _;
-                                       // Sometimes the HelpSource won't directly support a url.
-                                       // Case in point: the Tree will contain N:Enter.Namespace.Here nodes
-                                       // which aren't supported by HelpSource.GetText.
-                                       // If this happens, docRoot.RenderUrl() works.
-                                       // (And no, we can't always use docRoot.RenderUrl() for URLs like
-                                       // "ecma:0#Foo/", as that'll just grab the 0th stream contents from
-                                       // the first EcmaHelpSource found...
-                                       string contents = hs.GetText (url, out _) ?? docRoot.RenderUrl (url, out _);
+                                       string contents = docRoot.RenderUrl (url, generator, hs);
                                        o.Write (contents);
                                }
                        }