[setup-windows] Provide a Windows installer (#708)

I really didn't want to do this. I wanted the Xamarin.Android SDK on
Windows to be usable side-by-side, so that multiple
`oss-xamarin.android*.zip` files could be extracted, and developers
could switch between them by overriding MSBuild properties.

This is what was documented in commit 87ca2737, by overriding the
`$(TargetFrameworkRootPath)` MSBuild property.

There's just one "minor" problem with that approach: it only works if
the project that is being built, and *all* project dependencies, are
Xamarin.Android projects. If *any* other kind of dependency is brought
in, this approach will no longer work, as the `GetReferenceAssemblies`
target -- which looks for assemblies *rooted within
`$(TargetFrameworkRootPath)`* -- won't be able to find them.

Unfortunately, *everything of interest* doesn't fit within this
restriction. A Xamarin.Forms app, or any other app using PCL
assemblies, quickly runs afoul of it:

	error MSB3644: The reference assemblies for framework ".NETPortable,Version=v4.5,Profile=Profile259" were not found.

Consequently, the instructions from commit 87ca2737 are borderline
worthless. There is only one way to actually build such projects, and
that's to install Xamarin.Android *system-wide*, so that MSBuild's
`GetReferenceAssemblies` target can find everything it needs.

:-(

Thus, we need an "installer." I was hoping for a simple `.cmd` file,
but that stymied me. Then I hoped for a PowerShell script, but
installation requires access to the `%VSINSTALLDIR%` environment
variable, which is only exported from
Visual Studio Developer Command Prompts, and all the solutions I found
to import the VS command prompt environment info into PowerShell
looked decidedly ugly.

Which brings us to a minimal effort command-line installer:
`setup-windows.exe`. This utility backs up existing installs, then
creates symbolic links within the system-wide directories, pointing
them into the extracted `oss-xamarin.android*.zip` contents which
contains `setup-windows.exe`.

`setup-windows.exe /uninstall` is also provided, to put directories
back the way they were found.

`Documentation/UsingJenkinsBuildArtifacts.md` has been updated
accordingly.
This commit is contained in:
Jonathan Pryor 2017-07-31 03:51:51 -07:00 коммит произвёл Dean Ellis
Родитель 5af510d9cf
Коммит 4f3d604626
5 изменённых файлов: 307 добавлений и 49 удалений

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

@ -44,22 +44,8 @@ and download the `oss-xamarin.android*.zip` file, e.g.
There are two ways to install a Jenkins build of Xamarin.Android on Windows:
1. Through the `oss-xamarin.android*.zip` file.
2. Through the `Xamarin.Android.Sdk-OSS*.vsix` file.
### `oss-xamarin.android*.zip` Installation
Windows users can right-click the `oss-xamarin.android*.zip` file within
Windows Explorer and click **Extract All...**, and in the
**Extract Compressed (Zipped) Folders** dialog enter a *short* path such as
`C:\xa-sdk`. This is necessary because some of the contained filenames are
quite long. This will result in a path such as:
C:\xa-sdk\oss-xamarin.android_v7.2.99.19_Darwin-x86_64_master_3b893cd\bin\Debug\bin\mono-symbolicate.cmd
See the [**Command-line use: Windows**](#cmd-use-Windows) section for details
on using this installation within a **Developer Command Prompt for VS 2017**
window.
1. Through the `Xamarin.Android.Sdk-OSS*.vsix` file.
2. Through the `oss-xamarin.android*.zip` file.
### `Xamarin.Android.Sdk-OSS*.vsix` Installation
@ -103,6 +89,51 @@ Once you've selected the desired Visual Studio products, click the **Install**
button to install the Xamarin.Android SDK extension into Visual Studio 2017.
### `oss-xamarin.android*.zip` Installation
Windows users can right-click the `oss-xamarin.android*.zip` file within
Windows Explorer and click **Extract All...**, and in the
**Extract Compressed (Zipped) Folders** dialog enter a *short* path such as
`C:\xa-sdk`. This is necessary because some of the contained filenames are
quite long. This will result in a path such as:
C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\bin\setup-windows.exe
Once the `.zip` file has been extracted, please run the `setup-windows.exe`
utility within the `bin\Debug` or `bin\Release` folders. If you have
Visual Studio 2017 installed, this utility *must* be run within an
Administrator-elevated **Developer Command Prompt for VS 2017** window:
1. In the Start menu, search for **Developer Command Prompt for VS 2017**.
2. Right-click the **Developer Command Prompt for VS 2017** entry.
3. Click **Run as administrator**.
Within the elevated command prompt, execute the `setup-windows.exe` program:
> C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\bin\setup-windows.exe
Executing: MKLINK /D "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid" "C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\lib\xamarin.android\xbuild-frameworks\MonoAndroid"
Executing: MKLINK /D "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Xamarin\Android" "C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\lib\xamarin.android\xbuild\Xamarin\Android"
Success!
To uninstall, run `setup-windows.exe /uninstall`:
> C:\xa-sdk\oss-xamarin.android_v7.4.99.57_Darwin-x86_64_master_97f08f7\bin\Debug\bin\setup-windows.exe /uninstall
The `setup-windows.exe` utility checks for an existing Xamarin.Android install,
renames the existing directories for backup/easy restoration purposes, then
create symbolic links into the extracted Xamarin.Android directory.
(Unfortunately, this means that you can't easily have side-by-side installs
of the Xamarin.Android SDK. Only one install can be active at a time.)
If Visual Studio 2017 isn't installed, it should be fine to right-click
`setup-windows.exe` from within Windows Explorer, then click
**Run as administrator**. (`setup-windows.exe` will *not* do the correct thing
when Visual Studio 2017 is installed, as `%VSINSTALLDIR%` isn't properly
set outside of the Developer Command Prompt for VS 2017, so the *global*
`%ProgramFiles(x86)%\MSBuild\Xamarin\Android` directory is modified, not the
per-SKU Visual Studio 2017 directory.)
# Using Jenkins Build Artifacts
## Command-line use: Linux and macOS
@ -145,20 +176,11 @@ MSBuild properties:
* `AndroidSdkDirectory`: The location of the Android SDK.
* `AndroidNdkDirectory`: The location of the Android NDK.
* `JavaSdkDirectory`: The location of the Java SDK/JDK.
* `MonoAndroidBinDirectory`: The `xbuild\Xamarin\Android` directory in the
`oss-xamarin.android*.zip` installation.
* `MonoAndroidToolsDirectory`: The `xbuild\Xamarin\Android` directory in the
`oss-xamarin.android*.zip` installation.
* `TargetFrameworkRootPath`: The `xbuild-frameworks` directory in the
`oss-xamarin.android*.zip` installation.
For example (using the paths from [Android SDK Setup](#Android_SDK_Setup)):
msbuild /p:AndroidSdkDirectory="C:\xa-sdk\android-sdk" ^
/p:AndroidNdkDirectory="C:\xa-sdk\android-ndk\android-ndk-r14" ^
/p:MonoAndroidBinDirectory="C:\xa-sdk\oss-xamarin.android_v7.2.99.19_Darwin-x86_64_master_3b893cd\bin\Debug\lib\xamarin.android\xbuild\Xamarin\Android" ^
/p:MonoAndroidToolsDirectory="C:\xa-sdk\oss-xamarin.android_v7.2.99.19_Darwin-x86_64_master_3b893cd\bin\Debug\lib\xamarin.android\xbuild\Xamarin\Android" ^
/p:TargetFrameworkRootPath="C:\xa-sdk\oss-xamarin.android_v7.2.99.19_Darwin-x86_64_master_3b893cd\bin\Debug\lib\xamarin.android\xbuild-frameworks" ^
/t:SignAndroidPackage ^
samples\HelloWorld\HelloWorld.csproj

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

@ -29,10 +29,6 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Xamarin.Android.NamingCusto
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Java.Interop.Tools.TypeNameMappings", "external\Java.Interop\src\Java.Interop.Tools.TypeNameMappings\Java.Interop.Tools.TypeNameMappings.shproj", "{E706B6F2-5562-4765-8F07-8CF84A797B30}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Android", "src\Mono.Android\Mono.Android.csproj", "{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Android.Export", "src\Mono.Android.Export\Mono.Android.Export.csproj", "{B8105878-D423-4159-A3E7-028298281EC6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.Aidl", "src\Xamarin.Android.Tools.Aidl\Xamarin.Android.Tools.Aidl.csproj", "{D27AD8F7-7710-40BE-B03B-55EFBEC13C44}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Build.Tasks", "src\Xamarin.Android.Build.Tasks\Xamarin.Android.Build.Tasks.csproj", "{3F1F2F50-AF1A-4A5A-BEDB-193372F068D7}"
@ -111,6 +107,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "create-vsix", "build-tools\
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "netstandard", "src\netstandard\netstandard.mdproj", "{93614CB8-4564-43B9-93B0-4AF4B3B16AAE}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "Mono.Android", "src\Mono.Android\Mono.Android.csproj", "{8B10353F-2D58-41D4-BB26-E75218A4A800}"
EndProject
Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "Mono.Android.Export", "src\Mono.Android.Export\Mono.Android.Export.csproj", "{C31712E0-CFB1-47E5-855B-D0B59979F7B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "setup-windows", "tools\setup-windows\setup-windows.csproj", "{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AnyCPU = Debug|AnyCPU
@ -135,14 +137,6 @@ Global
{3FC3E78B-F7D4-42EA-BBE8-4535DF42BFF8}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{3FC3E78B-F7D4-42EA-BBE8-4535DF42BFF8}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|An yCPU
{3FC3E78B-F7D4-42EA-BBE8-4535DF42BFF8}.XAIntegrationRelease|Any CPU.Build.0 = Debug|An yCPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.Release|AnyCPU.Build.0 = Release|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7}.XAIntegrationRelease|Any CPU.Build.0 = Debug|Any CPU
{8FF78EB6-6FC8-46A7-8A15-EBBA9045C5FA}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{8FF78EB6-6FC8-46A7-8A15-EBBA9045C5FA}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{8FF78EB6-6FC8-46A7-8A15-EBBA9045C5FA}.Release|AnyCPU.ActiveCfg = Release|Any CPU
@ -181,14 +175,6 @@ Global
{B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{B17475BC-45A2-47A3-B8FC-62F3A0959EE0}.XAIntegrationRelease|Any CPU.Build.0 = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.Release|AnyCPU.Build.0 = Release|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{B8105878-D423-4159-A3E7-028298281EC6}.XAIntegrationRelease|Any CPU.Build.0 = Debug|Any CPU
{53EE4C57-1C03-405A-8243-8DA539546C88}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
{53EE4C57-1C03-405A-8243-8DA539546C88}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{53EE4C57-1C03-405A-8243-8DA539546C88}.Debug|AnyCPU.Build.0 = Debug|Any CPU
@ -509,6 +495,30 @@ Global
{93614CB8-4564-43B9-93B0-4AF4B3B16AAE}.XAIntegrationDebug|AnyCPU.Build.0 = Debug|Any CPU
{93614CB8-4564-43B9-93B0-4AF4B3B16AAE}.XAIntegrationRelease|AnyCPU.ActiveCfg = Debug|Any CPU
{93614CB8-4564-43B9-93B0-4AF4B3B16AAE}.XAIntegrationRelease|AnyCPU.Build.0 = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.Release|AnyCPU.Build.0 = Release|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{8B10353F-2D58-41D4-BB26-E75218A4A800}.XAIntegrationRelease|Any CPU.Build.0 = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.Debug|AnyCPU.Build.0 = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.Release|AnyCPU.ActiveCfg = Release|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.Release|AnyCPU.Build.0 = Release|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.XAIntegrationRelease|Any CPU.ActiveCfg = Debug|Any CPU
{C31712E0-CFB1-47E5-855B-D0B59979F7B0}.XAIntegrationRelease|Any CPU.Build.0 = Debug|Any CPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.Debug|AnyCPU.ActiveCfg = Debug|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.Debug|AnyCPU.Build.0 = Debug|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.Release|AnyCPU.ActiveCfg = Release|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.Release|AnyCPU.Build.0 = Release|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.XAIntegrationDebug|AnyCPU.ActiveCfg = Debug|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.XAIntegrationDebug|AnyCPU.Build.0 = Debug|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.XAIntegrationRelease|AnyCPU.ActiveCfg = Release|AnyCPU
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}.XAIntegrationRelease|AnyCPU.Build.0 = Release|AnyCPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{8FF78EB6-6FC8-46A7-8A15-EBBA9045C5FA} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}
@ -521,8 +531,6 @@ Global
{FE789F04-5E95-42C5-AEF1-E33F8DF06B3F} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{74598F5C-B8CC-4CE6-8EE2-AB9CA1400076} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{E706B6F2-5562-4765-8F07-8CF84A797B30} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{66CF299A-CE95-4131-BCD8-DB66E30C4BF7} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{B8105878-D423-4159-A3E7-028298281EC6} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{D27AD8F7-7710-40BE-B03B-55EFBEC13C44} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{3F1F2F50-AF1A-4A5A-BEDB-193372F068D7} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{91713046-C358-4647-B162-ED4E1442F3D8} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
@ -562,11 +570,12 @@ Global
{BD1D66BF-5AC7-4926-8EBE-B2198A112EB0} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483}
{94756FEB-1F64-411D-A18E-81B5158F776A} = {E351F97D-EA4F-4E7F-AAA0-8EBB1F2A4A62}
{93614CB8-4564-43B9-93B0-4AF4B3B16AAE} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{8B10353F-2D58-41D4-BB26-E75218A4A800} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{C31712E0-CFB1-47E5-855B-D0B59979F7B0} = {04E3E11E-B47D-4599-8AFC-50515A95E715}
{73DF9E10-E933-4222-B8E1-F4536FFF9FAD} = {864062D3-A415-4A6F-9324-5820237BA058}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0
$0.DotNetNamingPolicy = $1
$1.DirectoryNamespaceAssociation = None
$1.ResourceNamePolicy = FileFormatDefault
EndGlobalSection
EndGlobal

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

@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle ("setup-windows")]
[assembly: AssemblyDescription ("")]
[assembly: AssemblyConfiguration ("")]
[assembly: AssemblyCompany ("Microsoft Corporation")]
[assembly: AssemblyProduct ("")]
[assembly: AssemblyCopyright ("")]
[assembly: AssemblyTrademark ("")]
[assembly: AssemblyCulture ("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion ("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

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

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace Xamarin.Android.Tools
{
enum SymbolLinkFlag {
File = 0,
Directory = 1,
}
class SetupWindows
{
static string AppName;
public static int Main (string [] args)
{
// appPath is expected to be similar to: oss-xamarin.anroid-*/bin/Debug/bin/setup-windows.exe
var appPath = Environment.GetCommandLineArgs () [0];
AppName = Path.GetFileName (appPath);
var appDir = Path.GetDirectoryName (appPath);
if (Path.GetFileName (appDir) != "bin") {
Console.Error.WriteLine ($"{AppName}: This program must be run from the `bin` directory.");
return 1;
}
// prefix should be: oss-xamarin.anroid-*/bin/Debug
var prefix = Path.GetDirectoryName (appDir);
var hash = XAZipFolderNameToHash (Path.GetFileName (Path.GetDirectoryName (Path.GetDirectoryName (prefix))));
var progFiles = Environment.GetEnvironmentVariable ("ProgramFiles(x86)");
var vsInstall = Environment.GetEnvironmentVariable ("VSINSTALLDIR");
if (string.IsNullOrEmpty (vsInstall)) {
vsInstall = progFiles;
}
var msbuildTargets = Path.Combine (vsInstall, "MSBuild", "Xamarin", "Android");
var newTargets = Path.Combine (prefix, "lib", "xamarin.android", "xbuild", "Xamarin", "Android");
var refAssemblies = Path.Combine (progFiles, "Reference Assemblies", "Microsoft", "Framework", "MonoAndroid");
var newAssemblies = Path.Combine (prefix, "lib", "xamarin.android", "xbuild-frameworks", "MonoAndroid");
if (Path.DirectorySeparatorChar != '\\') {
Console.Error.WriteLine ($"{AppName}: This program is for use on Windows.");
return 1;
}
if (args.Length == 0 || args.Any (v => string.Equals (v, "install", StringComparison.OrdinalIgnoreCase) || string.Equals (v, "/install", StringComparison.OrdinalIgnoreCase))) {
return Install (msbuildTargets, newTargets, refAssemblies, newAssemblies, hash);
}
if (args.Any (v => string.Equals (v, "uninstall", StringComparison.OrdinalIgnoreCase) || string.Equals (v, "/uninstall", StringComparison.OrdinalIgnoreCase))) {
return Uninstall (msbuildTargets, refAssemblies, hash);
}
Console.Error.WriteLine ($"{AppName}: Invalid command `{string.Join (" ", args)}`.");
return 1;
}
static int Install (string msbuildTargets, string newTargets, string refAssemblies, string newAssemblies, string hash)
{
var backupAssemblies = GetNewBackupName (refAssemblies, hash);
var backupTargets = GetNewBackupName (msbuildTargets, hash);
try {
Directory.CreateDirectory (Path.GetDirectoryName (refAssemblies));
Directory.CreateDirectory (Path.GetDirectoryName (msbuildTargets));
if (CreateSymbolicLink (refAssemblies, newAssemblies, backupAssemblies) &&
CreateSymbolicLink (msbuildTargets, newTargets, backupTargets)) {
Console.WriteLine ("Success!");
return 0;
}
return 1;
}
catch (UnauthorizedAccessException e) {
Console.Error.WriteLine ($"{AppName}: {e.Message}");
Console.Error.WriteLine (e.ToString ());
return 1;
}
catch (Exception e) {
Console.Error.WriteLine ($"{AppName}: {e.Message}");
Console.Error.WriteLine (e);
return 1;
}
}
// XAZipFolderName is build-tools/scripts/BuildEverything.mk!$(ZIP_OUTPUT_BASENAME),
// oss-xamarin.android_v$(PRODUCT_VERSION).$(-num-commits-since-version-change)_$(OS)-$(OS_ARCH)_$(GIT_BRANCH)_$(GIT_COMMIT)
static string XAZipFolderNameToHash (string folderName)
{
var r = new Regex (@"^oss-xamarin.android_v(?<version>[^_]+)_(?<os>[^-]+)-(?<arch>[^_]+)_(?<branch>.*)_(?<commit>[A-Za-z0-9]+)$");
var m = r.Match (folderName);
if (!m.Success)
return "Unknown";
return m.Groups ["commit"].Value;
}
static string GetNewBackupName (string folder, string hash)
{
return GetBackupNames (folder, hash).First (d => !Directory.Exists (d));
}
static IEnumerable<string> GetBackupNames (string folder, string hash)
{
folder = GetBackupNamePrefix (folder, hash);
yield return folder;
int count = 1;
while (true) {
yield return $"{folder}+{count}";
count++;
}
}
static string GetBackupNamePrefix (string folder, string hash)
{
return folder + ".pre-" + hash;
}
static bool CreateSymbolicLink (string source, string target, string backup)
{
Console.WriteLine ($"Executing: MKLINK /D \"{source}\" \"{target}\"");
if (Directory.Exists (source)) {
Directory.Move (source, backup);
}
if (!CreateSymbolicLink (source, target, SymbolLinkFlag.Directory)) {
var error = new Win32Exception (Marshal.GetLastWin32Error ()).Message;
Console.Error.WriteLine ($"{AppName}: Unable to create symbolic link from `{source}` to `{target}`: {error}");
Directory.Move (backup, source);
return false;
}
return true;
}
static int Uninstall (string msbuildTargets, string refAssemblies, string hash)
{
var backupTargets = GetExistingBackupName (msbuildTargets, hash);
var backupAssemblies = GetExistingBackupName (refAssemblies, hash);
Directory.Delete (msbuildTargets);
if (backupTargets != null && Directory.Exists (backupTargets)) {
Directory.Move (backupTargets, msbuildTargets);
}
Directory.Delete (refAssemblies);
if (backupAssemblies != null && Directory.Exists (backupAssemblies)) {
Directory.Move (backupAssemblies, refAssemblies);
}
return 0;
}
static string GetExistingBackupName (string folder, string hash)
{
var prefix = GetBackupNamePrefix (folder, hash);
var path = Path.GetDirectoryName (prefix);
var pattern = Path.GetFileName (prefix) + "*.*";
return Directory.EnumerateDirectories (path, pattern, SearchOption.TopDirectoryOnly)
.FirstOrDefault ();
}
[DllImport ("kernel32.dll")]
[return: MarshalAs (UnmanagedType.I1)]
static extern bool CreateSymbolicLink (string lpSymlinkFileName, string lpTargetFileName, SymbolLinkFlag dwFlags);
}
}

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

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{73DF9E10-E933-4222-B8E1-F4536FFF9FAD}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>setupwindows</RootNamespace>
<AssemblyName>setup-windows</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\bin\Debug\bin</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<IntermediateOutputPath>obj\AnyCPU\Debug</IntermediateOutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>..\..\bin\Release\bin</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<IntermediateOutputPath>obj\AnyCPU\Release</IntermediateOutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="SetupWindows.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>