Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Build/FieldWorks.proj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<UsingTask TaskName="GenerateFwTargets" AssemblyFile="FwBuildTasks.dll"/>
<UsingTask TaskName="GenerateNUnitReports" AssemblyFile="FwBuildTasks.dll" />
<UsingTask TaskName="GenerateTestCoverageReport" AssemblyFile="FwBuildTasks.dll"/>
<UsingTask TaskName="LogMetadata" AssemblyFile="FwBuildTasks.dll"/>
<UsingTask TaskName="Make" AssemblyFile="FwBuildTasks.dll"/>
<UsingTask TaskName="Md5Checksum" AssemblyFile="FwBuildTasks.dll"/>
<UsingTask TaskName="NUnit" AssemblyFile="FwBuildTasks.dll"/>
Expand Down Expand Up @@ -60,8 +61,9 @@
<Import Project="Windows.targets"/>
<Import Project="FieldWorks.targets" Condition="Exists('FieldWorks.targets')"/>
<Import Project="mkall.targets"/>
<Import Project="Installer.targets"/>
<Import Project="Installer.targets" Condition="'$(OS)'=='Windows_NT'"/>
<Import Project="InstallerTests.targets" Condition="'$(OS)'=='Windows_NT'"/>
<Import Project="LocalLibrary.targets"/>
<Import Project="Localize.targets"/>
<Import Project="NuGet.targets"/>
<Import Project="LocalLibrary.targets"/>
</Project>
Binary file modified Build/FwBuildTasks.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion Build/Installer.targets
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@
<Copy SourceFiles="@(BinFiles)" OverwriteReadonlyFiles="true" DestinationFolder="$(AppBuildDir)/$(BinDirSuffix)/%(RecursiveDir)"/>
<Copy SourceFiles="@(CustomInstallFiles)" OverwriteReadonlyFiles="true" DestinationFolder="$(AppBuildDir)/$(BinDirSuffix)/.."/>
<Copy SourceFiles="@(OverrideFiles)" OverwriteReadonlyFiles="true" DestinationFolder="$(OverridesDestDir)"/>
<CallTarget Targets="HarvestL10n;ConvertHarvestsToWxi"/>
<CallTarget Targets="HarvestL10n;ConvertHarvestsToWxi;WriteFilesMetadata"/>
</Target>

<Target Name="HarvestL10n">
Expand Down
58 changes: 58 additions & 0 deletions Build/InstallerTests.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="15.0">
<PropertyGroup>
<ReposRoot Condition="'$(ReposRoot)'==''">$(fwrt)\..</ReposRoot>
</PropertyGroup>
<ItemGroup>
<!-- <ReposToTestPatching Include="$(ReposRoot)\libpalaso"/> -->
<!-- <ReposToTestPatching Include="$(ReposRoot)\liblcm"/> -->
<!-- <ReposToTestPatching Include="$(ReposRoot)\chorus"/> -->
<ReposToTestPatching Include="$(fwrt)"/>
<!-- <ReposToTestPatching Include="$(fwrt)\Localization"/>, helps? -->
</ItemGroup>

<!-- ########################################################################################################## -->
<!-- Builds a base installer, makes changes in each repository (by applying the stash), then builds a patch to test -->
<!-- ########################################################################################################## -->
<Target Name="BuildPatchTest">
<MSBuild Projects="$(MSBuildProjectFullPath)" Targets="BuildBaseInstaller"/>
<Exec Command="git stash apply" WorkingDirectory="%(ReposToTestPatching.Identity)"/>
<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="BuildVersionSegment=3" Targets="BuildPatchInstaller"/>
</Target>

<!-- ########################################################################################################## -->
<!-- Builds a base installer, changes each installed file, then builds a patch to test -->
<!-- Note: you must build target BuildBaseInstaller before using this test. -->
<!-- ########################################################################################################## -->
<Target Name="BuildQuickPatchTest" DependsOnTargets="InstallerVersionNumbers;CleanMasterOutputDir;FieldWorks">
<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="BuildingBaseInstaller=true"
Targets="CopyFilesToInstall;WriteFilesMetadata;BuildProductBaseMsi;CopyBuildToMaster"/>
<ItemGroup>
<HelloWorldLines Include='using System%3B'/>
<HelloWorldLines Include='public class FieldWorks{'/>
<HelloWorldLines Include='public static void Main(string[] args){'/>
<HelloWorldLines Include='Console.WriteLine("Hello, World")%3B}}'/>
<FlexCode Include="$(fwrt)\Src\Common\FieldWorks\**\*.cs"/>
</ItemGroup>
<WriteLinesToFile File="%(FlexCode.Identity)" Overwrite="true" Lines="//"/>
<WriteLinesToFile File="$(fwrt)\Src\Common\FieldWorks\FieldWorks.cs" Overwrite="true" Lines="@(HelloWorldLines)"/>
<MSBuild Projects="$(MSBuildProjectFullPath)" Properties="BuildVersionSegment=3"
Targets="FieldWorks;CopyFilesToInstall;WriteFilesMetadata;BuildProductPatchMsp"/>
</Target>

<!-- ########################################################################################################## -->
<!-- ### Write a table of files' metadata to verify that each file has been installed or patched correctly. ### -->
<!-- ########################################################################################################## -->
<Target Name="WriteFilesMetadata" DependsOnTargets="InstallerVersionNumbers">
<PropertyGroup>
<MetadataLog>$(AppBuildDir)\$(BinDirSuffix)\installerTestMetadata.$(BuildVersion).csv</MetadataLog>
</PropertyGroup>
<ItemGroup>
<BinFilesToHash Include="$(AppBuildDir)\$(BinDirSuffix)\**\*" Exclude="$(MetadataLog)"/>
<L10nFilesToHash Include="$(AppBuildDir)\$(L10nDirSuffix)\**\*"/>
<FLExExeToHash
</ItemGroup>
<WriteLinesToFile File="$(MetadataLog)" Overwrite="true" Lines="Metadata for $(ApplicationName) $(BuildVersion)"/>
<LogMetadata LogFile="$(MetadataLog)" Files="@(FilesToHash)" PathPrefixToDrop="$(AppBuildDir)\$(BinDirSuffix)\"/>
</Target>
</Project>
6 changes: 3 additions & 3 deletions Build/Src/FwBuildTasks/FwBuildTasks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,8 @@
<Reference Include="nunit.framework">
<HintPath>..\..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="SIL.TestUtilities, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cab3c8c5232dfcf2, processorArchitecture=AMD64">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Output\Release\SIL.TestUtilities.dll</HintPath>
<Reference Include="SIL.TestUtilities">
<HintPath>..\..\..\Output\Debug\SIL.TestUtilities.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="Microsoft.Build.Framework" />
Expand All @@ -110,6 +109,7 @@
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="FwBuildTasksTests\WxsToWxiTests.cs" />
<Compile Include="LogMetadata.cs" />
<Compile Include="WxsToWxi.cs" />
<Compile Include="Clouseau.cs" />
<Compile Include="CodeReader\ILReader.cs" />
Expand Down
47 changes: 47 additions & 0 deletions Build/Src/FwBuildTasks/LogMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2019 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)

using System.Diagnostics;
using System.IO;
using FwBuildTasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace SIL.FieldWorks.Build.Tasks
{
/// <summary>
/// Generate a CSV file containing metadata about the specified files (MD5, date modified, etc.)
/// for use in testing installers and patchers
/// </summary>
public class LogMetadata : Task
{
[Required]
public string[] Files { get; set; }

public string PathPrefixToDrop { get; set; }

[Required]
public string LogFile { get; set; }

public bool Overwrite { get; set; }

public override bool Execute()
{
using (var writer = new StreamWriter(LogFile, !Overwrite))
{
writer.WriteLine("File,MD5,Version,Modified");
var lengthToDrop = string.IsNullOrEmpty(PathPrefixToDrop) ? 0 : PathPrefixToDrop.Length;
foreach (var file in Files)
{
var md5 = Md5Checksum.Compute(file);
// Some files have commas in their versions. Replace with another character because our CSV reader is cheap.
var version = FileVersionInfo.GetVersionInfo(file).FileVersion?.Replace(',', ';');
var modified = File.GetLastWriteTimeUtc(file);
writer.WriteLine($"{file.Substring(lengthToDrop)}, {md5}, {version}, {modified:yyyy-MM-dd HH:mm:ss}");
}
return true;
}
}
}
}
33 changes: 20 additions & 13 deletions Build/Src/FwBuildTasks/Md5Checksum.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2015 SIL International
// Copyright (c) 2015-2019 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)

Expand All @@ -13,28 +13,19 @@ namespace FwBuildTasks
{
public class Md5Checksum : Task
{
private static readonly HashAlgorithm Hasher = HashAlgorithm.Create("MD5");

[Required]
public string SourceFile { get; set; }

public override bool Execute()
{
try
{
var hasher = HashAlgorithm.Create("MD5");
byte[] checksum;
using (var file = File.OpenRead(SourceFile))
{
checksum = hasher.ComputeHash(file);
}
var bldr = new StringBuilder();
for ( int i=0; i < checksum.Length; i++ )
{
bldr.Append(String.Format("{0:x2}", checksum[i]));
}
var outputFile = SourceFile + ".MD5";
using (var writer = new StreamWriter(outputFile))
{
writer.Write(bldr.ToString());
writer.Write(Compute(SourceFile));
}
return true;
}
Expand All @@ -44,5 +35,21 @@ public override bool Execute()
return false;
}
}

public static string Compute(string filename)
{
byte[] checksumBytes;
using (var file = File.OpenRead(filename))
{
checksumBytes = Hasher.ComputeHash(file);
}
var bldr = new StringBuilder();
foreach (var b in checksumBytes)
{
bldr.AppendFormat("{0:x2}", b);
}

return bldr.ToString();
}
}
}
16 changes: 13 additions & 3 deletions Build/Src/FwBuildTasks/Substitute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2018 SIL International
// Copyright (c) 2018 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)

Expand Down Expand Up @@ -74,8 +74,18 @@ public override bool Execute()
fileContents = regex.Replace(fileContents, string.Format("{0:dd}", DateTime.Now));

regex = new Regex("\\$NUMBEROFDAYS");
fileContents = regex.Replace(fileContents,
Convert.ToInt32(Math.Truncate(DateTime.Now.ToOADate())).ToString());
var numberOfDays = Convert.ToInt32(Math.Truncate(DateTime.Now.ToOADate())).ToString();
fileContents = regex.Replace(fileContents, numberOfDays);

// Jenkins builds should set the BUILD_NUMBER in the environment
var buildNumber = Environment.GetEnvironmentVariable("BUILD_NUMBER");
if (string.IsNullOrEmpty(buildNumber))
{
// fall back to number of days if no BUILD_NUMBER is in the environment
buildNumber = numberOfDays;
}
regex = new Regex("\\$BUILDNUMBER");
fileContents = regex.Replace(fileContents, buildNumber);

regex = new Regex("\\$GENERATEDFILECOMMENT");
if (regex.IsMatch(fileContents))
Expand Down
10 changes: 5 additions & 5 deletions Src/CommonAssemblyInfoTemplate.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*----------------------------------------------------------------------------------------------
/*----------------------------------------------------------------------------------------------
Copyright (c) 2002-2013 SIL International
This software is licensed under the LGPL, version 2.1 or later
(http://www.gnu.org/licenses/lgpl-2.1.html)
Expand All @@ -25,9 +25,9 @@ Some are kept here so that certain symbols (starting with $ in the template) can
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Format: Version.Milestone.Year.MMDDL
[assembly: AssemblyFileVersion("$!{FWMAJOR:0}.$!{FWMINOR:0}.$!{FWREVISION:0}.$NUMBEROFDAYS")]
// Format: FwMajorVersion.FwMinorVersion
// Format: Major.Minor.Revision.BuildNumber
[assembly: AssemblyFileVersion("$!{FWMAJOR:0}.$!{FWMINOR:0}.$!{FWREVISION:0}.$BUILDNUMBER")]
// Format: FwMajorVersion.FwMinorVersion Alpha/Beta/RC
[assembly: AssemblyInformationalVersionAttribute("$!{FWMAJOR:0}.$!{FWMINOR:0} $!FWBETAVERSION")]
// Format: Version.Milestone.0.Level
// Format: Major.Minor.Revision.BuildNumber?
[assembly: AssemblyVersion("$!{FWMAJOR:0}.$!{FWMINOR:0}.$!{FWREVISION:0}.*")]
107 changes: 107 additions & 0 deletions Src/InstallValidator/InstallValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) 2019 SIL International
// This software is licensed under the LGPL, version 2.1 or later
// (http://www.gnu.org/licenses/lgpl-2.1.html)

using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace SIL.InstallValidator
{
public class InstallValidator
{
// ENHANCE (Hasso) 2019.07: look for extra files?
// ENHANCE (Hasso) 2019.07: option to catalog files that have already been installed (for testing against other upgrade scenarios)
public static void Main(string[] args)
{
if (args.Length == 0 || !File.Exists(args[0]))
{
// The user double-clicked (poor user won't see this), ran w/o args, or ran w/ invalid args.
Debug.WriteLine("SIL Installation Validator");
Debug.WriteLine("Copyright (c) 2019 SIL International");
Debug.WriteLine(string.Empty);
Debug.WriteLine("This program may be installed in the same directory as another SIL program,");
Debug.WriteLine("but users should not use it. Its purpose is to help verify that the program");
Debug.WriteLine(" was installed correctly.");
Debug.WriteLine("Usage:");
Debug.WriteLine(" - Drop installerTestMetadata.csv on this exe to generate a report");
Debug.WriteLine(" - InstallValidator.exe installerTestMetadata.csv [alternate report location]");
Debug.WriteLine(" (for unit tests)");
return;
}

var logFile = SafeGetAt(args, 1) ?? Path.Combine(Path.GetTempPath(), "FlexInstallationReport.csv");

using (var expected = new StreamReader(args[0]))
using (var actual = new StreamWriter(logFile))
{
actual.WriteLine("File, Result, Expected Version, Actual Version, Expected Date, Actual Date Modified (UTC)");
expected.ReadLine(); // skip headers
string file;
while ((file = expected.ReadLine()) != null)
{
var info = file.Split(',');
if (info.Length < 2)
{
actual.WriteLine($"Bad input (or EOF), {file}");
continue;
}

var filePath = info[0].Trim();
actual.Write(filePath);
var fullPath = Path.Combine(Directory.GetCurrentDirectory(), filePath);
if (!File.Exists(fullPath))
{
actual.WriteLine(", is missing");
continue;
}

var expectedMd5 = info[1].Trim();
var actualMd5 = ComputeMd5Sum(fullPath);
if (string.Equals(expectedMd5, actualMd5))
{
actual.WriteLine(", was installed correctly");
continue;
}

var expectedVersion = SafeGetAt(info, 2);
var actualVersion = FileVersionInfo.GetVersionInfo(fullPath).FileVersion;
var expectedDate = SafeGetAt(info, 3);
var actualDate = File.GetLastWriteTimeUtc(fullPath);
actual.WriteLine(
$", incorrect file is present, {expectedVersion}, {actualVersion}, {expectedDate}, {actualDate:yyyy-MM-dd HH:mm:ss}");
}
}

// If we ran the program by dropping installerTestMetadata.csv, open the report using the default program
if (args.Length == 1)
{
Process.Start(logFile);
}
}

private static string SafeGetAt(string[] arr, int index)
{
return arr.Length > index ? arr[index].Trim() : null;
}

private static readonly HashAlgorithm Hasher = HashAlgorithm.Create("MD5");

public static string ComputeMd5Sum(string filename)
{
byte[] checksumBytes;
using (var file = File.OpenRead(filename))
{
checksumBytes = Hasher.ComputeHash(file);
}
var bldr = new StringBuilder();
foreach (var b in checksumBytes)
{
bldr.AppendFormat("{0:x2}", b);
}

return bldr.ToString();
}
}
}
Loading