Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
zadjii-msft committed May 17, 2017
1 parent a33d5b9 commit 5bc5c8d
Show file tree
Hide file tree
Showing 25 changed files with 1,886 additions and 0 deletions.
22 changes: 22 additions & 0 deletions DistroInstaller.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mydistro", "DistroInstaller\DistroInstaller.vcxproj", "{BA627106-E5F7-46EE-B8D7-2D5A760F2FB2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BA627106-E5F7-46EE-B8D7-2D5A760F2FB2}.Debug|x64.ActiveCfg = Debug|x64
{BA627106-E5F7-46EE-B8D7-2D5A760F2FB2}.Debug|x64.Build.0 = Debug|x64
{BA627106-E5F7-46EE-B8D7-2D5A760F2FB2}.Release|x64.ActiveCfg = Release|x64
{BA627106-E5F7-46EE-B8D7-2D5A760F2FB2}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
268 changes: 268 additions & 0 deletions DistroInstaller/BaseLinuxDistroLauncher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
#include "stdafx.h"
#include "BaseLinuxDistroLauncher.hpp"

#define REGISTRY_DISTRO_SETUP_COMPLETE_KEY (L"SetupComplete")

using namespace Helpers;


BaseLinuxDistroLauncher::BaseLinuxDistroLauncher() :
_myName(nullptr)
{
}

BaseLinuxDistroLauncher::~BaseLinuxDistroLauncher()
{
}

////////////////////////////////////////////////////////////////////////////////
// Installation
////////////////////////////////////////////////////////////////////////////////

// Method Description:
// - Determines if this distro is already installed on WSL.
// Arguments:
// - None
// Return Value:
// - true iff this distro has already been registered with WSL using `WslRegisterDistribution`
BOOL BaseLinuxDistroLauncher::IsInstalled()
{
if (_myName == nullptr)
{
throw std::invalid_argument("You must set a name for your distro before"
" calling any WSL API's. See MyLinuxDistroLauncher::Initialize()");
}
return wslApi.WslIsDistributionRegistered(_myName);
}

// Method Description:
// - Attempts to install and register the distro contained by this app with the
// linux subsystem.
// Arguments:
// - None
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::InstallDistro()
{
HRESULT hr = S_OK;

PrintMessage(MSG_STATUS_INSTALLING);
hr = wslApi.WslRegisterDistribution(_myName, L"install.tar.gz");

if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
{
// The install didn't actually fail - it's just already been installed.
hr = S_OK;
}

PrintMessage(SUCCEEDED(hr) ? MSG_INSTALL_SUCCESS : MSG_INSTALL_FAILURE);

return hr;
}

////////////////////////////////////////////////////////////////////////////////
// Command Line Parsing
////////////////////////////////////////////////////////////////////////////////

// Method Description:
// - Parses the commandline args passed in, and dispatches the appropriate function.
// Arguments:
// - argc: Number of args in argv
// - argv: An array of arguments to parse.
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::DispatchCommandLine(int argc, wchar_t const *argv[])
{
HRESULT hr = S_OK;
if (argc <= 0 || argv == nullptr)
{
hr = this->LaunchDefault();
}
else
{
wchar_t const * command = argv[0];
int remainingArgc = argc - 1;
wchar_t const ** remainingArgv = argc > 1 ? argv + 1 : nullptr;

if (_wcsicmp(command, L"run") == 0 ||
_wcsicmp(command, L"/c") == 0 ||
_wcsicmp(command, L"-c") == 0 )
{
hr = this->LaunchProcess(remainingArgc, remainingArgv);
}
else if (_wcsicmp(command, L"config") == 0 )
{
hr = this->Configure(remainingArgc, remainingArgv);
}
else if (_wcsicmp(command, L"help") == 0 ||
_wcsicmp(command, L"/?") == 0 ||
_wcsicmp(command, L"-?") == 0)
{
hr = this->PrintHelp(remainingArgc, remainingArgv);
}
else
{
PrintMessage(MSG_INVALID_ARGS, command);
hr = E_INVALIDARG;
}

}

return hr;
}

// Method Description:
// - Unregisters this distro from the linux subsystem, and removes the distro's
// files. The app remains installed, so the user can re-install the distro
// without re-downloading the entire appx again.
// Arguments:
// - None
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::CleanDistro()
{
HRESULT hr = S_OK;

PrintMessage(MSG_STATUS_UNINSTALL_PROMPT);
hr = PromptAcceptance(MSG_AGREE_PROMPT_WORD, MSG_AGREE_PROMPT);
if (SUCCEEDED(hr))
{
PrintMessage(MSG_STATUS_UNINSTALLING);
hr = wslApi.WslUnregisterDistribution(_myName);

if (SUCCEEDED(hr))
{
PrintMessage(MSG_UNINSTALL_SUCCESS);
}
else
{
PrintMessage(MSG_UNINSTALL_FAILED);
}
}
else
{
PrintMessage(MSG_AGREE_REJECTED);
}
return hr;
}

// Method Description:
// - Launches a default process for this distro. This is what's launched when
// the user runs this application without any arguments.
// By default, this launches the user's default shell, via wsl.exe.
// Make any changes to the subclass (MyLinuxDistroLauncher) if you'd like
// to modify this.
// Arguments:
// - None
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::LaunchDefault()
{
HRESULT hr = S_OK;
DWORD returnValue;
hr = wslApi.WslLaunchInteractive(_myName, L"", false, &returnValue);

return hr;
}

// Method Description:
// - Launches the commandline specified by the arguments in argv.
// This will take the args in argv and join them with spaces, and pass that
// command line to WslLaunchInteractive. This launches the process as the
// default user for the distro.
// If no args are passed in (argc==0 && argv==nullptr), then this launches
// the default process for this distro (see LaunchDefault).
// Arguments:
// - argc: Number of args in argv
// - argv: An array of arguments to parse.
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::LaunchProcess(int argc, wchar_t const *argv[])
{

HRESULT hr = S_OK;
if (argc == 0)
{
// No args were passed in
hr = this->LaunchDefault();
}
else
{
std::wstring command = argv[0];
// Join args with spaces
for (int i = 1; i < argc; ++i)
{
command += L" " + std::wstring(argv[i]);
}

DWORD returnValue;
hr = wslApi.WslLaunchInteractive(_myName, command.c_str(), true, &returnValue);
}

return hr;
}

////////////////////////////////////////////////////////////////////////////////
// Configuration
////////////////////////////////////////////////////////////////////////////////

// Method Description:
// - Parses the commandline args passed in to perform certain configuration tasks.
// With no args, it prints all of the state of this distro.
// If you pass in one of the configuration flags, you can get
// specifically that value, or pass in more arguments to set that value.
// By default, the only config flags supported are:
// `--default-user <username>`: Set the default user for this distro to <username>
// Arguments:
// - argc: Number of args in argv
// - argv: An array of arguments to parse.
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::Configure(int argc, wchar_t const *argv[])
{
HRESULT hr = S_OK;
if (argc <= 0 || argv == nullptr)
{
PrintMessage(MSG_INVALID_COMMANDLINE);
hr = E_INVALIDARG;
}
else
{
wchar_t const * token = argv[0];
wchar_t const ** remainingArgv = argc > 1 ? argv + 1 : nullptr;
int remainingArgc = argc-1;

if ( _wcsicmp(token, L"--default-user") == 0 )
{
hr = this->SetDefaultUser(remainingArgc, remainingArgv);
}
else
{
PrintMessage(MSG_INVALID_ARGS, token);
hr = E_INVALIDARG;
}

}
return hr;
}

////////////////////////////////////////////////////////////////////////////////
// Help
////////////////////////////////////////////////////////////////////////////////

// Method Description:
// - Prints the usage
// Arguments:
// - argc: Number of args in argv
// - argv: An array of arguments to parse.
// Return Value:
// - An HRESULT with the failure code, or S_OK if it succeeded.
HRESULT BaseLinuxDistroLauncher::PrintHelp(int argc, wchar_t const *argv[])
{
PrintMessage(MSG_USAGE);
return S_OK;
}
33 changes: 33 additions & 0 deletions DistroInstaller/BaseLinuxDistroLauncher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
#pragma once

class BaseLinuxDistroLauncher
{
public:
BaseLinuxDistroLauncher();
~BaseLinuxDistroLauncher();
virtual HRESULT Initialize() = 0;

HRESULT DispatchCommandLine(int argc, wchar_t const *argv[]);

BOOL IsInstalled();
HRESULT InstallDistro();

virtual HRESULT SetupDistro() = 0;

HRESULT CleanDistro();

HRESULT LaunchDefault();
HRESULT LaunchProcess(int argc, wchar_t const *argv[]);

HRESULT Configure(int argc, wchar_t const *argv[]);
virtual HRESULT SetDefaultUser(int argc, wchar_t const *argv[]) = 0;

HRESULT PrintHelp(int argc, wchar_t const *argv[]);

protected:
const wchar_t* _myName;
};
54 changes: 54 additions & 0 deletions DistroInstaller/DistroInstaller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the terms described in the LICENSE file in the root of this project.
//
#include "stdafx.h"
#include "MyLinuxDistroLauncher.hpp"

int wmain(int argc, wchar_t const *argv[])
{
HRESULT hr = S_OK;

MyLinuxDistroLauncher myDistro = MyLinuxDistroLauncher();
hr = myDistro.Initialize();

// Quick look to see if we're cleaning the distro.
// We want this to be able to be done even if setup hasn't been completed.
if (argc > 1 && _wcsicmp(argv[1], L"clean") == 0)
{
hr = myDistro.CleanDistro();
}
else if (SUCCEEDED(hr))
{
if (!myDistro.IsInstalled())
{
// Try installing the distro. If we successfully install, then also
// perform setup.
hr = myDistro.InstallDistro();

if (SUCCEEDED(hr))
{
hr = myDistro.SetupDistro();
}
}

if (SUCCEEDED(hr))
{
// Proccess the commandline args if there are any
int remainingArgc = argc - 1;
wchar_t const ** remainingArgv = argc > 1 ? argv + 1 : nullptr;
hr = myDistro.DispatchCommandLine(remainingArgc, remainingArgv);
}
}

// If it wasn't an invalid commandline, print the error message.
if (!SUCCEEDED(hr) && hr != E_INVALIDARG)
{
Helpers::PrintMessage(MSG_ERROR_CODE, hr);

Helpers::PrintMessage(MSG_PRESS_A_KEY);
_getwch();
}

return SUCCEEDED(hr)? 0 : 1;
}
Binary file added DistroInstaller/DistroInstaller.rc
Binary file not shown.
Loading

0 comments on commit 5bc5c8d

Please sign in to comment.