-
Notifications
You must be signed in to change notification settings - Fork 638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DYN-4687 - docs browser and docs generator produce .md files with names that are too long. #13588
Changes from all commits
20d2f84
0e0ffad
380bc8f
7dd287e
5663022
a06ce38
347c25a
b09be40
866bab9
574c9d8
3d312ce
ebb2032
76477a1
1ba1c6c
c69da4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<!--- Autodesk.DesignScript.Geometry.TSpline.TSplineSurface.ByBoxLengths(origin, width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) ---> | ||
<!--- HNVVP7HSR2IM5H5AFWWLLJBXSX2WTG5FEWESXLGORW2CL2CG7C4Q ---> | ||
## ByBoxLengths(origin, width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) - Documentation | ||
This documentation file is auto generated by NodeDocumentationMarkdownGenerator, Version=2.14.0.3986, Culture=neutral, PublicKeyToken=null. | ||
|
||
For more information about adding documentation to nodes see https://github.com/DynamoDS/Dynamo/wiki/Create-and-Add-Custom-Documentation-to-Nodes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<!--- Autodesk.DesignScript.Geometry.TSpline.TSplineSurface.ByBoxLengths(cs, width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) | ||
<!--- VFK33PBU2AHJIHDOMW3NS2YJNGRTQADZ2RUGALOLEWRXK4DM4DTA ---> | ||
## ByBoxLengths(cs, width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) - Documentation | ||
This documentation file is auto generated by NodeDocumentationMarkdownGenerator, Version=2.14.0.3986, Culture=neutral, PublicKeyToken=null. | ||
|
||
For more information about adding documentation to nodes see https://github.com/DynamoDS/Dynamo/wiki/Create-and-Add-Custom-Documentation-to-Nodes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<!--- Autodesk.DesignScript.Geometry.TSpline.TSplineSurface.ByBoxLengths(width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) ---> | ||
<!--- WN6BWNG6A6KOPFMMRBHLV7XBOOEGXTSO5I5FZXHKKUG5YO6MNNYA ---> | ||
## ByBoxLengths(width, length, height, xSpans, ySpans, zSpans, symmetry, inSmoothMode) - Documentation | ||
This documentation file is auto generated by NodeDocumentationMarkdownGenerator, Version=2.14.0.3986, Culture=neutral, PublicKeyToken=null. | ||
|
||
For more information about adding documentation to nodes see https://github.com/DynamoDS/Dynamo/wiki/Create-and-Add-Custom-Documentation-to-Nodes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using System.Text; | ||
|
||
namespace Dynamo.Utilities | ||
{ | ||
internal class Hash | ||
{ | ||
/// <summary> | ||
/// Get the hash value | ||
/// </summary> | ||
/// <param name="bytes">input as a byte array</param> | ||
/// <returns>hash as a byte array</returns> | ||
internal static byte[] GetHash(byte[] bytes) | ||
{ | ||
using (var hashAlgorithm = SHA256.Create()) | ||
{ | ||
return hashAlgorithm.ComputeHash(bytes); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Get the hash value | ||
/// </summary> | ||
/// <param name="str">input as a string</param> | ||
/// <returns>hash as a byte array</returns> | ||
internal static byte[] GetHashFromString(string str) | ||
{ | ||
var bytes = Encoding.UTF8.GetBytes(str); | ||
return GetHash(bytes); | ||
} | ||
|
||
/// <summary> | ||
/// Get a valid filename for a hash | ||
/// </summary> | ||
/// <param name="bytes">hash as a byte array</param> | ||
/// <returns>hash as a valid filename string</returns> | ||
internal static string GetFilenameFromHash(byte[] bytes) | ||
{ | ||
return ToBase32String(bytes); | ||
} | ||
|
||
/// <summary> | ||
/// Get hash file name | ||
/// </summary> | ||
/// <param name="str">inout as a string</param> | ||
/// <returns>hash as a valid filename</returns> | ||
internal static string GetHashFilenameFromString(string str) | ||
{ | ||
var hash = GetHashFromString(str); | ||
return GetFilenameFromHash(hash); | ||
} | ||
|
||
/// <summary> | ||
/// /// The different characters allowed in Base32 encoding. | ||
/// </summary> | ||
/// <remarks> | ||
/// This is a 32-character subset of the twenty-six letters A–Z and six digits 2–7. | ||
/// <see cref="https://en.wikipedia.org/wiki/Base32" /> | ||
/// </remarks> | ||
internal static string Base32AllowedCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; | ||
|
||
/// <summary> /// Converts a byte array into a Base32 string. | ||
/// </summary> | ||
/// <param name="input">The string to convert to Base32.</param> | ||
/// <param name="addPadding">Whether or not to add RFC3548 '='-padding to the string.</param> | ||
/// <returns>A Base32 string.</returns> | ||
/// <remarks> | ||
/// https://tools.ietf.org/html/rfc3548#section-2.2 indicates padding MUST be added unless the reference to the RFC tells us otherswise. | ||
/// https://github.com/google/google-authenticator/wiki/Key-Uri-Format indicates that padding SHOULD be omitted. | ||
/// To meet both requirements, you can omit padding when required. | ||
/// </remarks> | ||
internal static string ToBase32String(byte[] input, bool addPadding = false) | ||
{ | ||
if (input == null || input.Length == 0) | ||
{ | ||
return string.Empty; | ||
} | ||
|
||
var bits = input.Select(b => Convert.ToString(b, 2).PadLeft(8, '0')).Aggregate((a, b) => a + b) | ||
.PadRight((int)(Math.Ceiling((input.Length * 8) / 5d) * 5), '0'); | ||
var result = Enumerable.Range(0, bits.Length / 5) | ||
.Select(i => Base32AllowedCharacters.Substring(Convert.ToInt32(bits.Substring(i * 5, 5), 2), 1)) | ||
.Aggregate((a, b) => a + b); | ||
|
||
if (addPadding) | ||
{ | ||
result = result.PadRight((int)(Math.Ceiling(result.Length / 8d) * 8), '='); | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System; | ||
using System.IO; | ||
using System.Linq; | ||
using NodeDocumentationMarkdownGenerator.Verbs; | ||
|
||
namespace NodeDocumentationMarkdownGenerator.Commands | ||
{ | ||
internal static class RenameCommand | ||
{ | ||
internal static void HandleRename(RenameOptions opts) | ||
{ | ||
if (opts.InputMdFile is null && opts.InputMdDirectory != null) | ||
{ | ||
RenameDirectory(opts.InputMdDirectory, opts.MaxLength); | ||
aparajit-pratap marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
else if (opts.InputMdFile != null && opts.InputMdDirectory is null) | ||
{ | ||
RenameFile(opts.InputMdFile); | ||
} | ||
else | ||
{ | ||
Console.WriteLine("Invalid options: You can rename a single file using the file option\nor rename multiple files in a directory (if they are longer than max length)\nusing the directory option"); | ||
} | ||
} | ||
|
||
private static void RenameFile(string file) | ||
{ | ||
var extension = Path.GetExtension(file); | ||
if (!extension.Equals(".md", StringComparison.InvariantCultureIgnoreCase)) | ||
{ | ||
Console.WriteLine($"Can only rename MD files: {file}"); | ||
return; | ||
} | ||
|
||
if (!File.Exists(file)) | ||
{ | ||
Console.WriteLine($"File not found: {file}"); | ||
return; | ||
} | ||
|
||
var baseName = Path.GetFileNameWithoutExtension(file); | ||
var shortName = Dynamo.Utilities.Hash.GetHashFilenameFromString(baseName); | ||
|
||
RenameFile(file, baseName, shortName); | ||
} | ||
|
||
private static void RenameFile(string file, string baseName, string shortName) | ||
{ | ||
var content = File.ReadAllText(file); | ||
content = content.Replace(baseName, shortName); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saving the hashed name in the file contents as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nop, only the original name. But I could easily do it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I meant to ask what is the purpose of line 50 if it's not necessary to save the hashed name in the file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is for replacing the base name of all support files (images and example files etc). Sorry, I misunderstood your question. |
||
var path = Path.GetDirectoryName(file); | ||
var newFile = Path.Combine(path, shortName + ".md"); | ||
File.WriteAllText(newFile, $"<!--- {baseName} --->\n<!--- {shortName} --->\n" + content); | ||
File.Delete(file); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we need to expect permission issues? only devs will run this command ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will get exceptions if that is the case and those are catched and reported at a higher level in the handle function for the rename command. Yes, this is an internal tool. It is not shipped. |
||
|
||
var allSupportFiles = Directory.GetFiles(path, baseName + ".*", SearchOption.TopDirectoryOnly) | ||
.Select(x => new FileInfo(x)).ToList(); | ||
allSupportFiles.AddRange(Directory.GetFiles(path, baseName + "_img.*", SearchOption.TopDirectoryOnly) | ||
.Select(x => new FileInfo(x)).ToList()); | ||
|
||
foreach (var supportFile in allSupportFiles) | ||
{ | ||
var newName = Path.Combine(supportFile.DirectoryName, | ||
supportFile.Name.Replace(baseName, shortName)); | ||
supportFile.MoveTo(newName); | ||
} | ||
} | ||
|
||
private static void RenameDirectory(string directory, int maxLength) | ||
{ | ||
if (!Directory.Exists(directory)) | ||
{ | ||
Console.WriteLine($"Directory not found: {directory}"); | ||
return; | ||
} | ||
|
||
var allMdFiles = Directory.GetFiles(directory, "*.md", SearchOption.TopDirectoryOnly).Select(x => new FileInfo(x)).ToList(); | ||
|
||
foreach (var mdFile in allMdFiles) | ||
{ | ||
if (mdFile.Name.Length > maxLength) | ||
{ | ||
var baseName = Path.GetFileNameWithoutExtension(mdFile.Name); | ||
var shortName = Dynamo.Utilities.Hash.GetHashFilenameFromString(baseName); | ||
RenameFile(mdFile.FullName, baseName, shortName); | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using CommandLine.Text; | ||
using CommandLine; | ||
using System.Collections.Generic; | ||
|
||
namespace NodeDocumentationMarkdownGenerator.Verbs | ||
{ | ||
[Verb("rename", HelpText = "Renaming utilities for fallback MD files")] | ||
internal class RenameOptions | ||
{ | ||
[Option('f', "file", HelpText = "Input MD file. Renames a single MD file including any support files to a shorter length (~56-60 characters) base file name.", Required = false)] | ||
public string InputMdFile { get; set; } | ||
[Option('d', "directory", HelpText = "Input directory. Inspects all MD files in a directory and renames all MD files with a base name longer that maxlength (see below).", Required = false)] | ||
public string InputMdDirectory { get; set; } | ||
[Option('m', "maxlength", HelpText = "Max length of the base file name before renaming to a shorter length (~56-60 characters) base file name.", Required = false, Default = 65)] | ||
public int MaxLength { get; set; } | ||
[Usage(ApplicationAlias = "Dynamo docs generator")] | ||
public static IEnumerable<Example> Examples | ||
{ | ||
get | ||
{ | ||
yield return new Example("Renaming utilities for fallback MD files", new RenameOptions()); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the encoding/decoding logic specific to filenames ? looks pretty generic to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What we get back are guaranteed to work as a file name in all file systems. That's why I named it that way (and used base32).