Moving Rover (cli-bootstrapping tool) from private repository, into public
This commit is contained in:
parent
218888387c
commit
c0b4aa284e
1
tools/cli-bootstrap/.dockerignore
Normal file
1
tools/cli-bootstrap/.dockerignore
Normal file
|
@ -0,0 +1 @@
|
|||
.git/*
|
3
tools/cli-bootstrap/.gitattributes
vendored
Normal file
3
tools/cli-bootstrap/.gitattributes
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.py -crlf
|
||||
*.sh -crlf
|
||||
*.json -crlf
|
4
tools/cli-bootstrap/.gitignore
vendored
Normal file
4
tools/cli-bootstrap/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
.rover
|
||||
*~
|
||||
*-dotnet
|
||||
.vscode
|
36
tools/cli-bootstrap/README.md
Normal file
36
tools/cli-bootstrap/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Rover
|
||||
The dotnet CLI bootstrapping tool
|
||||
|
||||
## What
|
||||
Bootstrapping a tool like the dotnet CLI can be a dizzying effort. From a high-level we simply want to replace the native components of a pre-existing CLI with new ones that
|
||||
have been built on the targetted platform. Unfortunately, from the bottom-up, this means that we need to clone a handful of dotnet repositories, execute particular
|
||||
command lines with particular arguments and then copy them in to a pre-existing dotnet file. Rover aims to simplify that.
|
||||
|
||||
The goal is to place Rover on to the distro of choice, execute it, and then have it do the required steps for you - and then things 'just work'!
|
||||
|
||||
However, things don't always 'just work.' When this is the case Rover hopes to reduce the amount of effort necessary to fix build or script breaks by placing 'repro' shell scripts when there is a failure so that a developer can go in and 'apply pressure' where appropriate.
|
||||
|
||||
## How
|
||||
|
||||
There are default settings for each of the rover arguments. If all is going to plan, you should never need to specify any additional parameters. However
|
||||
many situations arise where it becomes a necessity or a nice-to-have. Namely, when things go wrong, you want to be able to get in there and fix
|
||||
up the build, make changes, etc. This is 'development mode' or DevMode for short. In DevMode, NO git commands are executed. This is to prevent
|
||||
the script from stomping out any changes you have made in the working directory.
|
||||
|
||||
DevMode is triggered if the working directory is pre-existing. Consequently, when things fail in the script, we do not 'clean up' the working directory. We write a repro script
|
||||
of the command that failed and then we bail out immediately.
|
||||
|
||||
Rover has the following command line options:
|
||||
|
||||
- -clone [-c] - This defines the set of repositories that we want to clone. This WILL NOT function in DevMode. By default the full clone set is specified as {coreclr, corefx, core-setup, libuv}.
|
||||
|
||||
- -build [-b] - This defines the set of repositories we want to build. By default the full build set is specified as {coreclr, corefx, core-setup, libuv}
|
||||
|
||||
- -nopatch
|
||||
|
||||
- -payload - a path to a local tarball that we will extract and then subsequently patch. If this is not specified, we pull the latest tarball from the dotnet repository.
|
||||
|
||||
## Work Flow
|
||||
Place Rover in a directory. Run it.
|
||||
|
||||
In the event of a failure, we prevent clean-up. If the failure is not a rover script error, there is likely a rover_failure-repro.sh in the directory where the command failed (you are notified on
|
562
tools/cli-bootstrap/cli.bootstrap.py
Normal file
562
tools/cli-bootstrap/cli.bootstrap.py
Normal file
|
@ -0,0 +1,562 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import json
|
||||
import platform
|
||||
import argparse
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
# for readability
|
||||
from subprocess import call
|
||||
from subprocess import check_output
|
||||
from subprocess import check_call
|
||||
from subprocess import CalledProcessError
|
||||
|
||||
from os import path
|
||||
from os import makedirs
|
||||
|
||||
from string import find
|
||||
from urllib import urlretrieve
|
||||
|
||||
|
||||
# ROVER BASE #
|
||||
class RoverMods:
|
||||
HEADER = '\033[95m'
|
||||
BLUE = '\033[94m'
|
||||
GREEN = '\033[92m'
|
||||
YELLOW = '\033[93m'
|
||||
RED = '\033[91m'
|
||||
WHITE = '\033[97m'
|
||||
BOLD = '\033[1m'
|
||||
UNDERLINE = '\033[4m'
|
||||
ENDC = '\033[0m'
|
||||
|
||||
@staticmethod
|
||||
def Header(line):
|
||||
return RoverMods.HEADER + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Blue(line):
|
||||
return RoverMods.BLUE + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Green(line):
|
||||
return RoverMods.GREEN + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Yellow(line):
|
||||
return RoverMods.YELLOW + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def White(line):
|
||||
return RoverMods.WHITE + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Red(line):
|
||||
return RoverMods.RED + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Bold(line):
|
||||
return RoverMods.BOLD + line + RoverMods.ENDC
|
||||
|
||||
@staticmethod
|
||||
def Underline(line):
|
||||
return RoverMods.UNDERLINE + line + RoverMods.ENDC
|
||||
|
||||
def RoverPrint(line):
|
||||
print(RoverMods.Bold(RoverMods.Header('** ' + RoverMods.Underline('ROVER'))) + ' ' + (str(line)))
|
||||
|
||||
def UnexpectedRoverException(exc_info):
|
||||
RoverPrint(RoverMods.Red('CAUGHT AN UNEXPECTED EXCEPTION: \"' + RoverMods.White('%s'%(str(exc_info[1]))) + '\" of type: %s'%(str(exc_info[0]))))
|
||||
RoverPrint(RoverMods.White('%s'%(str(traceback.print_tb(exc_info[2])))))
|
||||
|
||||
|
||||
# probably a pretty shaky interpretation of the semantic versioning 2.0.0 standard (http://semver.org/)
|
||||
# I really focused on clauses 9, 10 and 11
|
||||
class SemanticVersion:
|
||||
# this is python overloading the '>' operator
|
||||
def __gt__(self, other):
|
||||
# Major, minor, and patch versions are always compared numerically.
|
||||
# Example: 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1.
|
||||
for index, val in enumerate(self.VersionTuple[0]):
|
||||
if self.VersionTuple[0][index] > other.VersionTuple[0][index]:
|
||||
return True
|
||||
|
||||
# When major, minor, and patch are equal, a pre-release version has lower precedence than a normal version.
|
||||
# Example: 1.0.0-alpha < 1.0.0
|
||||
if(len(self.VersionTuple) < len(other.VersionTuple)):
|
||||
return True
|
||||
|
||||
# Precedence for two pre-release versions with the same major, minor, and patch version MUST be determined
|
||||
# by comparing each dot separated identifier from left to right until a difference is found as follows:
|
||||
# identifiers consisting of only digits are compared numerically and identifiers with letters or hyphens are compared
|
||||
# lexically in ASCII sort order.
|
||||
|
||||
# Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
# A larger set of pre-release fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal.
|
||||
# Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0.
|
||||
|
||||
# Maybe a tad hacky - but I treat the remainder of the version (the non numerical piece) as being lex-sorted.
|
||||
# assuming, of course, that we have two to compare.
|
||||
if(len(self.VersionTuple) >= 2 and len(self.VersionTuple) >= 2):
|
||||
if(self.VersionTuple[1] > other.VersionTuple[1]):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def GetVersionTuple(self, versionStr):
|
||||
# a version string potentially looks like this:
|
||||
# 0.0.0-alpha-00000
|
||||
# the first part is canonical: 0.0.0 - it is ordered by the 'ol intuitive manner
|
||||
# the second part is 'build metadata' - it is ordered lexically
|
||||
middleIndex = versionStr.find('-')
|
||||
# if we do not have a middle
|
||||
if middleIndex == -1:
|
||||
array = versionStr.split('.')
|
||||
versionTuple = ([array])
|
||||
else:
|
||||
# otherwise, we'll slice in two
|
||||
versionTuple = (versionStr[0:middleIndex].split('.'), versionStr[middleIndex:len(versionStr)])
|
||||
|
||||
return versionTuple
|
||||
|
||||
def __str__(self):
|
||||
return self.VersionString
|
||||
|
||||
def __init__(self, versionStr):
|
||||
self.VersionTuple = self.GetVersionTuple(versionStr)
|
||||
self.VersionString = versionStr
|
||||
|
||||
# END ROVER BASE #
|
||||
|
||||
class RoverSettings:
|
||||
# Setting dev mode to True means that we keep a folder around.
|
||||
# By Design DevMode is triggered if there is a pre-existing working directory
|
||||
# By Design, when in DevMode we do not run any git commands.
|
||||
_DevMode=False
|
||||
|
||||
# This function needs to be here, because otherwise we wouldnt be able to change DevMode.
|
||||
def FetchOSVariables():
|
||||
try:
|
||||
os_release_path = '/etc/os-release'
|
||||
|
||||
# according to the man page, we should fall back here if the canonical os-release is missing.
|
||||
if not path.exists(os_release_path):
|
||||
os_release_path = '/usr/lib/os-release'
|
||||
|
||||
os_vars = {}
|
||||
with open(os_release_path) as f:
|
||||
for line in f.readlines():
|
||||
line = line.strip()
|
||||
|
||||
if not line: # skip blank lines
|
||||
continue
|
||||
|
||||
data = line.split('=')
|
||||
os_vars[str(data[0]).strip('\n\"')] = str(data[1]).strip('\n\"')
|
||||
|
||||
return os_vars
|
||||
except IOError:
|
||||
RoverPrint(RoverMods.Red('requires \'/etc/os-release/\' to exist. For more information, try ' + RoverMods.White('man os-release')))
|
||||
except:
|
||||
RoverSettings._DevMode = True # to prevent cleanup (to support investigation)
|
||||
RoverPrint(RoverMods.Red('CAUGHT AN UNEXPECTED EXCEPTION: \"' + RoverMods.White("%s") + '\" of type: %s'%(str(sys.exc_info()[1]), str(sys.exc_info()[0]))))
|
||||
RoverPrint(RoverMods.Red(RoverMods.White('%s')%(str(sys.exc_info()[3]))))
|
||||
|
||||
_OsVars = FetchOSVariables()
|
||||
_Rid = '%s.%s-x64'%(_OsVars['ID'], _OsVars['VERSION_ID'])
|
||||
_Moniker = '%s-dotnet'%(_Rid)
|
||||
|
||||
_WorkingDirectory = '%s'%(_Moniker)
|
||||
_srcDirectory = path.join(_WorkingDirectory, "src")
|
||||
_objDirectory = path.join(_WorkingDirectory, "obj")
|
||||
_binDirectory = path.join(_WorkingDirectory, "bin")
|
||||
|
||||
_ScriptDirectory = str(path.dirname(path.abspath(__file__)))
|
||||
_LaunchedFromDirectory = os.getcwd()
|
||||
|
||||
PayloadPath = str('')
|
||||
PatchTargetPath = _binDirectory
|
||||
CloneSet = []
|
||||
BuildSet = []
|
||||
Patch = True
|
||||
|
||||
CoreCLRBinDirectory = ''
|
||||
CoreFXBinDirectory = ''
|
||||
CoreSetupBinDirectory = ''
|
||||
LibUVBinDirectory = ''
|
||||
|
||||
PatchTarget_Shared = ''
|
||||
PatchTarget_SDK = ''
|
||||
PatchTarget_Host = ''
|
||||
|
||||
DotNetCommitHash = 'rover-boot-strap'
|
||||
|
||||
@staticmethod
|
||||
def MaxPrecedence(versionStrA, versionStrB):
|
||||
versionA = SemanticVersion(versionStrA)
|
||||
versionB = SemanticVersion(versionStrB)
|
||||
|
||||
if(versionA > versionB):
|
||||
return versionA
|
||||
|
||||
return versionB
|
||||
|
||||
|
||||
@staticmethod
|
||||
def SelectGreatestPrecendenceDirectory(containerDirectory):
|
||||
maxVersion = '0.0.0-alpha-00000'
|
||||
|
||||
for root, dirs, files in os.walk(containerDirectory):
|
||||
for dirName in dirs:
|
||||
maxVersion = RoverSettings.MaxPrecedence(dirName, maxVersion)
|
||||
|
||||
break # just 'walk' the top level.
|
||||
|
||||
return str(maxVersion)
|
||||
|
||||
@staticmethod
|
||||
def SetPatchTargetPath(pathToFolder):
|
||||
if path.exists(pathToFolder):
|
||||
RoverSettings.PatchTargetPath = pathToFolder
|
||||
# require there to be a Microsoft.NETCore.App in the shared
|
||||
# we will locate the highest version;
|
||||
shared_containerFolder = path.join(pathToFolder, path.join('shared', 'Microsoft.NETCore.App'))
|
||||
RoverSettings.PatchTarget_Shared = path.join(shared_containerFolder, RoverSettings.SelectGreatestPrecendenceDirectory(shared_containerFolder))
|
||||
|
||||
# will locate the highest version and patch that
|
||||
sdk_containerFolder = path.join(pathToFolder, path.join('sdk'))
|
||||
RoverSettings.PatchTarget_SDK = path.join(sdk_containerFolder, RoverSettings.SelectGreatestPrecendenceDirectory(sdk_containerFolder))
|
||||
|
||||
# require the host to be 'fxr', then we take the highest version.
|
||||
host_containerFolder = path.join(pathToFolder, path.join('host', 'fxr'))
|
||||
RoverSettings.PatchTarget_Host = path.join(host_containerFolder, RoverSettings.SelectGreatestPrecendenceDirectory(host_containerFolder))
|
||||
|
||||
|
||||
if path.exists(RoverSettings._WorkingDirectory):
|
||||
RoverPrint(RoverMods.Header(RoverMods.Red('FORCED SETTINGS CHANGE: DEV MODE \'ON\' ')))
|
||||
RoverPrint(RoverMods.Yellow(('will skip all git commands.')))
|
||||
RoverPrint(RoverMods.Yellow(('requires the deletion of the directory \'%s\' to reset the dev-mode trigger.'%(RoverSettings._WorkingDirectory))))
|
||||
|
||||
RoverSettings._DevMode=True
|
||||
|
||||
# A 'Rover Shell Call' is a shell call that we want to be reproduceable in the event of a failure.
|
||||
# namely, something that a developer can go in and 'drill in' on without running the entirety of the
|
||||
# build again.
|
||||
def RoverShellCall(cmd, cwd = None):
|
||||
if not cwd:
|
||||
cwd = os.getcwd()
|
||||
|
||||
try:
|
||||
check_call(cmd, shell=True, cwd=cwd)
|
||||
|
||||
except CalledProcessError as repro_data:
|
||||
RoverSettings._DevMode = True
|
||||
|
||||
repro_filename = 'rover_failure-repro.sh'
|
||||
repro_destination = path.join(cwd, repro_filename)
|
||||
|
||||
# when the call fails, print a repro to the working directory.
|
||||
with open(repro_destination, 'w') as repro_file:
|
||||
repro_file.writelines(['#!/usr/bin/env bash\n', repro_data.cmd + '\n'])
|
||||
|
||||
if os.getuid() == 0:
|
||||
call('chmod +x %s'%(repro_filename), shell=True, cwd=cwd)
|
||||
|
||||
RoverPrint(RoverMods.Red('has detected a failure. A repro shell script has been placed at ') + RoverMods.Yellow(repro_destination))
|
||||
RoverPrint(RoverMods.White('To reproduce the failure:\n\tcd %s\n\t./%s'%(cwd, repro_filename)))
|
||||
RoverPrint(RoverMods.Red('is forcefully closing. Note that re-running Rover will execute it with DevMode enabled (no git commands will be run)'))
|
||||
|
||||
os._exit(1) # if we fail a check_call then we want to bail out asap so the dev can investigate.
|
||||
|
||||
|
||||
|
||||
|
||||
##
|
||||
## ROVER FUNCTION DEFINITIONS
|
||||
##
|
||||
|
||||
# detination_folder is expected to be relative to the _ScriptDirectory.
|
||||
# payload path is expected to be a dotn``et-cli tarball.
|
||||
def SpawnPatchTarget(destination_folder, payload_path):
|
||||
try:
|
||||
if payload_path and not path.isabs(payload_path):
|
||||
payload_path = path.join(RoverSettings._LaunchedFromDirectory, payload_path)
|
||||
|
||||
if not path.isabs(destination_folder):
|
||||
destination_folder = path.join(RoverSettings._LaunchedFromDirectory, destination_folder)
|
||||
|
||||
if not path.exists(str(payload_path)):
|
||||
fallback_url = 'https://dotnetcli.blob.core.windows.net/dotnet/Sdk/rel-1.0.0/dotnet-dev-debian-x64.latest.tar.gz'
|
||||
RoverPrint('could not locate a payload at path: \'%s\' so I am going to download the latest dotnet CLI from %s'%(payload_path, fallback_url))
|
||||
|
||||
payload_filename = 'dotnet-dev-debian-x64.latest.tar.gz'
|
||||
|
||||
RoverPrint(RoverMods.Blue('is downloading latest .NET CLI for bootstrapping (%s)'%(payload_filename)))
|
||||
|
||||
payload_path = path.join(RoverSettings._objDirectory, 'dotnet-dev-debian-x64.latest.tar.gz')
|
||||
|
||||
urlretrieve(fallback_url, payload_path)
|
||||
|
||||
# lets force the path to be made absolute - assuming that the payload path is relative to the directory we launched the script from.
|
||||
# otherwise if we have an abs path already - fantastic.
|
||||
|
||||
RoverShellCall('tar xf %s -C %s'%(payload_path, destination_folder))
|
||||
except:
|
||||
RoverSettings._DevMode = True
|
||||
UnexpectedRoverException(sys.exc_info())
|
||||
|
||||
RoverSettings.SetPatchTargetPath(path.join(RoverSettings._ScriptDirectory, destination_folder))
|
||||
|
||||
def CloneRepositories(cwd,
|
||||
coreclr_commit_hash,
|
||||
corefx_commit_hash,
|
||||
dotnet_commit_hash):
|
||||
try:
|
||||
if not RoverSettings._DevMode:
|
||||
RoverPrint(RoverMods.Blue('is initializing the .NET GitHub repositories.'))
|
||||
|
||||
if 'coreclr' in RoverSettings.CloneSet:
|
||||
if not path.exists(path.join(cwd, 'coreclr')):
|
||||
RoverShellCall('git clone http://www.github.com/dotnet/coreclr', cwd=cwd)
|
||||
RoverShellCall('git checkout %s'%(coreclr_commit_hash), cwd=path.join(cwd, 'coreclr'))
|
||||
|
||||
if 'corefx' in RoverSettings.CloneSet:
|
||||
if not path.exists(path.join(cwd, 'corefx')):
|
||||
RoverShellCall('git clone http://www.github.com/dotnet/corefx', cwd=cwd)
|
||||
RoverShellCall('git checkout %s'%(corefx_commit_hash), cwd=path.join(cwd, 'corefx'))
|
||||
|
||||
if 'core-setup' in RoverSettings.CloneSet:
|
||||
if not path.exists(path.join(cwd, 'core-setup')):
|
||||
RoverShellCall('git clone http://www.github.com/dotnet/core-setup', cwd=cwd)
|
||||
RoverShellCall('git checkout %s'%(dotnet_commit_hash), cwd=path.join(cwd, 'core-setup'))
|
||||
|
||||
if 'libuv' in RoverSettings.CloneSet:
|
||||
if not path.exists(path.join(cwd, 'libuv')):
|
||||
RoverShellCall('git clone http://www.github.com/libuv/libuv', cwd=cwd)
|
||||
# we are fixed to using libuv 1.9.0 - this is the commit hash for that (https://github.com/libuv/libuv/commit/229b3a4cc150aebd6561e6bd43076eafa7a03756)
|
||||
RoverShellCall('git checkout %s'%('229b3a4cc150aebd6561e6bd43076eafa7a03756'), cwd=path.join(cwd, 'libuv'))
|
||||
|
||||
else:
|
||||
RoverPrint(RoverMods.Yellow(('DEVMODE IS ON. Skipping all git calls : I.e. you must manually control git your self.')))
|
||||
|
||||
except:
|
||||
RoverSettings._DevMode = True
|
||||
UnexpectedRoverException(sys.exc_info())
|
||||
|
||||
|
||||
|
||||
def BuildNativeComponents( coreclr_git_directory,
|
||||
corefx_git_directory,
|
||||
core_setup_git_directory,
|
||||
libuv_git_directory):
|
||||
try:
|
||||
RoverPrint(RoverMods.Blue('is building the .NET GitHub repositories.'))
|
||||
|
||||
# Build CoreCLR
|
||||
# skipping non-essential for bootstrapping.
|
||||
if 'coreclr' in RoverSettings.BuildSet:
|
||||
RoverShellCall('./build.sh x64 release skiptests skipnuget', cwd=coreclr_git_directory)
|
||||
|
||||
# Build CoreFX Native Pieces
|
||||
if 'corefx' in RoverSettings.BuildSet:
|
||||
# at different points in the history of CoreFX there have been differing build behaviors, these conditionals
|
||||
# cover that. However, if we find these differences, we will need to adapt.s
|
||||
if path.exists(path.join(corefx_git_directory, 'src', 'Native', 'build-native.sh')):
|
||||
RoverShellCall('./build-native.sh x64 release Linux --numProc 1', cwd="%s/src/Native"%(corefx_git_directory))
|
||||
else:
|
||||
RoverShellCall('./build.sh native x64 release', cwd=corefx_git_directory)
|
||||
|
||||
# Build corehost from core-setup
|
||||
# TODO: declare proper runtime id
|
||||
# TODO: hostver?
|
||||
# TODO: fxrver?
|
||||
# TODO: policyver?
|
||||
if 'core-setup' in RoverSettings.BuildSet:
|
||||
RoverShellCall('./build.sh --arch x64 --rid %s --hostver 0.0.0 --fxrver 0.0.0 --policyver 0.0.0 --commithash %s'%(RoverSettings._Rid, RoverSettings.DotNetCommitHash), cwd="%s/src/corehost"%(core_setup_git_directory))
|
||||
|
||||
# Build libUV
|
||||
if 'libuv' in RoverSettings.BuildSet:
|
||||
RoverShellCall('./autogen.sh', cwd=libuv_git_directory)
|
||||
RoverShellCall('./configure', cwd=libuv_git_directory)
|
||||
RoverShellCall('make', cwd=libuv_git_directory)
|
||||
|
||||
except:
|
||||
RoverSettings._DevMode = True
|
||||
UnexpectedRoverException(sys.exc_info())
|
||||
|
||||
|
||||
def PatchTarget(patchTarget_folder,
|
||||
coreclr_bin_directory,
|
||||
corefx_native_bin_directory,
|
||||
core_setup_cli_bin_directory,
|
||||
libuv_bin_directory):
|
||||
try:
|
||||
if RoverSettings.Patch:
|
||||
RoverPrint(RoverMods.Blue('is patching %s'%(RoverMods.Yellow(patchTarget_folder))))
|
||||
|
||||
# replace native dotnet in the base directory
|
||||
# from core_setup
|
||||
RoverShellCall('cp dotnet %s'%(path.join(patchTarget_folder)), cwd='%s/exe/'%(core_setup_cli_bin_directory))
|
||||
|
||||
# replace native files in 'shared' folder.
|
||||
# from coreclr
|
||||
RoverShellCall('cp *so %s'%(RoverSettings.PatchTarget_Shared), cwd=coreclr_bin_directory)
|
||||
RoverShellCall('cp corerun %s'%(RoverSettings.PatchTarget_Shared), cwd=coreclr_bin_directory)
|
||||
RoverShellCall('cp crossgen %s'%(RoverSettings.PatchTarget_Shared), cwd=coreclr_bin_directory)
|
||||
|
||||
# from core_setup
|
||||
RoverShellCall('cp dotnet %s'%(RoverSettings.PatchTarget_Shared), cwd='%s/exe/'%(core_setup_cli_bin_directory))
|
||||
RoverShellCall('cp libhostpolicy.so %s'%(RoverSettings.PatchTarget_Shared), cwd='%s/dll/'%(core_setup_cli_bin_directory))
|
||||
RoverShellCall('cp libhostfxr.so %s'%(RoverSettings.PatchTarget_Shared), cwd='%s/fxr/'%(core_setup_cli_bin_directory))
|
||||
|
||||
# from corefxcd
|
||||
RoverShellCall('cp System.* %s'%(RoverSettings.PatchTarget_Shared), cwd=corefx_native_bin_directory)
|
||||
|
||||
# from libuv
|
||||
RoverShellCall('cp libuv.so %s'%(RoverSettings.PatchTarget_Shared), cwd=libuv_bin_directory)
|
||||
|
||||
# replace native files in 'sdk' folder.
|
||||
# from core_setup
|
||||
RoverShellCall('cp libhostpolicy.so %s'%(RoverSettings.PatchTarget_SDK), cwd='%s/dll/'%(core_setup_cli_bin_directory))
|
||||
RoverShellCall('cp libhostfxr.so %s'%(RoverSettings.PatchTarget_SDK), cwd='%s/fxr/'%(core_setup_cli_bin_directory))
|
||||
|
||||
# replace native files in 'host' folder.
|
||||
# from core_setup
|
||||
RoverShellCall('cp libhostfxr.so %s'%(RoverSettings.PatchTarget_Host), cwd='%s/fxr/'%(core_setup_cli_bin_directory))
|
||||
|
||||
RoverPrint(RoverMods.Blue('has finished patching %s'%(RoverMods.Yellow(patchTarget_folder))))
|
||||
except:
|
||||
RoverSettings._DevMode = True
|
||||
UnexpectedRoverException(sys.exc_info())
|
||||
|
||||
##
|
||||
## END ROVER FUNCTION DEFINITIONS
|
||||
##
|
||||
|
||||
if __name__ == "__main__":
|
||||
##
|
||||
## COMMAND-LINE BEHAVIOR
|
||||
##
|
||||
|
||||
parser = argparse.ArgumentParser(description = 'Rover is the dotnet bootstrapping tool.')
|
||||
parser.add_argument('-clone', metavar='c', nargs='*', default=['coreclr', 'corefx', 'core-setup', 'libuv'], help='Clones specified repositories in to the working directory. Select from the following repositories: {'
|
||||
+ '%s, %s, %s, %s'%(RoverMods.Red('coreclr'), RoverMods.Blue('corefx'), RoverMods.Green('core-setup'), RoverMods.Yellow('libuv') +'}'))
|
||||
parser.add_argument('-build', metavar='b', nargs='*', default = ['coreclr', 'corefx', 'core-setup', 'libuv'],help='\'Builds\' all native components if no arguments are specified. Otherwise, specify one or more (space separated) arguments from the following : {'
|
||||
+ '%s, %s, %s, %s'%(RoverMods.Red('coreclr'), RoverMods.Blue('corefx'), RoverMods.Green('core-setup'), RoverMods.Yellow('libuv') +'}'))
|
||||
parser.add_argument('-nopatch', action='store_true', default=False, help='prevents the copying of specific native binaries from the pre-built repositories in to the destination directory.')
|
||||
parser.add_argument('-payload', nargs=1, help='Specify a path to a tarball (something that we can tar xf) that contains a version of the dotnet CLI.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.payload:
|
||||
RoverPrint('using payload ' + RoverMods.White(str(args.payload)))
|
||||
|
||||
RoverPrint('Cloning Set: ' + RoverMods.White(str(args.clone)))
|
||||
RoverPrint('Building Set: ' + RoverMods.White(str(args.build)))
|
||||
RoverPrint('Is Patching? ' + RoverMods.White(str(not args.nopatch)))
|
||||
|
||||
RoverSettings.CloneSet = args.clone
|
||||
RoverSettings.BuildSet = args.build
|
||||
|
||||
# I am guessing that users are more inclined to want patching to happen whenever it can, and so I ask
|
||||
# for specificity in the instances that they do not want patching.
|
||||
RoverSettings.Patch = not args.nopatch
|
||||
|
||||
if args.payload:
|
||||
RoverSettings.PayloadPath = args.payload[0]
|
||||
##
|
||||
## END COMMAND-LINE BEHAVIOR
|
||||
##
|
||||
|
||||
##
|
||||
## BEGIN DECLARATIONS
|
||||
##
|
||||
|
||||
coreclr_working_git_directory = path.join(RoverSettings._srcDirectory, 'coreclr')
|
||||
corefx_working_git_directory = path.join(RoverSettings._srcDirectory, 'corefx')
|
||||
core_setup_working_git_directory = path.join(RoverSettings._srcDirectory, 'core-setup')
|
||||
libuv_working_git_directory = path.join(RoverSettings._srcDirectory, 'libuv')
|
||||
|
||||
default_coreclr_bin_directory = '%s/bin/Product/Linux.x64.Release/'%(coreclr_working_git_directory)
|
||||
default_corefx_native_bin_directory = '%s/bin/Linux.x64.Release/Native'%(corefx_working_git_directory)
|
||||
default_core_setup_cli_bin_directory= '%s/src/corehost/cli'%(core_setup_working_git_directory)
|
||||
default_libuv_bin_directory = '%s/.libs'%(libuv_working_git_directory)
|
||||
|
||||
RoverSettings.CoreCLRBinDirectory = default_coreclr_bin_directory
|
||||
RoverSettings.CoreFXBinDirectory = default_corefx_native_bin_directory
|
||||
RoverSettings.CoreSetupBinDirectory = default_core_setup_cli_bin_directory
|
||||
RoverSettings.LibUVBinDirectory = default_libuv_bin_directory
|
||||
|
||||
platform_info = platform.uname()
|
||||
this_distro_name = str(platform.linux_distribution()[0]).lower()
|
||||
|
||||
##
|
||||
## END DECLARATIONS
|
||||
##
|
||||
|
||||
##
|
||||
## BEGIN PROCEDURE
|
||||
##
|
||||
|
||||
try:
|
||||
os.putenv('ID', RoverSettings._OsVars['ID'])
|
||||
os.putenv('VERSION_ID', RoverSettings._OsVars['VERSION_ID'])
|
||||
|
||||
RoverPrint(RoverMods.Blue('RID: %s'%(RoverMods.Green(RoverSettings._Rid))))
|
||||
|
||||
# if we're root, then we will install dependencies
|
||||
# should we ask first? It's going to be running apt-get in 'yes' mode.
|
||||
if os.getuid() == 0:
|
||||
RoverPrint(RoverMods.Yellow('(because sudo) is installing required dependencies to build the native components of the .NET GitHub Repositories.'))
|
||||
|
||||
# are people cool with this?
|
||||
RoverShellCall('chmod +x %s/repo-dependencies-installer.py'%(RoverSettings._ScriptDirectory), cwd=RoverSettings._ScriptDirectory)
|
||||
RoverShellCall('python %s/repo-dependencies-installer.py'%(RoverSettings._ScriptDirectory), cwd=RoverSettings._ScriptDirectory)
|
||||
|
||||
# Spawn our working directory
|
||||
if not path.exists(RoverSettings._WorkingDirectory):
|
||||
makedirs(RoverSettings._WorkingDirectory)
|
||||
makedirs(RoverSettings._srcDirectory)
|
||||
makedirs(RoverSettings._objDirectory)
|
||||
makedirs(RoverSettings._binDirectory)
|
||||
|
||||
|
||||
SpawnPatchTarget(RoverSettings._binDirectory, RoverSettings.PayloadPath)
|
||||
|
||||
# Fetch the commit hashes from the native files.
|
||||
coreclr_output = check_output('strings libcoreclr.so | grep @\(#\)', shell = True, cwd=RoverSettings.PatchTarget_Shared)
|
||||
corefx_output = check_output('strings System.Native.so | grep @\(#\)', shell = True, cwd=RoverSettings.PatchTarget_Shared)
|
||||
|
||||
dotnet_commit_hash = check_output('strings dotnet | grep "[a-f0-9]\{40\}"', shell = True, cwd=RoverSettings.PatchTarget_Shared)
|
||||
coreclr_commit_hash = coreclr_output[find(coreclr_output, 'Commit Hash: ') + len('Commit Hash: '):len(coreclr_output)]
|
||||
corefx_commit_hash = corefx_output[find(corefx_output, 'Commit Hash: ') + len('Commit Hash: '):len(corefx_output)]
|
||||
|
||||
RoverSettings.DotNetCommitHash = dotnet_commit_hash
|
||||
|
||||
CloneRepositories(RoverSettings._srcDirectory,
|
||||
coreclr_commit_hash,
|
||||
corefx_commit_hash,
|
||||
dotnet_commit_hash)
|
||||
|
||||
BuildNativeComponents(coreclr_working_git_directory,
|
||||
corefx_working_git_directory,
|
||||
core_setup_working_git_directory,
|
||||
libuv_working_git_directory)
|
||||
|
||||
PatchTarget(RoverSettings.PatchTargetPath,
|
||||
RoverSettings.CoreCLRBinDirectory,
|
||||
RoverSettings.CoreFXBinDirectory,
|
||||
RoverSettings.CoreSetupBinDirectory,
|
||||
RoverSettings.LibUVBinDirectory)
|
||||
|
||||
RoverPrint(RoverMods.Green('spawned a \'dotnet\' in %s'%(RoverMods.Yellow('./' + path.relpath(RoverSettings.PatchTargetPath) + '/'))) + RoverMods.Green('(enjoy!)'))
|
||||
except:
|
||||
RoverSettings._DevMode = True
|
||||
UnexpectedRoverException(sys.exc_info())
|
||||
|
||||
|
||||
##
|
||||
## END PROCEDURE
|
||||
##
|
8
tools/cli-bootstrap/dockerfiles/bake.sh
Normal file
8
tools/cli-bootstrap/dockerfiles/bake.sh
Normal file
|
@ -0,0 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
for dir in */ ; do
|
||||
echo "$dir"
|
||||
pushd $dir
|
||||
name=${dir%"/"}
|
||||
docker build -t "rover:$name" .
|
||||
popd
|
||||
done
|
8
tools/cli-bootstrap/dockerfiles/centos71/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/centos71/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM centos:7.1.1503
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/debian8/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/debian8/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM debian:8.0
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/fedora23/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/fedora23/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM fedora:23
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/opensuse13.2/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/opensuse13.2/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM opensuse:13.2
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/opensuse42.1/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/opensuse42.1/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM opensuse:42.1
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/ubuntu1404/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/ubuntu1404/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM ubuntu:14.04
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/ubuntu1604/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/ubuntu1604/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM ubuntu:16.04
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
8
tools/cli-bootstrap/dockerfiles/ubuntu1610/Dockerfile
Normal file
8
tools/cli-bootstrap/dockerfiles/ubuntu1610/Dockerfile
Normal file
|
@ -0,0 +1,8 @@
|
|||
FROM ubuntu:16.10
|
||||
MAINTAINER Bryan P. Arant <bryanar@microsoft.com>
|
||||
RUN apt-get -qqy update
|
||||
RUN apt-get -qqy install git
|
||||
RUN apt-get -qqy install python
|
||||
VOLUME /env/rover
|
||||
WORKDIR /env/rover
|
||||
ENTRYPOINT python rover.py
|
39
tools/cli-bootstrap/repo-dependencies-installer.py
Normal file
39
tools/cli-bootstrap/repo-dependencies-installer.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import json
|
||||
|
||||
from subprocess import call
|
||||
from subprocess import check_output
|
||||
from os import path
|
||||
|
||||
# Debian .deb apt, apt-cache, apt-get, dpkg
|
||||
# Ubuntu .deb apt, apt-cache, apt-get, dpkg
|
||||
# CentOS .rpm yum
|
||||
# Fedora .rpm dnf
|
||||
# FreeBSD Ports,.txz make, pkg
|
||||
|
||||
def Detect(pm_name):
|
||||
aptget_check_output = check_output('whereis %s'%(pm_name), shell=True)
|
||||
|
||||
if(len(str(aptget_check_output).strip()) > len('%s:'%(pm_name))):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
scriptDirectory = path.dirname(path.abspath(__file__))
|
||||
dependencies = json.load(open(path.join(scriptDirectory, 'repo-dependencies.json'), mode='r'))
|
||||
|
||||
if Detect('apt-get'):
|
||||
print('detected apt-get.')
|
||||
for dep in dependencies['apt-get']:
|
||||
call('apt-get -qqy install %s'%(str(dep)), shell=True)
|
||||
elif Detect('yum'):
|
||||
print('detected yum.')
|
||||
|
||||
for dep in dependencies['yum']:
|
||||
call('yum -qy install %s'%(str(dep)), shell=True)
|
||||
else:
|
||||
print('failed to find a compatible package manager.')
|
||||
|
||||
print('TODO: Print list of dependencies, or attempt to fetch them from the web?')
|
38
tools/cli-bootstrap/repo-dependencies.json
Normal file
38
tools/cli-bootstrap/repo-dependencies.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"apt-get":
|
||||
[
|
||||
"g++",
|
||||
"cmake",
|
||||
"llvm-3.5",
|
||||
"clang-3.5",
|
||||
"lldb-3.5",
|
||||
"lldb-3.5-dev",
|
||||
"libunwind8",
|
||||
"libunwind8-dev",
|
||||
"gettext",
|
||||
"libicu-dev",
|
||||
"liblttng-ust-dev",
|
||||
"libcurl4-openssl-dev",
|
||||
"libssl-dev",
|
||||
"uuid-dev",
|
||||
"libkrb5-dev",
|
||||
"automake",
|
||||
"libtool-bin"
|
||||
],
|
||||
"yum":
|
||||
[
|
||||
|
||||
],
|
||||
"dnf":
|
||||
[
|
||||
|
||||
],
|
||||
"pkg":
|
||||
[
|
||||
|
||||
],
|
||||
"ports":
|
||||
[
|
||||
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue