Merge branch 'feature/msbuild'
This commit is contained in:
Коммит
18cffad542
|
@ -89,7 +89,7 @@ namespace Confuser.Core.Project {
|
||||||
|
|
||||||
if (IsExternal) {
|
if (IsExternal) {
|
||||||
XmlAttribute extAttr = xmlDoc.CreateAttribute("external");
|
XmlAttribute extAttr = xmlDoc.CreateAttribute("external");
|
||||||
extAttr.Value = IsExternal.ToString();
|
extAttr.Value = IsExternal ? "true" : "false";
|
||||||
elem.Attributes.Append(extAttr);
|
elem.Attributes.Append(extAttr);
|
||||||
}
|
}
|
||||||
if (SNKeyPath != null) {
|
if (SNKeyPath != null) {
|
||||||
|
@ -610,4 +610,4 @@ namespace Confuser.Core.Project {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
using System.IO;
|
||||||
|
using System.Xml;
|
||||||
|
using Confuser.Core;
|
||||||
|
using Confuser.Core.Project;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Confuser.MSBuild.Tasks {
|
||||||
|
public sealed class ConfuseTask : Task {
|
||||||
|
[Required]
|
||||||
|
public ITaskItem Project { get; set; }
|
||||||
|
|
||||||
|
[Required, Output]
|
||||||
|
public ITaskItem OutputAssembly { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute() {
|
||||||
|
var project = new ConfuserProject();
|
||||||
|
var xmlDoc = new XmlDocument();
|
||||||
|
xmlDoc.Load(Project.ItemSpec);
|
||||||
|
project.Load(xmlDoc);
|
||||||
|
project.OutputDirectory = Path.GetDirectoryName(OutputAssembly.ItemSpec);
|
||||||
|
|
||||||
|
var logger = new MSBuildLogger(Log);
|
||||||
|
var parameters = new ConfuserParameters {
|
||||||
|
Project = project,
|
||||||
|
Logger = logger
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfuserEngine.Run(parameters).Wait();
|
||||||
|
return !logger.HasError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<Import Project="..\ConfuserEx.Common.props" Condition="Exists('..\ConfuserEx.Common.props')" />
|
||||||
|
|
||||||
|
<PropertyGroup Label="Assembly Settings">
|
||||||
|
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
|
||||||
|
<SignAssembly>true</SignAssembly>
|
||||||
|
<AssemblyOriginatorKeyFile>..\ConfuserEx.snk</AssemblyOriginatorKeyFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Label="Nuget Package Settings">
|
||||||
|
<PackageId>Confuser.MSBuild</PackageId>
|
||||||
|
<PackageLicenseUrl>https://github.com/mkaring/ConfuserEx/blob/master/LICENSE.md</PackageLicenseUrl>
|
||||||
|
<PackageProjectUrl>https://github.com/mkaring/ConfuserEx</PackageProjectUrl>
|
||||||
|
<PackageTags>Obfuscation Confuser ConfuserEx</PackageTags>
|
||||||
|
<DevelopmentDependency>true</DevelopmentDependency>
|
||||||
|
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<NoPackageAnalysis>true</NoPackageAnalysis>
|
||||||
|
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);IncludeConfuserDependencyFiles</TargetsForTfmSpecificContentInPackage>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup Label="Nuget Dependencies">
|
||||||
|
<PackageReference Include="Microsoft.Build.Tasks.Core" Version="15.7.*" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Label="Project Dependencies">
|
||||||
|
<ProjectReference Include="..\Confuser.Core\Confuser.Core.csproj" PrivateAssets="all" />
|
||||||
|
<ProjectReference Include="..\Confuser.Protections\Confuser.Protections.csproj" PrivateAssets="all" />
|
||||||
|
<ProjectReference Include="..\Confuser.Renamer\Confuser.Renamer.csproj" PrivateAssets="all" />
|
||||||
|
<ProjectReference Include="..\Confuser.Runtime\Confuser.Runtime.csproj" Condition="'$(TargetFramework)' == 'net461'" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="build\*" PackagePath="build" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="build\Confuser.MSBuild.targets" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="IncludeConfuserDependencyFiles">
|
||||||
|
<ItemGroup>
|
||||||
|
<ConfuserNetFrameworkDependencies Include="$(BaseOutputPath)\$(Configuration)\net461\*.dll" />
|
||||||
|
<ConfuserNetFrameworkDependencies Include="$(BaseOutputPath)\$(Configuration)\net461\*.pdb" />
|
||||||
|
<ConfuserNetStandardDependencies Include="$(BaseOutputPath)\$(Configuration)\netstandard2.0\*.dll" />
|
||||||
|
<ConfuserNetStandardDependencies Include="$(BaseOutputPath)\$(Configuration)\netstandard2.0\*.pdb" />
|
||||||
|
</ItemGroup>
|
||||||
|
<CreateItem Include="@(ConfuserNetFrameworkDependencies)" AdditionalMetadata="PackagePath=netframework">
|
||||||
|
<Output TaskParameter="Include" ItemName="TfmSpecificPackageFile" />
|
||||||
|
</CreateItem>
|
||||||
|
<CreateItem Include="@(ConfuserNetStandardDependencies)" AdditionalMetadata="PackagePath=netstandard">
|
||||||
|
<Output TaskParameter="Include" ItemName="TfmSpecificPackageFile" />
|
||||||
|
</CreateItem>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Import Project="..\ConfuserEx.Common.targets" Condition="Exists('..\ConfuserEx.Common.targets')" />
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,84 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Xml;
|
||||||
|
using Confuser.Core.Project;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
|
||||||
|
namespace Confuser.MSBuild.Tasks {
|
||||||
|
public sealed class CreateProjectTask : Task {
|
||||||
|
public ITaskItem SourceProject { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem[] References { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public ITaskItem AssemblyPath { get; set; }
|
||||||
|
|
||||||
|
public ITaskItem[] SatelliteAssemblyPaths { get; set; }
|
||||||
|
|
||||||
|
public ITaskItem KeyFilePath { get; set; }
|
||||||
|
|
||||||
|
[Required, Output]
|
||||||
|
public ITaskItem ResultProject { get; set; }
|
||||||
|
|
||||||
|
public override bool Execute() {
|
||||||
|
var project = new ConfuserProject();
|
||||||
|
if (!string.IsNullOrWhiteSpace(SourceProject?.ItemSpec)) {
|
||||||
|
var xmlDoc = new XmlDocument();
|
||||||
|
xmlDoc.Load(SourceProject.ItemSpec);
|
||||||
|
project.Load(xmlDoc);
|
||||||
|
|
||||||
|
// Probe Paths are not required, because all dependent assemblies are added as external modules.
|
||||||
|
project.ProbePaths.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
project.BaseDirectory = Path.GetDirectoryName(AssemblyPath.ItemSpec);
|
||||||
|
var mainModule = GetOrCreateProjectModule(project, AssemblyPath.ItemSpec);
|
||||||
|
if (!string.IsNullOrWhiteSpace(KeyFilePath?.ItemSpec)) {
|
||||||
|
mainModule.SNKeyPath = KeyFilePath.ItemSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SatelliteAssemblyPaths != null) {
|
||||||
|
foreach (var satelliteAssembly in SatelliteAssemblyPaths) {
|
||||||
|
if (!string.IsNullOrWhiteSpace(satelliteAssembly?.ItemSpec)) {
|
||||||
|
var satelliteModule = GetOrCreateProjectModule(project, satelliteAssembly.ItemSpec);
|
||||||
|
if (!string.IsNullOrWhiteSpace(KeyFilePath?.ItemSpec)) {
|
||||||
|
satelliteModule.SNKeyPath = KeyFilePath.ItemSpec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var probePath in References.Select(r => Path.GetDirectoryName(r.ItemSpec)).Distinct()) {
|
||||||
|
project.ProbePaths.Add(probePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
project.Save().Save(ResultProject.ItemSpec);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProjectModule GetOrCreateProjectModule(ConfuserProject project, string assemblyPath, bool isExternal = false) {
|
||||||
|
var assemblyFileName = Path.GetFileName(assemblyPath);
|
||||||
|
var assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
|
||||||
|
foreach (var module in project) {
|
||||||
|
if (string.Equals(module.Path, assemblyFileName) || string.Equals(module.Path, assemblyName)) {
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assemblyPath.StartsWith(project.BaseDirectory)) {
|
||||||
|
assemblyPath = assemblyPath.Substring(project.BaseDirectory.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new ProjectModule {
|
||||||
|
Path = assemblyPath,
|
||||||
|
IsExternal = isExternal
|
||||||
|
};
|
||||||
|
project.Add(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Build.Framework;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
|
using ILogger = Confuser.Core.ILogger;
|
||||||
|
|
||||||
|
namespace Confuser.MSBuild.Tasks {
|
||||||
|
internal sealed class MSBuildLogger : ILogger {
|
||||||
|
private readonly TaskLoggingHelper loggingHelper;
|
||||||
|
|
||||||
|
internal bool HasError { get; private set; }
|
||||||
|
|
||||||
|
internal MSBuildLogger(TaskLoggingHelper loggingHelper) =>
|
||||||
|
this.loggingHelper = loggingHelper ?? throw new ArgumentNullException(nameof(loggingHelper));
|
||||||
|
|
||||||
|
void ILogger.Debug(string msg) => loggingHelper.LogMessage(MessageImportance.Low, "[DEBUG] " + msg);
|
||||||
|
|
||||||
|
void ILogger.DebugFormat(string format, params object[] args) {
|
||||||
|
loggingHelper.LogMessage(MessageImportance.Low, "[DEBUG] " + format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.EndProgress() {}
|
||||||
|
|
||||||
|
void ILogger.Error(string msg) {
|
||||||
|
loggingHelper.LogError(msg);
|
||||||
|
HasError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.ErrorException(string msg, Exception ex) {
|
||||||
|
loggingHelper.LogError(msg);
|
||||||
|
loggingHelper.LogErrorFromException(ex);
|
||||||
|
HasError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.ErrorFormat(string format, params object[] args) {
|
||||||
|
loggingHelper.LogError(format, args);
|
||||||
|
HasError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.Finish(bool successful) {
|
||||||
|
if (!successful) {
|
||||||
|
HasError = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.Info(string msg) => loggingHelper.LogMessage(MessageImportance.Normal, msg);
|
||||||
|
|
||||||
|
void ILogger.InfoFormat(string format, params object[] args) =>
|
||||||
|
loggingHelper.LogMessage(MessageImportance.Normal, format, args);
|
||||||
|
|
||||||
|
void ILogger.Progress(int progress, int overall) { }
|
||||||
|
|
||||||
|
void ILogger.Warn(string msg) => loggingHelper.LogWarning(msg);
|
||||||
|
|
||||||
|
void ILogger.WarnException(string msg, Exception ex) {
|
||||||
|
loggingHelper.LogWarning(msg);
|
||||||
|
loggingHelper.LogWarningFromException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILogger.WarnFormat(string format, params object[] args) => loggingHelper.LogWarning(format, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Project>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(MSBuildRuntimeType)' == 'Full'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ConfuserAssemblyPath>$(MSBuildThisFileDirectory)\..\netframework\</ConfuserAssemblyPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ConfuserAssemblyPath>$(MSBuildThisFileDirectory)\..\netstandard\</ConfuserAssemblyPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<UsingTask TaskName="Confuser.MSBuild.Tasks.CreateProjectTask"
|
||||||
|
AssemblyFile="$(ConfuserAssemblyPath)Confuser.MSBuild.Tasks.dll" />
|
||||||
|
<UsingTask TaskName="Confuser.MSBuild.Tasks.ConfuseTask"
|
||||||
|
AssemblyFile="$(ConfuserAssemblyPath)Confuser.MSBuild.Tasks.dll" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,156 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ConfuserKeyFile Condition="'$(ConfuserKeyFile)' == ''">$(AssemblyOriginatorKeyFile)</ConfuserKeyFile>
|
||||||
|
<ConfuserIntermediateOutputPath Condition="'$(ConfuserIntermediateOutputPath)' == ''">$(IntermediateOutputPath)confused\</ConfuserIntermediateOutputPath>
|
||||||
|
<ConfuserReplaceOutput Condition="'$(ConfuserReplaceOutput)' == ''">false</ConfuserReplaceOutput>
|
||||||
|
<ConfuserOutDir Condition="'$(ConfuserOutDir)' == ''">$(OutDir)confused\</ConfuserOutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(ConfuserProject)' == ''">
|
||||||
|
<ConfuserProject Condition="Exists('$(MSBuildProjectDirectory)\$(MSBuildProjectName).crproj')">$(MSBuildProjectDirectory)\$(MSBuildProjectName).crproj</ConfuserProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<ConfuserExDependsOn>
|
||||||
|
CreateConfuserProject;
|
||||||
|
ConfuseAssembly;
|
||||||
|
_ReplaceOutputWithConfusedAssemblies;
|
||||||
|
_ReplaceDebugOutputWithConfusedAssemblies;
|
||||||
|
CopyConfusedFilesToOutputDirectory;
|
||||||
|
</ConfuserExDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<Target Name="ConfuserEx"
|
||||||
|
DependsOnTargets="$(ConfuserExDependsOn)"
|
||||||
|
BeforeTargets="PrepareForRun" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<CreateConfuserProjectDependsOn>
|
||||||
|
ResolveReferences;
|
||||||
|
ComputeIntermediateSatelliteAssemblies
|
||||||
|
</CreateConfuserProjectDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="CreateConfuserProject"
|
||||||
|
Condition="$(DesignTimeBuild) != true And $(Obfuscate) == true"
|
||||||
|
DependsOnTargets="$(CreateConfuserProjectDependsOn)"
|
||||||
|
Inputs="@(IntermediateAssembly->'%(FullPath)');$(ConfuserProject);@(IntermediateSatelliteAssembliesWithTargetPath)"
|
||||||
|
Outputs="@(IntermediateAssembly->'$(IntermediateOutputPath)%(Filename).crproj')">
|
||||||
|
<Confuser.MSBuild.Tasks.CreateProjectTask
|
||||||
|
SourceProject="$(ConfuserProject)"
|
||||||
|
References="@(ReferencePath)"
|
||||||
|
AssemblyPath="@(IntermediateAssembly)"
|
||||||
|
SatelliteAssemblyPaths="@(IntermediateSatelliteAssembliesWithTargetPath)"
|
||||||
|
KeyFilePath="$(ConfuserKeyFile)"
|
||||||
|
ResultProject="@(IntermediateAssembly->'$(IntermediateOutputPath)%(Filename).crproj')"/>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<ConfuseAssemblyDependsOn>
|
||||||
|
CreateConfuserProject
|
||||||
|
</ConfuseAssemblyDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="ConfuseAssembly"
|
||||||
|
Condition="Exists('@(IntermediateAssembly)') And $(DesignTimeBuild) != true And $(Obfuscate) == true"
|
||||||
|
DependsOnTargets="$(ConfuseAssemblyDependsOn)"
|
||||||
|
Inputs="@(IntermediateAssembly->'%(FullPath)');@(IntermediateAssembly->'$(IntermediateOutputPath)%(Filename).crproj')"
|
||||||
|
Outputs="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename)%(Extension)');@(IntermediateSatelliteAssembliesWithTargetPath->'$(ConfuserIntermediateOutputPath)%(TargetPath)')">
|
||||||
|
<Confuser.MSBuild.Tasks.ConfuseTask
|
||||||
|
Project="@(IntermediateAssembly->'$(IntermediateOutputPath)%(Filename).crproj')"
|
||||||
|
OutputAssembly="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename)%(Extension)')" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_ReplaceOutputWithConfusedAssemblies"
|
||||||
|
Condition="$(DesignTimeBuild) != true And $(Obfuscate) == true and '$(ConfuserReplaceOutput)' == 'true'"
|
||||||
|
DependsOnTargets="ConfuseAssembly">
|
||||||
|
<CreateItem Include="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename)%(Extension)')">
|
||||||
|
<Output TaskParameter="Include" ItemName="IntermediateConfusedAssembly" />
|
||||||
|
</CreateItem>
|
||||||
|
<ItemGroup>
|
||||||
|
<IntermediateAssembly Remove="@(IntermediateAssembly)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<CreateItem Include="@(IntermediateConfusedAssembly)">
|
||||||
|
<Output TaskParameter="Include" ItemName="IntermediateAssembly" />
|
||||||
|
</CreateItem>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="_ReplaceDebugOutputWithConfusedAssemblies"
|
||||||
|
Condition="$(DesignTimeBuild) != true And $(Obfuscate) == true and '$(ConfuserReplaceOutput)' == 'true' and '@(_DebugSymbolsIntermediatePath)' != ''"
|
||||||
|
DependsOnTargets="ConfuseAssembly">
|
||||||
|
<CreateItem Include="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename).pdb')">
|
||||||
|
<Output TaskParameter="Include" ItemName="_ConfusedDebugSymbolsIntermediatePath" />
|
||||||
|
</CreateItem>
|
||||||
|
<ItemGroup>
|
||||||
|
<_DebugSymbolsIntermediatePath Remove="@(_DebugSymbolsIntermediatePath)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<CreateItem Include="@(_ConfusedDebugSymbolsIntermediatePath)">
|
||||||
|
<Output TaskParameter="Include" ItemName="_DebugSymbolsIntermediatePath" />
|
||||||
|
</CreateItem>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<Target Name="CopyConfusedFilesToOutputDirectory"
|
||||||
|
Condition="$(DesignTimeBuild) != true And $(Obfuscate) == true and '$(ConfuserReplaceOutput)' != 'true'">
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- By default we're not using Hard Links to copy to the output directory, and never when building in VS -->
|
||||||
|
<CreateHardLinksForCopyFilesToOutputDirectoryIfPossible Condition="'$(BuildingInsideVisualStudio)' == 'true' or '$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)' == ''">false</CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>
|
||||||
|
<CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible Condition="'$(BuildingInsideVisualStudio)' == 'true' or '$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)' == ''">false</CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<CopyBuildOutputToOutputDirectory Condition="'$(CopyBuildOutputToOutputDirectory)'==''">true</CopyBuildOutputToOutputDirectory>
|
||||||
|
<CopyOutputSymbolsToOutputDirectory Condition="'$(CopyOutputSymbolsToOutputDirectory)'==''">true</CopyOutputSymbolsToOutputDirectory>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Copy the confused build product (.dll or .exe). -->
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename)%(Extension)')"
|
||||||
|
DestinationFolder="$(ConfuserOutDir)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
Condition="'$(CopyBuildOutputToOutputDirectory)' == 'true' and '$(SkipCopyBuildProduct)' != 'true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="ConfusedMainAssembly"/>
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<!-- Copy the debug information file (.pdb), if any -->
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(IntermediateAssembly->'$(ConfuserIntermediateOutputPath)%(Filename).pdb')"
|
||||||
|
DestinationFolder="$(ConfuserOutDir)"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
Condition="'$(_DebugSymbolsProduced)'=='true' and '$(SkipCopyingSymbolsToOutputDirectory)' != 'true' and '$(CopyOutputSymbolsToOutputDirectory)'=='true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
|
||||||
|
</Copy>
|
||||||
|
|
||||||
|
<!-- Copy the satellite assemblies (.resources.dll), if any -->
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(ConfuserIntermediateOutputPath)%(TargetPath)')"
|
||||||
|
DestinationFiles="@(IntermediateSatelliteAssembliesWithTargetPath->'$(ConfuserOutDir)%(TargetPath)')"
|
||||||
|
SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
|
||||||
|
OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
|
||||||
|
Retries="$(CopyRetryCount)"
|
||||||
|
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
|
||||||
|
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||||
|
Condition="'$(_DebugSymbolsProduced)'=='true' and '$(SkipCopyingSymbolsToOutputDirectory)' != 'true' and '$(CopyOutputSymbolsToOutputDirectory)'=='true'">
|
||||||
|
|
||||||
|
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||||
|
|
||||||
|
</Copy>
|
||||||
|
</Target>
|
||||||
|
</Project>
|
|
@ -31,7 +31,7 @@ namespace Confuser.Renamer.Analyzers {
|
||||||
if (!match.Success)
|
if (!match.Success)
|
||||||
continue;
|
continue;
|
||||||
string typeName = match.Groups[1].Value;
|
string typeName = match.Groups[1].Value;
|
||||||
TypeDef type = mainModule.FindReflectionThrow(typeName);
|
TypeDef type = mainModule.FindReflection(typeName);
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
context.Logger.WarnFormat("Could not find resource type '{0}'.", typeName);
|
context.Logger.WarnFormat("Could not find resource type '{0}'.", typeName);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -98,6 +98,8 @@ namespace Confuser.Renamer.Analyzers {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalyzeCAArgument(ConfuserContext context, INameService service, CAArgument arg) {
|
void AnalyzeCAArgument(ConfuserContext context, INameService service, CAArgument arg) {
|
||||||
|
if (arg.Value == null) return; // null was passed to the custom attribute. We'll ignore that.
|
||||||
|
|
||||||
if (arg.Type.DefinitionAssembly.IsCorLib() && arg.Type.FullName == "System.Type") {
|
if (arg.Type.DefinitionAssembly.IsCorLib() && arg.Type.FullName == "System.Type") {
|
||||||
var typeSig = (TypeSig)arg.Value;
|
var typeSig = (TypeSig)arg.Value;
|
||||||
foreach (ITypeDefOrRef typeRef in typeSig.FindTypeRefs()) {
|
foreach (ITypeDefOrRef typeRef in typeSig.FindTypeRefs()) {
|
||||||
|
|
|
@ -40,7 +40,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Confuser.UnitTest", "Tests\
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntiTamper", "Tests\AntiTamper\AntiTamper.csproj", "{6A2BA6F7-3399-4890-9453-2D5BE8EEBBA9}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntiTamper", "Tests\AntiTamper\AntiTamper.csproj", "{6A2BA6F7-3399-4890-9453-2D5BE8EEBBA9}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AntiTamper.Test", "Tests\AntiTamper.Test\AntiTamper.Test.csproj", "{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AntiTamper.Test", "Tests\AntiTamper.Test\AntiTamper.Test.csproj", "{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Confuser.MSBuild.Tasks", "Confuser.MSBuild.Tasks\Confuser.MSBuild.Tasks.csproj", "{91B12706-DC6A-45DE-97F1-FAF0901FF6AF}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -100,6 +102,10 @@ Global
|
||||||
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Release|Any CPU.Build.0 = Release|Any CPU
|
{3F5558BD-7B94-4CB0-A46C-A7252B5BCA17}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{91B12706-DC6A-45DE-97F1-FAF0901FF6AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{91B12706-DC6A-45DE-97F1-FAF0901FF6AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{91B12706-DC6A-45DE-97F1-FAF0901FF6AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{91B12706-DC6A-45DE-97F1-FAF0901FF6AF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -16,16 +17,14 @@ namespace CompressorWithResx.Test {
|
||||||
this.outputHelper = outputHelper ?? throw new ArgumentNullException(nameof(outputHelper));
|
this.outputHelper = outputHelper ?? throw new ArgumentNullException(nameof(outputHelper));
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("false", "normal")]
|
[MemberData(nameof(CompressAndExecuteTestData))]
|
||||||
[InlineData("true", "normal")]
|
|
||||||
[InlineData("false", "dynamic")]
|
|
||||||
[InlineData("true", "dynamic")]
|
|
||||||
[Trait("Category", "Packer")]
|
[Trait("Category", "Packer")]
|
||||||
[Trait("Packer", "compressor")]
|
[Trait("Packer", "compressor")]
|
||||||
public async Task CompressAndExecuteTest(string compatKey, string deriverKey) {
|
public async Task CompressAndExecuteTest(string compatKey, string deriverKey, string resourceProtectionMode) {
|
||||||
var baseDir = Environment.CurrentDirectory;
|
var baseDir = Environment.CurrentDirectory;
|
||||||
var outputDir = Path.Combine(baseDir, "testtmp");
|
var outputDir = Path.Combine(baseDir, "testtmp");
|
||||||
var inputFile = Path.Combine(baseDir, "CompressorWithResx.exe");
|
var inputFile = Path.Combine(baseDir, "CompressorWithResx.exe");
|
||||||
|
var inputSatelliteFile = Path.Combine(baseDir, "de", "CompressorWithResx.resources.dll");
|
||||||
var outputFile = Path.Combine(outputDir, "CompressorWithResx.exe");
|
var outputFile = Path.Combine(outputDir, "CompressorWithResx.exe");
|
||||||
FileUtilities.ClearOutput(outputFile);
|
FileUtilities.ClearOutput(outputFile);
|
||||||
var proj = new ConfuserProject {
|
var proj = new ConfuserProject {
|
||||||
|
@ -36,7 +35,17 @@ namespace CompressorWithResx.Test {
|
||||||
{ "key", deriverKey }
|
{ "key", deriverKey }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (resourceProtectionMode != "none") {
|
||||||
|
proj.Rules.Add(new Rule() {
|
||||||
|
new SettingItem<Protection>("resources") {
|
||||||
|
{ "mode", resourceProtectionMode }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
proj.Add(new ProjectModule() { Path = inputFile });
|
proj.Add(new ProjectModule() { Path = inputFile });
|
||||||
|
proj.Add(new ProjectModule() { Path = inputSatelliteFile });
|
||||||
|
|
||||||
|
|
||||||
var parameters = new ConfuserParameters {
|
var parameters = new ConfuserParameters {
|
||||||
|
@ -56,7 +65,8 @@ namespace CompressorWithResx.Test {
|
||||||
using (var process = Process.Start(info)) {
|
using (var process = Process.Start(info)) {
|
||||||
var stdout = process.StandardOutput;
|
var stdout = process.StandardOutput;
|
||||||
Assert.Equal("START", await stdout.ReadLineAsync());
|
Assert.Equal("START", await stdout.ReadLineAsync());
|
||||||
Assert.Equal("Test", await stdout.ReadLineAsync());
|
Assert.Equal("Test (fallback)", await stdout.ReadLineAsync());
|
||||||
|
Assert.Equal("Test (deutsch)", await stdout.ReadLineAsync());
|
||||||
Assert.Equal("END", await stdout.ReadLineAsync());
|
Assert.Equal("END", await stdout.ReadLineAsync());
|
||||||
Assert.Empty(await stdout.ReadToEndAsync());
|
Assert.Empty(await stdout.ReadToEndAsync());
|
||||||
Assert.True(process.HasExited);
|
Assert.True(process.HasExited);
|
||||||
|
@ -65,5 +75,12 @@ namespace CompressorWithResx.Test {
|
||||||
|
|
||||||
FileUtilities.ClearOutput(outputFile);
|
FileUtilities.ClearOutput(outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<object[]> CompressAndExecuteTestData() {
|
||||||
|
foreach (var compressorCompatKey in new string[] { "true", "false" })
|
||||||
|
foreach (var compressorDeriveKey in new string[] { "normal", "dynamic" })
|
||||||
|
foreach (var resourceProtectionMode in new string[] { "none", "normal", "dynamic" })
|
||||||
|
yield return new object[] { compressorCompatKey, compressorDeriveKey, resourceProtectionMode };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ namespace CompressorWithResx {
|
||||||
public class Program {
|
public class Program {
|
||||||
internal static int Main(string[] args) {
|
internal static int Main(string[] args) {
|
||||||
Console.WriteLine("START");
|
Console.WriteLine("START");
|
||||||
|
Properties.Resources.Culture = new System.Globalization.CultureInfo("en-US");
|
||||||
|
Console.WriteLine(Properties.Resources.TestString);
|
||||||
|
Properties.Resources.Culture = new System.Globalization.CultureInfo("de-DE");
|
||||||
Console.WriteLine(Properties.Resources.TestString);
|
Console.WriteLine(Properties.Resources.TestString);
|
||||||
Console.WriteLine("END");
|
Console.WriteLine("END");
|
||||||
return 42;
|
return 42;
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace CompressorWithResx.Properties {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sucht eine lokalisierte Zeichenfolge, die Test ähnelt.
|
/// Sucht eine lokalisierte Zeichenfolge, die Test (fallback) ähnelt.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string TestString {
|
internal static string TestString {
|
||||||
get {
|
get {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="TestString" xml:space="preserve">
|
||||||
|
<value>Test (deutsch)</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
|
@ -118,6 +118,6 @@
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<data name="TestString" xml:space="preserve">
|
<data name="TestString" xml:space="preserve">
|
||||||
<value>Test</value>
|
<value>Test (fallback)</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -24,3 +24,7 @@ build:
|
||||||
artifacts:
|
artifacts:
|
||||||
- path: Release/bin
|
- path: Release/bin
|
||||||
name: ConfuserEx
|
name: ConfuserEx
|
||||||
|
type: zip
|
||||||
|
|
||||||
|
- path: Confuser.MSBuild.Tasks/bin/Release/*.nupkg
|
||||||
|
name: ConfuserEx.MSBuild
|
||||||
|
|
Загрузка…
Ссылка в новой задаче