Merged PR 758421: Add PipProperties to help text. Rename PipFingerprintingSalt to PipFingerprintSalt

- PipProperties made it into the flags.md file but not into buildxl's actual help text. Add it to help text
- Rename PipFingerprintingSalt to drop the "ing" which better aligns with related terminology in BuildXL
- Add platform agnostic support for newlines in help text and generated markdown documentation

Related work items: #2131602
This commit is contained in:
Michael Pysson 2023-12-21 18:50:35 +00:00
Родитель 534d0781f5
Коммит 03bc84fdb7
16 изменённых файлов: 67 добавлений и 45 удалений

Просмотреть файл

@ -178,10 +178,7 @@ This page lists flags that can be used to configure BuildXL.
| PathSetThreshold | The maximum number of visited path sets allowed before switching to an 'augmented' weak fingerprint computed from common dynamically accessed paths. |
| Phase | Specifies the phase until which {ShortProductName} runs. Allowed values are None (no phase is run), Parse (run until parsing is done), Evaluate (run until value evaluation is done), Schedule (run until scheduling is done), Execute (run until execution is done). Default is Execute. |
| PinCachedOutputs | Indicates whether outputs should be pinned in CAS for cached pips. Defaults to on. |
| PipProperty | Enforces specific properties to the pip. The list of properties that are permitted: PipFingerprintingSalt, ForcedCacheMiss, and EnableVerboseProcessLogging. These properties should be passed along with the semi-stable hash of the pip using /pipProperty flag. Example: /pipProperty:Pip232325435435[PipFingerprintingSalt=TooSalty, ForcedCacheMiss, EnableVerboseProcessLogging]. |
| PipProperty_EnableVerboseProcessLogging | Enables verbose sandbox logging for specific pips based on their formatted semistable hashes. This is tantamount to switching /logObservedFileAccesses and /logProcesses for these pips, and also enabling verbose debug logging in the sandbox. The pip semi-stable hash along with the EnableVerboseProcessLogging flag might be specified using the /pipProperty flag .Example: /pipProperty:Pip232325435435[EnableVerboseProcessLogging] /pipProperty:Pip435345345345[EnableVerboseProcessLogging]. |
| PipProperty_ForcedCacheMiss | Forces a pip to be a cache miss in the build, independently of the artificial cache miss options(see /injectCacheMisses). The pip semi-stable hash along with the ForcedCacheMiss flag needs to be specified using the flag /pipProperty. Example: /pipProperty:Pip232325435435[ForcedCacheMiss] /pipProperty:Pip342343423423[ForcedCacheMiss]. |
| PipProperty_PipFingerprintingSalt | Enables fingerprint salting for specific pips. The pip semi-stable hash along with the the PipFingerprintingSalt flag and the specific fingerprint salt value needs to be specified using the /pipPropertyFlag. If the specific value ``*`` is given as the salt value then a random salt value is generated everytime and used for the weak-fingerprint computation of the pip. Example: /pipProperty:Pip232325435435[PipFingerprintingSalt=TooSalty] /pipProperty:Pip4354554[PipFingerprintingSalt=``*``]. |
| PipProperty | Sets execution behaviors for a pip. Supported properties: <br> PipFingerprintSalt - adds a pip specific salt value or '*' for a random salt. Ex: /pipProperty:Pip4354554[PipFingerprintingSalt=*] <br> EnableVerboseProcessLogging - Enables verbose sandbox logging for specific pips. This is equivalent to switching /logObservedFileAccesses and /logProcesses for these pips, and also enabling verbose debug logging in the sandbox. Example: /pipProperty:Pip232325435435[EnableVerboseProcessLogging] |
| PipTimeout | How long to wait before terminating individual processes, in milliseconds. Setting this value will only have an effect if no other timeout is specified for a process. |
| PipTimeoutMultiplier | Multiplier applied to the final timeout for individual processes. Setting a multiplier greater than one will increase the timeout accordingly for all pips, even those with an explicit non-default timeout set. |
| PipWarningTimeout | After how much time to issue a warning that an individual process runs too long, in milliseconds. Setting this value will only have an effect if no other timeout is specified for a process. |

Просмотреть файл

@ -20,7 +20,7 @@ namespace BuildXL
/// Parse pipProperty argument and map pipIds with the respective pipProperties.
/// </summary>
/// <remarks>
/// /pipProperty:Pip232325435435[PipFingerprintingSalt=TooSalty,ForcedCacheMiss,Debug_EnableVerboseProcessLogging]
/// /pipProperty:Pip232325435435[PipFingerprintSalt=TooSalty,ForcedCacheMiss,Debug_EnableVerboseProcessLogging]
/// </remarks>
public static void ParsePipPropertyArg(CommandLineUtilities.Option opt, EngineConfiguration engineConfiguration)
{
@ -73,7 +73,7 @@ namespace BuildXL
{
throw CommandLineUtilities.Error(Strings.Args_PipProperty_InvalidProperty, pipProperty);
}
// Ex: /pipFingerprintingSalt=tooSalty
// Ex: /pipFingerprintSalt=tooSalty
// propertyValue captures the tooSalty and pipPropertyToBeChecked captures propertyName
pipPropertyToBeChecked = property[0];
propertyValue = property[1];

Просмотреть файл

@ -923,6 +923,12 @@ namespace BuildXL
HelpLevel.Verbose
);
hw.WriteOption(
"/PipProperty:[PipId:[PropertyAndValue]]",
Strings.HelpText_DisplayHelp_PipProperty,
HelpLevel.Verbose
);
#endregion
hw.WriteBanner(

Просмотреть файл

@ -1166,19 +1166,10 @@ Example: ad2d42d2ec5d2ca0c0b7ad65402d07c7ef40b91e</value>
<value>When set to true, it enables the execution permission for the root process of process pips in Linux builds. Defaults to true.</value>
</data>
<data name="HelpText_DisplayHelp_PipProperty" xml:space="preserve">
<value>Enforces specific properties to the pip. The list of properties that are permitted: PipFingerprintingSalt, ForcedCacheMiss, and EnableVerboseProcessLogging. These properties should be passed along with the semi-stable hash of the pip using /pipProperty flag. Example: /pipProperty:Pip232325435435[PipFingerprintingSalt=TooSalty, ForcedCacheMiss, EnableVerboseProcessLogging].</value>
</data>
<data name="HelpText_DisplayHelp_PipProperty_ForcedCacheMiss" xml:space="preserve">
<value>Forces a pip to be a cache miss in the build, independently of the artificial cache miss options(see /injectCacheMisses). The pip semi-stable hash along with the ForcedCacheMiss flag needs to be specified using the flag /pipProperty. Example: /pipProperty:Pip232325435435[ForcedCacheMiss] /pipProperty:Pip342343423423[ForcedCacheMiss].</value>
</data>
<data name="HelpText_DisplayHelp_PipProperty_EnableVerboseProcessLogging" xml:space="preserve">
<value>Enables verbose sandbox logging for specific pips based on their formatted semistable hashes. This is tantamount to switching /logObservedFileAccesses and /logProcesses for these pips, and also enabling verbose debug logging in the sandbox. The pip semi-stable hash along with the EnableVerboseProcessLogging flag might be specified using the /pipProperty flag .Example: /pipProperty:Pip232325435435[EnableVerboseProcessLogging] /pipProperty:Pip435345345345[EnableVerboseProcessLogging].</value>
</data>
<data name="HelpText_DisplayHelp_PipProperty_PipFingerprintingSalt" xml:space="preserve">
<value>Enables fingerprint salting for specific pips. The pip semi-stable hash along with the the PipFingerprintingSalt flag and the specific fingerprint salt value needs to be specified using the /pipPropertyFlag. If the specific value ``*`` is given as the salt value then a random salt value is generated everytime and used for the weak-fingerprint computation of the pip. Example: /pipProperty:Pip232325435435[PipFingerprintingSalt=TooSalty] /pipProperty:Pip4354554[PipFingerprintingSalt=``*``].</value>
<value>Sets execution behaviors for a pip. Supported properties: \n PipFingerprintSalt - adds a pip specific salt value or '*' for a random salt. Ex: /pipProperty:Pip4354554[PipFingerprintingSalt=*] \n EnableVerboseProcessLogging - Enables verbose sandbox logging for specific pips. This is equivalent to switching /logObservedFileAccesses and /logProcesses for these pips, and also enabling verbose debug logging in the sandbox. Example: /pipProperty:Pip232325435435[EnableVerboseProcessLogging]</value>
</data>
<data name="Args_PipProperty_InvalidProperty" xml:space="preserve">
<value>The specified property '{0}' in the /pipProperty argument is not to be enforced on specific pips.</value>
<value>The specified property '{0}' in the /pipProperty argument is not a valid property.</value>
</data>
<data name="Args_PipProperty_FailedToParsePipProperty" xml:space="preserve">
<value>Failed to parse pip properties passed via /pipProperty argument</value>

Просмотреть файл

@ -203,7 +203,7 @@ namespace BuildXL.Engine
AddFingerprint(topLevelHasher, "ExtraFingerprintSalts", extraFingerprintSalts.CalculatedSaltsFingerprint);
// If the pip has been passed with a specific fingerprint salt, those salt values should be used to see if the graph can be invalidated.
var pipSemiStableHashesAndValues = pipSpecificPropertiesConfig?.RetrievePipSemistableHashesWithValues(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt);
var pipSemiStableHashesAndValues = pipSpecificPropertiesConfig?.RetrievePipSemistableHashesWithValues(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt);
if (pipSemiStableHashesAndValues?.Any() == true)
{
var pipSpecificComputedSalt = string.Join(";", pipSemiStableHashesAndValues.OrderBy(pipSemiStableHashesAndValue => pipSemiStableHashesAndValue.Key)

Просмотреть файл

@ -88,7 +88,7 @@ namespace BuildXL.Scheduler.Graph
directoryProducerFingerprintLookup: null,
extraFingerprintSalts: extraFingerprintSalts,
pathExpander: pathExpander,
pipFingerprintSaltLookup: process => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, process.SemiStableHash))
pipFingerprintSaltLookup: process => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, process.SemiStableHash))
{
FingerprintTextEnabled = configuration.Schedule.LogPipStaticFingerprintTexts
};

Просмотреть файл

@ -1233,7 +1233,7 @@ namespace BuildXL.Scheduler
PipGraph.QueryFileArtifactPipData,
process => m_fileContentManager?.SourceChangeAffectedInputs.GetChangeAffectedInputs(process) ?? CollectionUtilities.EmptyArray<AbsolutePath>(),
pipId => PipGraph.TryGetPipFingerprint(pipId, out var fingerprint) ? fingerprint.Hash : default,
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, process.SemiStableHash));
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, process.SemiStableHash));
m_historicPerfDataTableTask = runningTimeTable;
// Prepare Root Map redirection table. see m_rootMappings comment on why this is happening here.
@ -1402,7 +1402,7 @@ namespace BuildXL.Scheduler
PipGraph.QueryFileArtifactPipData,
process => m_fileContentManager?.SourceChangeAffectedInputs.GetChangeAffectedInputs(process) ?? CollectionUtilities.EmptyArray<AbsolutePath>(),
pipId => PipGraph.TryGetPipFingerprint(pipId, out var fingerprint) ? fingerprint.Hash : default,
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, process.SemiStableHash)),
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, process.SemiStableHash)),
cache,
DirectedGraph,
m_fingerprintStoreCounters,

Просмотреть файл

@ -174,7 +174,7 @@ const combineCopyAndTwo = Transformer.execute({{
Configuration.Engine.PipSpecificPropertyAndValues = new List<PipSpecificPropertyAndValue>
{
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, processPipsInBuild.First().SemiStableHash, "TooSalt"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, processPipsInBuild.First().SemiStableHash, "TooSalt"),
};
var countersPostSaltingPip = Build("Build after Salting");

Просмотреть файл

@ -2345,7 +2345,7 @@ namespace IntegrationTest.BuildXL.Scheduler
[Theory]
[InlineData(PipSpecificPropertiesConfig.PipSpecificProperty.ForcedCacheMiss)]
[InlineData(PipSpecificPropertiesConfig.PipSpecificProperty.EnableVerboseProcessLogging)]
[InlineData(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt)]
[InlineData(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt)]
public void ValidateGetPipIdsForProperty(PipSpecificPropertiesConfig.PipSpecificProperty pipSpecificProperty)
{
var propertiesAndValues = new List<PipSpecificPropertyAndValue>
@ -2353,9 +2353,9 @@ namespace IntegrationTest.BuildXL.Scheduler
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.ForcedCacheMiss, 24 ,null),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.EnableVerboseProcessLogging, 24, null),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.EnableVerboseProcessLogging, 22, null),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, 24 ,"salty"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, 24, "TooSalty"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, 22, "saltLess")
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, 24 ,"salty"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, 24, "TooSalty"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, 22, "saltLess")
};
Configuration.Engine.PipSpecificPropertyAndValues.AddRange(propertiesAndValues);
@ -2387,14 +2387,14 @@ namespace IntegrationTest.BuildXL.Scheduler
}
// Obtain pip property value for a given property and semistablehash.
if (pipSpecificProperty.ToString().Equals("PipFingerprintingSalt"))
if (pipSpecificProperty.ToString().Equals("PipFingerprintSalt"))
{
XAssert.AreEqual(PipSpecificPropertiesConfig.GetPipSpecificPropertyValue(pipSpecificProperty, 24), "TooSalty");
}
}
/// <summary>
/// Ensure that a pip is salted when the salt value is passed via PipFingerprintingSalt flag.
/// Ensure that a pip is salted when the salt value is passed via PipFingerprintSalt flag.
/// This test also runs with IS feature enabled as well. So it covers the IS feature
/// </summary>
[Fact]
@ -2409,11 +2409,11 @@ namespace IntegrationTest.BuildXL.Scheduler
RunScheduler().AssertCacheMiss(pip.PipId);
RunScheduler().AssertCacheHit(pip.PipId);
// Set the pipFingerprintingSalt property value for this pip in the config object.
// Set the pipFingerprintSalt property value for this pip in the config object.
// Once this is passed we expect the pip to have a cache miss.
var propertiesAndValues = new List<PipSpecificPropertyAndValue>
{
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, pip.SemiStableHash, "TooSalted"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, pip.SemiStableHash, "TooSalted"),
};
Configuration.Engine.PipSpecificPropertyAndValues.AddRange(propertiesAndValues);
ResetPipGraphBuilder();
@ -2431,7 +2431,7 @@ namespace IntegrationTest.BuildXL.Scheduler
}
/// <summary>
/// Ensure that a pip is salted when the salt value of "*" is passed via PipFingerprintingSalt flag.
/// Ensure that a pip is salted when the salt value of "*" is passed via PipFingerprintSalt flag.
/// This test also runs with IS feature enabled as well. So it covers the IS feature.
/// </summary>
[Fact]
@ -2446,7 +2446,7 @@ namespace IntegrationTest.BuildXL.Scheduler
RunScheduler().AssertCacheMiss(pip.PipId);
RunScheduler().AssertCacheHit(pip.PipId);
// Set the pipFingerprintingSalt property value for this pip in the config object.
// Set the pipFingerprintSalt property value for this pip in the config object.
// Once this is passed we expect the pip to have a cache miss.
SchedulePipsForSaltValue(pOperations, pip);
SchedulePipsForSaltValue(pOperations, pip);
@ -2469,7 +2469,7 @@ namespace IntegrationTest.BuildXL.Scheduler
{
var propertiesAndValues = new List<PipSpecificPropertyAndValue>
{
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, pip.SemiStableHash, "*"),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, pip.SemiStableHash, "*"),
};
Configuration.Engine.PipSpecificPropertyAndValues.AddRange(propertiesAndValues);
ResetPipGraphBuilder();

Просмотреть файл

@ -810,7 +810,7 @@ namespace Test.BuildXL.Scheduler
{
var result = ProcessWeakFingerprintForPipSpecificSalt(pipFingerprinterType, "*");
// If the pipFingerprintingSaltValue is "*" then we expect the value to be unique everytime.
// If the pipFingerprintSaltValue is "*" then we expect the value to be unique everytime.
var baselineFingerprint1 = result.pipFingerprinter.ComputeWeakFingerprint(result.process, out var fingerprintText1);
var baselineFingerprint2 = result.pipFingerprinter.ComputeWeakFingerprint(result.process, out var fingerprintText2);
XAssert.AreNotEqual(fingerprintText1, fingerprintText2);
@ -825,7 +825,7 @@ namespace Test.BuildXL.Scheduler
// Pass the pip specific fingerprint salt.
var propertiesAndValues = new List<PipSpecificPropertyAndValue>
{
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, process.SemiStableHash, pipSaltValue),
new PipSpecificPropertyAndValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, process.SemiStableHash, pipSaltValue),
};
var pipSpecificPropertiesConfig = new PipSpecificPropertiesConfig(propertiesAndValues);
@ -839,7 +839,7 @@ namespace Test.BuildXL.Scheduler
pathTable,
GetContentHashLookup(executable),
ExtraFingerprintSalts.Default(),
pipFingerprintSaltLookup: p => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, p.SemiStableHash))
pipFingerprintSaltLookup: p => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, p.SemiStableHash))
{
FingerprintTextEnabled = true
};
@ -850,7 +850,7 @@ namespace Test.BuildXL.Scheduler
pipFingerprinter = new PipStaticFingerprinter(
pathTable,
extraFingerprintSalts: ExtraFingerprintSalts.Default(),
pipFingerprintSaltLookup: p => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, p.SemiStableHash))
pipFingerprintSaltLookup: p => pipSpecificPropertiesConfig.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, p.SemiStableHash))
{
FingerprintTextEnabled = true
};

Просмотреть файл

@ -394,10 +394,10 @@ namespace BuildXL.Pips.Graph
fingerprinter.Add(nameof(Process.PreserveOutputsTrustLevel), process.PreserveOutputsTrustLevel);
// If the pip has been passed with a specific fingerprinting salt value then we use it in the computation of weak fingerprint.
var pipFingerprintingSaltValue = m_pipFingerprintSaltLookup(process);
if (!string.IsNullOrEmpty(pipFingerprintingSaltValue))
var pipFingerprintSaltValue = m_pipFingerprintSaltLookup(process);
if (!string.IsNullOrEmpty(pipFingerprintSaltValue))
{
fingerprinter.Add("PipSpecificFingerprintingSalt", pipFingerprintingSaltValue == "*" ? Guid.NewGuid().ToString() : pipFingerprintingSaltValue);
fingerprinter.Add("PipSpecificFingerprintingSalt", pipFingerprintSaltValue == "*" ? Guid.NewGuid().ToString() : pipFingerprintSaltValue);
}
}

Просмотреть файл

@ -224,7 +224,7 @@ namespace BuildXL.Pips.Graph
GetDirectoryProducerFingerprint,
extraFingerprintSalts,
semanticPathExpander,
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintingSalt, process.SemiStableHash))
process => pipSpecificPropertiesConfig?.GetPipSpecificPropertyValue(PipSpecificPropertiesConfig.PipSpecificProperty.PipFingerprintSalt, process.SemiStableHash))
{
FingerprintTextEnabled = configuration.Schedule.LogPipStaticFingerprintTexts
};

Просмотреть файл

@ -71,7 +71,13 @@ namespace BuildXL.ToolSupport
foreach (string word in words)
{
if (m_builder.Length < wrapColumn)
if (word == "\\n")
{
m_writer.WriteLine(m_builder.ToString());
m_builder.Length = 0;
continue;
}
else if (m_builder.Length < wrapColumn)
{
m_builder.Append(' ', wrapColumn - m_builder.Length);
}

Просмотреть файл

@ -135,5 +135,27 @@ namespace Test.BuildXL.ToolSupport
Assert.Equal("Standard"+ Environment.NewLine + "Verbose"+ Environment.NewLine, writer.ToString());
}
}
[Fact]
public void HelpWriterNewlines()
{
// no newline
using (var writer = new StringWriter(CultureInfo.InvariantCulture))
{
HelpWriter hw = new HelpWriter(writer, 50, HelpLevel.Standard);
hw.WriteLine("line 1 line 2", HelpLevel.Standard);
writer.Flush();
XAssert.AreEqual(2, writer.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None).Length);
}
// newline is reflected in length of output
using (var writer = new StringWriter(CultureInfo.InvariantCulture))
{
HelpWriter hw = new HelpWriter(writer, 50, HelpLevel.Standard);
hw.WriteLine("line 1 \\n line 2", HelpLevel.Standard);
writer.Flush();
XAssert.AreEqual(3, writer.ToString().Split(new[] { Environment.NewLine }, StringSplitOptions.None).Length);
}
}
}
}

Просмотреть файл

@ -40,9 +40,9 @@ namespace BuildXL.Utilities
/// <summary>
/// Enables fingerprint salting for specific pips.
/// Ex: /pipProperty:Pip00000[PipFingerprintingSalt=tooSalty]
/// Ex: /pipProperty:Pip00000[PipFingerprintSalt=tooSalty]
/// </summary>
PipFingerprintingSalt = 3
PipFingerprintSalt = 3
}
/// <summary>

Просмотреть файл

@ -47,7 +47,7 @@ foreach ($Data in $HelpText)
if (Should-Output($Data.Item1))
{
$NameStr = $Data.Item1 -replace "HelpText_DisplayHelp_", "";
$Output += "| $($NameStr) | $($Data.Item2) |";
$Output += "| $($NameStr) | $($Data.Item2 -replace "\\n", "<br>") |";
}
}