Skip to content

Commit f11958f

Browse files
authored
fix: docfx download command behaviors (#9721)
* fix: docfx download command behaviors * chore: add logics to set baseurl if not exists. and resolve relative href to absolute
1 parent 263cf10 commit f11958f

File tree

5 files changed

+60
-74
lines changed

5 files changed

+60
-74
lines changed

src/Docfx.Build/XRefMaps/XRefArchiveBuilder.cs

Lines changed: 22 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public async Task<bool> DownloadAsync(Uri uri, string outputFile)
2424
try
2525
{
2626
using var xa = XRefArchive.Open(outputFile, XRefArchiveMode.Create);
27-
await DownloadCoreAsync(uri, xa, true);
27+
await DownloadCoreAsync(uri, xa);
2828
}
2929
catch (Exception ex)
3030
{
@@ -36,88 +36,42 @@ public async Task<bool> DownloadAsync(Uri uri, string outputFile)
3636
}
3737
}
3838

39-
private async Task<string> DownloadCoreAsync(Uri uri, XRefArchive xa, bool isMajor)
39+
private async Task<string> DownloadCoreAsync(Uri uri, XRefArchive xa)
4040
{
4141
IXRefContainer container;
4242
container = await _downloader.DownloadAsync(uri);
4343
if (container is not XRefMap map)
4444
{
45-
// not support download an xref archive, or reference to an xref archive
45+
// XRefArchive is not supported by `docfx download`.
46+
Logger.LogWarning($"Download an xref archive, or reference to an xref archive is not supported. URI: {uri}");
4647
return null;
4748
}
48-
if (map.Redirections?.Count > 0)
49-
{
50-
await RewriteRedirections(uri, xa, map);
51-
}
52-
if (map.References?.Count > 0 && map.HrefUpdated != true)
53-
{
54-
if (string.IsNullOrEmpty(map.BaseUrl))
55-
{
56-
XRefMapDownloader.UpdateHref(map, uri);
57-
}
58-
}
59-
lock (_syncRoot)
60-
{
61-
if (isMajor)
62-
{
63-
return xa.CreateMajor(map);
64-
}
65-
else
66-
{
67-
return xa.CreateMinor(map, GetNames(uri, map));
68-
}
69-
}
70-
}
7149

72-
private static IEnumerable<string> GetNames(Uri uri, XRefMap map)
73-
{
74-
var name = uri.Segments.LastOrDefault();
75-
yield return name;
76-
if (map.References?.Count > 0)
50+
// If BaseUrl is not set. Use xrefmap file download url as basePath.
51+
if (string.IsNullOrEmpty(map.BaseUrl))
7752
{
78-
yield return map.References[0].Uid;
53+
var baseUrl = uri.GetLeftPart(UriPartial.Path);
54+
baseUrl = baseUrl.Substring(0, baseUrl.LastIndexOf('/') + 1);
55+
map.BaseUrl = baseUrl;
56+
map.UpdateHref(new Uri(baseUrl)); // Update hrefs from relative to absolute url.
57+
map.HrefUpdated = null; // Don't save this flag for downloaded XRefMap.
7958
}
80-
}
81-
82-
#region Rewrite redirections
8359

84-
private async Task<List<XRefMapRedirection>> RewriteRedirections(Uri uri, XRefArchive xa, XRefMap map) =>
85-
(from list in
86-
await Task.WhenAll(
87-
from r in map.Redirections
88-
where !string.IsNullOrEmpty(r.Href)
89-
group r by r.Href into g
90-
let href = GetHrefUri(uri, g.Key)
91-
where href != null
92-
select RewriteRedirectionsCore(g.ToList(), href, xa))
93-
from r in list
94-
orderby (r.UidPrefix ?? string.Empty).Length descending, (r.UidPrefix ?? string.Empty)
95-
select r).ToList();
96-
97-
private async Task<List<XRefMapRedirection>> RewriteRedirectionsCore(List<XRefMapRedirection> redirections, Uri uri, XRefArchive xa)
98-
{
99-
var fileRef = await DownloadCoreAsync(uri, xa, false);
100-
if (fileRef == null)
60+
// Enforce XRefMap's references are sorted by uid.
61+
// Note:
62+
// Sort is not needed if `map.Sorted == true`.
63+
// But there are some xrefmap files that is not propery sorted by using InvariantCulture.
64+
// (e.g. Unity xrefmap that maintained by community)
65+
if (map.References != null && map.References.Count > 0)
10166
{
102-
return new List<XRefMapRedirection>();
67+
map.References.Sort(XRefSpecUidComparer.Instance);
68+
map.Sorted = true;
10369
}
104-
return (from r in redirections
105-
select new XRefMapRedirection { UidPrefix = r.UidPrefix, Href = fileRef }).ToList();
106-
}
10770

108-
private static Uri GetHrefUri(Uri uri, string href)
109-
{
110-
if (!Uri.TryCreate(href, UriKind.RelativeOrAbsolute, out Uri hrefUri))
111-
{
112-
Logger.LogWarning($"Invalid redirection href: {href}.");
113-
return null;
114-
}
115-
if (!hrefUri.IsAbsoluteUri)
71+
// Write XRefMap content to `xrefmap.yml`.
72+
lock (_syncRoot)
11673
{
117-
hrefUri = new Uri(uri, hrefUri);
74+
return xa.CreateMajor(map);
11875
}
119-
return hrefUri;
12076
}
121-
122-
#endregion
12377
}

src/Docfx.Build/XRefMaps/XRefMap.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,49 @@
1010

1111
namespace Docfx.Build.Engine;
1212

13+
/// <summary>
14+
/// Xrefmap.
15+
/// </summary>
1316
public class XRefMap : IXRefContainer
1417
{
18+
/// <summary>
19+
/// Indicate <see cref="References"/> are sorted by <see cref="XRefSpec.Uid"/> with or not.
20+
/// </summary>
1521
[YamlMember(Alias = "sorted")]
1622
[JsonProperty("sorted")]
1723
[JsonPropertyName("sorted")]
1824
public bool? Sorted { get; set; }
1925

26+
/// <summary>
27+
/// Indicate href links are updated or not.
28+
/// </summary>
2029
[YamlMember(Alias = "hrefUpdated")]
2130
[JsonProperty("hrefUpdated")]
2231
[JsonPropertyName("hrefUpdated")]
2332
public bool? HrefUpdated { get; set; }
2433

34+
/// <summary>
35+
/// Base url. It's used when href is specified as relative url.
36+
/// </summary>
2537
[YamlMember(Alias = "baseUrl")]
2638
[JsonProperty("baseUrl")]
2739
[JsonPropertyName("baseUrl")]
2840
public string BaseUrl { get; set; }
2941

42+
/// <summary>
43+
/// List of <see href="XRefMapRedirection"/> settings.
44+
/// </summary>
3045
[YamlMember(Alias = "redirections")]
3146
[JsonProperty("redirections")]
3247
[JsonPropertyName("redirections")]
3348
public List<XRefMapRedirection> Redirections { get; set; }
3449

50+
/// <summary>
51+
/// List of <see href="XRefSpec"/>.
52+
/// </summary>
53+
/// <remarks>
54+
/// If <see cref="Sorted"/> is true. XRefSpec items must be sorted by <see cref="XRefSpec.Uid"/> with InvariantCulture.
55+
/// </remarks>
3556
[YamlMember(Alias = "references")]
3657
[JsonProperty("references")]
3758
[JsonPropertyName("references")]

src/Docfx.Build/XRefMaps/XRefMapDownloader.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private IXRefContainer ReadLocalFileWithFallback(Uri uri)
8181
/// </remarks>
8282
protected virtual async Task<IXRefContainer> DownloadBySchemeAsync(Uri uri)
8383
{
84-
IXRefContainer result = null;
84+
IXRefContainer result;
8585
if (uri.IsFile)
8686
{
8787
result = DownloadFromLocal(uri);
@@ -123,8 +123,6 @@ private static IXRefContainer ReadLocalFile(string filePath)
123123
protected static async Task<XRefMap> DownloadFromWebAsync(Uri uri)
124124
{
125125
Logger.LogVerbose($"Reading from web: {uri.OriginalString}");
126-
var baseUrl = uri.GetLeftPart(UriPartial.Path);
127-
baseUrl = baseUrl.Substring(0, baseUrl.LastIndexOf('/') + 1);
128126

129127
using var httpClient = new HttpClient(new HttpClientHandler()
130128
{
@@ -138,8 +136,7 @@ protected static async Task<XRefMap> DownloadFromWebAsync(Uri uri)
138136
using var stream = await httpClient.GetStreamAsync(uri);
139137
using var sr = new StreamReader(stream, bufferSize: 81920); // Default :1024 byte
140138
var map = YamlUtility.Deserialize<XRefMap>(sr);
141-
map.BaseUrl = baseUrl;
142-
UpdateHref(map, null);
139+
143140
return map;
144141
}
145142

src/docfx/Properties/launchSettings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@
4242
"environmentVariables": {
4343
}
4444
},
45+
// Run `docfx download` command.
46+
"docfx download": {
47+
"commandName": "Project",
48+
"commandLineArgs": "download xrefmap.zip --xref https://github.com/dotnet/docfx/raw/main/.xrefmap.json",
49+
"workingDirectory": ".",
50+
"environmentVariables": {
51+
}
52+
},
4553
// Run `docfx` command.
4654
"docfx": {
4755
"commandName": "Project",

test/Docfx.Build.Tests/XRefArchiveBuilderTest.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,18 @@ public async Task TestDownload()
1414
const string ZipFile = "test.zip";
1515
var builder = new XRefArchiveBuilder();
1616

17+
// Download following xrefmap.yml content.
18+
// ```
19+
// ### YamlMime:XRefMap
20+
// sorted: true
21+
// references: []
22+
// ```
1723
Assert.True(await builder.DownloadAsync(new Uri("http://dotnet.github.io/docfx/xrefmap.yml"), ZipFile));
1824

1925
using (var xar = XRefArchive.Open(ZipFile, XRefArchiveMode.Read))
2026
{
2127
var map = xar.GetMajor();
22-
Assert.True(map.HrefUpdated);
28+
Assert.Null(map.HrefUpdated);
2329
Assert.True(map.Sorted);
2430
Assert.NotNull(map.References);
2531
Assert.Null(map.Redirections);

0 commit comments

Comments
 (0)