FeaturizersLibrary/bootstrap_impl.py

332 строки
12 KiB
Python

# ----------------------------------------------------------------------
# |
# | bootstrap_impl.py
# |
# | David Brownell <db@DavidBrownell.com>
# | 2019-05-21 08:23:15
# |
# ----------------------------------------------------------------------
# |
# | Copyright David Brownell 2019
# | Distributed under the Boost Software License, Version 1.0. See
# | accompanying file LICENSE_1_0.txt or copy at
# | http://www.boost.org/LICENSE_1_0.txt.
# |
# ----------------------------------------------------------------------
"""Performs repository bootstrap activities (Enlistment and setup)"""
import os
import shutil
import sys
import textwrap
from collections import OrderedDict
import inflect as inflect_mod
import six
import CommonEnvironment
from CommonEnvironment.CallOnExit import CallOnExit
from CommonEnvironment import CommandLine
from CommonEnvironment import FileSystem
from CommonEnvironment import Process
from CommonEnvironment.Shell.All import CurrentShell
from CommonEnvironment.StreamDecorator import StreamDecorator
from CommonEnvironment import StringHelpers
# ----------------------------------------------------------------------
_script_fullpath = CommonEnvironment.ThisFullpath()
_script_dir, _script_name = os.path.split(_script_fullpath)
# ----------------------------------------------------------------------
# Tuples in the form:
# ("<repo name>", "<clone command line>", "<setup command suffix>" or None)
_REPO_DATA = [
(
"Common_cpp_Clang_8",
'git clone https://github.com/davidbrownell/Common_cpp_Clang_8 "{output_dir}"',
None,
),
(
"Common_cpp_Clang_Common",
'git clone https://github.com/davidbrownell/Common_cpp_Clang_Common "{output_dir}"',
None,
),
(
"Common_cpp_Common",
'git clone https://github.com/davidbrownell/Common_cpp_Common "{output_dir}"',
None,
),
]
if CurrentShell.CategoryName == "Linux":
_REPO_DATA += [
(
"Common_cpp_binutils",
'git clone https://github.com/davidbrownell/Common_cpp_binutils "{output_dir}"',
None,
),
(
"Common_cpp_GCC",
'git clone https://github.com/davidbrownell/Common_cpp_GCC "{output_dir}"',
None,
),
]
elif CurrentShell.CategoryName == "Windows":
_REPO_DATA += [
(
"Common_cpp_MSVC_2019",
'git clone https://github.com/davidbrownell/Common_cpp_MSVC_2019 "{output_dir}"',
None,
),
(
"Common_cpp_MSVC_Common",
'git clone https://github.com/davidbrownell/Common_cpp_MSVC_Common "{output_dir}"',
None,
),
(
"Common_cpp_MSVC_WindowsKits_10",
'git clone https://github.com/davidbrownell/Common_cpp_MSVC_WindowsKits_10 "{output_dir}"',
None,
),
]
else:
raise Exception("'{}' is not supported OS".format(CurrentShell.CategoryName))
_ACTIVATION_REPO_CONFIGURATION = "<x64|featurizer_prep>"
# ----------------------------------------------------------------------
inflect = inflect_mod.engine()
# ----------------------------------------------------------------------
@CommandLine.EntryPoint(
setup_args=CommandLine.EntryPoint.Parameter(
"Optional arguments passed to this repository's setup command",
),
)
@CommandLine.Constraints(
output_dir=CommandLine.DirectoryTypeInfo(),
setup_args=CommandLine.StringTypeInfo(
arity="?",
),
output_stream=None,
)
def EntryPoint(
output_dir,
verbose=False,
setup_args=None,
output_stream=sys.stdout,
):
with StreamDecorator(output_stream).DoneManager(
line_prefix="",
prefix="\nResults: ",
suffix="\n",
) as dm:
repo_data = OrderedDict()
enlistment_repositories = []
sync_repositories = []
dm.stream.write("Calculating enlistment repositories...")
with dm.stream.DoneManager(
done_suffix=lambda: "{} found for enlistment".format(
inflect.no("repository", len(enlistment_repositories)),
),
suffix="\n",
) as this_dm:
for data in _REPO_DATA:
repo_name = data[0]
repo_output_dir = os.path.join(
output_dir,
repo_name.replace("_", os.path.sep),
)
if not os.path.isdir(repo_output_dir):
enlistment_repositories.append((repo_output_dir, data))
else:
sync_repositories.append((repo_output_dir, data))
repo_data[repo_output_dir] = data
repo_data[_script_dir] = (_script_dir, None, setup_args)
if enlistment_repositories:
dm.stream.write(
"Enlisting in {}...".format(
inflect.no("repository", len(enlistment_repositories)),
),
)
with dm.stream.DoneManager(
suffix="\n",
) as enlist_dm:
for index, (repo_output_dir, data) in enumerate(enlistment_repositories):
enlist_dm.stream.write(
"'{}' ({} of {})...".format(
data[0],
index + 1,
len(enlistment_repositories),
),
)
with enlist_dm.stream.DoneManager() as this_dm:
FileSystem.MakeDirs(os.path.dirname(repo_output_dir))
temp_directory = repo_output_dir + "_tmp"
sink = six.moves.StringIO()
this_dm.result = Process.Execute(
data[1].format(
output_dir=temp_directory,
),
StreamDecorator(
[
sink,
StreamDecorator(
this_dm.stream if verbose else None,
line_prefix="INFO: ",
),
],
),
)
if this_dm.result != 0:
if not verbose:
this_dm.stream.write(sink.getvalue())
return this_dm.result
shutil.move(temp_directory, repo_output_dir)
if CurrentShell.CategoryName == "Linux":
CurrentShell.UpdateOwnership(output_dir)
if sync_repositories:
dm.stream.write(
"Syncing {}...".format(inflect.no("repository", len(sync_repositories))),
)
with dm.stream.DoneManager(
suffix="\n",
) as sync_dm:
sync_command_template = '{} PullAndUpdate "/directory={{}}"'.format(
CurrentShell.CreateScriptName("SCM"),
)
for index, (repo_output_dir, data) in enumerate(sync_repositories):
sync_dm.stream.write(
"'{}' ({} of {})...".format(
data[0],
index + 1,
len(sync_repositories),
),
)
with sync_dm.stream.DoneManager() as this_dm:
this_dm.result, output = Process.Execute(
sync_command_template.format(repo_output_dir),
)
if this_dm.result != 0:
this_dm.stream.write(output)
if sync_dm.result != 0:
return sync_dm.result
dm.stream.write(
"Setting up {}...".format(inflect.no("repository", len(repo_data))),
)
with dm.stream.DoneManager(
suffix="\n",
) as setup_dm:
command_line_template = "Setup{} {{suffix}}".format(
CurrentShell.ScriptExtension,
)
for index, (repo_output_dir, data) in enumerate(six.iteritems(repo_data)):
setup_dm.stream.write(
"'{}' ({} of {})...".format(data[0], index + 1, len(repo_data)),
)
with setup_dm.stream.DoneManager() as this_dm:
prev_dir = os.getcwd()
os.chdir(repo_output_dir)
with CallOnExit(lambda: os.chdir(prev_dir)):
command_line = command_line_template.format(
suffix=data[2] or "",
)
if CurrentShell.CategoryName == "Linux":
command_line = "./{}".format(command_line)
sink = six.moves.StringIO()
this_dm.result = Process.Execute(
command_line,
StreamDecorator(
[
sink,
StreamDecorator(
this_dm.stream if verbose else None,
line_prefix="INFO: ",
),
],
),
)
if this_dm.result != 0:
if not verbose:
this_dm.stream.write(sink.getvalue())
return this_dm.result
dm.stream.write(
StringHelpers.LeftJustify(
textwrap.dedent(
"""\
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
The enlistment and setup of all repositories was successful. To begin
development activities, please run the following command. Note that
this command must be run every time you open a new terminal window.
{}{} {}
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
""",
).format(
". " if CurrentShell.CategoryName == "Linux" else "",
os.path.join(
_script_dir,
"Activate{}{}".format(
".{}".format(
os.getenv("DEVELOPMENT_ENVIRONMENT_ENVIRONMENT_NAME"),
)
if os.getenv("DEVELOPMENT_ENVIRONMENT_ENVIRONMENT_NAME")
!= "DefaultEnv"
else "",
CurrentShell.ScriptExtension,
),
),
_ACTIVATION_REPO_CONFIGURATION or "",
),
16,
skip_first_line=False,
),
)
return dm.result
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
# ----------------------------------------------------------------------
if __name__ == "__main__":
try:
sys.exit(CommandLine.Main())
except KeyboardInterrupt:
pass