-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding a build script #33
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e908338
Adding a build script
jorive 3a077b2
Marking default build to release.
jorive 6f72857
Removed dead code.
jorive eb01ee1
Refactor build.py and moved code to a module
jorive 21fe6ce
Moving build.py into ./scripts/
jorive b8718b4
Move the coreclr output to its own folder under bin
jorive File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
#!/usr/bin/env python3 | ||
|
||
''' | ||
Builds the CoreClr Benchmarks | ||
''' | ||
|
||
from subprocess import CalledProcessError | ||
from traceback import format_exc | ||
from typing import Tuple | ||
|
||
import argparse | ||
import datetime | ||
import logging | ||
import os | ||
import sys | ||
|
||
from build.common import get_logging_console_handler | ||
from build.common import get_logging_file_handler | ||
from build.common import get_repo_root_path | ||
from build.common import is_supported_version | ||
from build.common import log_start_message | ||
from build.common import LAUNCH_TIME | ||
from build.common import LOGGING_FORMATTER | ||
from build.exception.FatalError import FatalError | ||
from build.parser.TargetFrameworkAction import TargetFrameworkAction | ||
from build.process.DotNet import DotNet | ||
from build.runner.RunCommand import RunCommand | ||
|
||
|
||
def generate_log_file_name() -> str: | ||
'''Generates a unique log file name for the current script''' | ||
log_dir = os.path.join(get_repo_root_path(), 'logs') | ||
if not os.path.exists(log_dir): | ||
os.makedirs(log_dir) | ||
|
||
script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0] | ||
timestamp = datetime.datetime.fromtimestamp(LAUNCH_TIME).strftime( | ||
"%Y%m%d%H%M%S") | ||
log_file_name = '{}-{}-pid{}.log'.format( | ||
timestamp, script_name, os.getpid()) | ||
return os.path.join(log_dir, log_file_name) | ||
|
||
|
||
def init_logging(verbose: bool) -> str: | ||
'''Initializes the loggers used by the script.''' | ||
logging.getLogger().setLevel(logging.INFO) | ||
|
||
log_file_name = generate_log_file_name() | ||
|
||
for logger in ['shell', 'script']: | ||
logging.getLogger(logger).addHandler(get_logging_console_handler( | ||
LOGGING_FORMATTER, verbose)) | ||
logging.getLogger(logger).addHandler(get_logging_file_handler( | ||
log_file_name, LOGGING_FORMATTER)) | ||
logging.getLogger(logger).setLevel(logging.INFO) | ||
|
||
return log_file_name | ||
|
||
|
||
def check_requirements(log_file: str, verbose: bool) -> None: | ||
''' | ||
Checks that the requirements needs to build the CoreClr benchmarks are met. | ||
''' | ||
logging.getLogger('script').info("Making sure dotnet exists...") | ||
try: | ||
cmdline = ['dotnet', '--info'] | ||
RunCommand(log_file, cmdline, verbose=verbose).run('dotnet-info') | ||
except Exception: | ||
raise FatalError("Cannot find dotnet.") | ||
|
||
|
||
def process_arguments() -> Tuple[str, list, bool]: | ||
''' | ||
Function used to parse the command line arguments passed to this script | ||
through the cli. | ||
''' | ||
parser = argparse.ArgumentParser( | ||
description="Builds the CoreClr benchmarks.", | ||
) | ||
parser.add_argument( | ||
'-c', '--configuration', | ||
metavar='CONFIGURATION', | ||
required=False, | ||
default='release', | ||
choices=['debug', 'release'], | ||
type=str.casefold, | ||
help='Configuration use for building the project (default "release").', | ||
) | ||
parser.add_argument( | ||
'-f', '--frameworks', | ||
metavar='FRAMEWORK', | ||
required=False, | ||
nargs='*', | ||
action=TargetFrameworkAction, | ||
default=TargetFrameworkAction.supported_target_frameworks(), | ||
help='Target frameworks to publish for (default all).', | ||
) | ||
parser.add_argument( | ||
'-v', '--verbose', | ||
required=False, | ||
default=False, | ||
action='store_true', | ||
help='Turns on verbosity (default "False")', | ||
) | ||
|
||
# --verbosity <LEVEL> | ||
# ['quiet', 'minimal', 'normal', 'detailed', 'diagnostic'] | ||
|
||
args = parser.parse_args() | ||
return ( | ||
args.configuration, | ||
args.frameworks, | ||
args.verbose | ||
) | ||
|
||
|
||
def build_coreclr( | ||
log_file: str, | ||
configuration: str, | ||
frameworks: list, | ||
verbose: bool) -> None: | ||
'''Builds the CoreClr set of benchmarks (Code Quality).''' | ||
working_directory = os.path.join( | ||
get_repo_root_path(), 'src', 'coreclr', 'PerformanceHarness') | ||
csproj_file = 'PerformanceHarness.csproj' | ||
|
||
dotnet = DotNet(log_file, working_directory, csproj_file, verbose) | ||
dotnet.restore() | ||
for framework in frameworks: | ||
dotnet.publish(configuration, framework, 'CoreClr-Benchmarks') | ||
|
||
|
||
def main() -> int: | ||
'''Script main entry point.''' | ||
try: | ||
if not is_supported_version(): | ||
raise FatalError("Unsupported python version.") | ||
|
||
args = process_arguments() | ||
configuration, frameworks, verbose = args | ||
log_file = init_logging(verbose) | ||
|
||
log_start_message('script') | ||
check_requirements(log_file, verbose) | ||
build_coreclr(log_file, configuration, frameworks, verbose) | ||
|
||
return 0 | ||
except FatalError as ex: | ||
logging.getLogger('script').error(str(ex)) | ||
except CalledProcessError as ex: | ||
logging.getLogger('script').error( | ||
'Command: "%s", exited with status: %s', ex.cmd, ex.returncode) | ||
except IOError as ex: | ||
logging.getLogger('script').error( | ||
"I/O error (%s): %s", ex.errno, ex.strerror) | ||
except SystemExit: # Argparse throws this exception when it exits. | ||
pass | ||
except Exception: | ||
logging.getLogger('script')( | ||
'Unexpected error: {}'.format(sys.exc_info()[0])) | ||
logging.getLogger('script')(format_exc()) | ||
raise | ||
return 1 | ||
|
||
|
||
if __name__ == "__main__": | ||
sys.exit(main()) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
''' | ||
Common functionality used by the .NET Performance Repository build scripts. | ||
''' | ||
|
||
from contextlib import contextmanager | ||
|
||
import datetime | ||
import logging | ||
import os | ||
import sys | ||
import time | ||
|
||
|
||
LAUNCH_TIME = time.time() | ||
LOGGING_FORMATTER = logging.Formatter( | ||
fmt='[%(asctime)s][%(levelname)s] %(message)s', | ||
datefmt="%Y-%m-%d %H:%M:%S") | ||
|
||
|
||
def is_supported_version() -> bool: | ||
'''Checks if the script is running on the supported version (>=3.5).''' | ||
return sys.version_info.major > 2 and sys.version_info.minor > 4 | ||
|
||
|
||
def log_start_message(name) -> None: | ||
'''Used to log a start event message header.''' | ||
start_msg = "Script started at {}".format( | ||
str(datetime.datetime.fromtimestamp(LAUNCH_TIME))) | ||
logging.getLogger(name).info('-' * len(start_msg)) | ||
logging.getLogger(name).info(start_msg) | ||
logging.getLogger(name).info('-' * len(start_msg)) | ||
|
||
|
||
def get_script_path() -> str: | ||
'''Gets this script directory.''' | ||
return sys.path[0] | ||
|
||
|
||
def get_repo_root_path() -> str: | ||
'''Gets repository root directory.''' | ||
return os.path.abspath(os.path.join(get_script_path(), '..')) | ||
|
||
|
||
@contextmanager | ||
def push_dir(path: str = None) -> None: | ||
''' | ||
Adds the specified location to the top of a location stack, then changes to | ||
the specified directory. | ||
''' | ||
if path: | ||
prev = os.getcwd() | ||
try: | ||
logging.getLogger('shell').info('pushd "%s"', path) | ||
os.chdir(path) | ||
yield | ||
finally: | ||
logging.getLogger('shell').info('popd') | ||
os.chdir(prev) | ||
else: | ||
yield | ||
|
||
|
||
def get_logging_console_handler( | ||
fmt: logging.Formatter, | ||
verbose: bool) -> logging.StreamHandler: | ||
''' | ||
Gets a logging console handler (logging.StreamHandler) based on the | ||
specified formatter (logging.Formatter) and verbosity. | ||
''' | ||
console_handler = logging.StreamHandler() | ||
console_handler.setLevel(logging.INFO if verbose else logging.WARNING) | ||
console_handler.setFormatter(fmt) | ||
return console_handler | ||
|
||
|
||
def get_logging_file_handler( | ||
file: str, | ||
fmt: logging.Formatter, | ||
set_formatter: bool = True) -> logging.FileHandler: | ||
''' | ||
Gets a logging file handler (logging.FileHandler) based on the specified | ||
formatter (logging.Formatter). | ||
''' | ||
file_handler = logging.FileHandler(file) | ||
file_handler.setLevel(logging.INFO) | ||
if set_formatter: | ||
file_handler.setFormatter(fmt) | ||
return file_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
''' | ||
Contains the definition of the FatalError exception. | ||
''' | ||
|
||
|
||
class FatalError(Exception): | ||
''' | ||
Raised for various script errors regarding environment and build | ||
requirements. | ||
''' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
''' | ||
Contains the definition of the TargetFrameworkAction type used to parse | ||
the .NET Cli the supported target frameworks. | ||
''' | ||
|
||
import argparse | ||
|
||
|
||
class TargetFrameworkAction(argparse.Action): | ||
''' | ||
Used by the ArgumentParser to represent the information needed to parse the | ||
supported .NET Core target frameworks argument from the command line. | ||
''' | ||
|
||
def __call__(self, parser, namespace, values, option_string=None): | ||
if values: | ||
wrong_choices = [] | ||
for value in values: | ||
if value not in self.supported_target_frameworks(): | ||
wrong_choices.append(value) | ||
if wrong_choices: | ||
message = ', '.join(wrong_choices) | ||
message = 'Invalid choice(s): {}'.format(message) | ||
raise argparse.ArgumentError(self, message) | ||
setattr(namespace, self.dest, values) | ||
|
||
@staticmethod | ||
def supported_target_frameworks() -> list: | ||
'''List of supported .NET Core target frameworks.''' | ||
return ['netcoreapp1.1', 'netcoreapp2.0', 'netcoreapp2.1', 'net461'] |
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Should probably be verbosity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was planning to add verbosity to the script for debuggability. This flag was to turn it on/off.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that he has a potential verbosity level option commented out, I feel like the bool of verbose on or off makes sense as verbose, rather than verbosity. Verbosity implies levels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the verbose setting that we pass to the publish and restore steps is always the default? Is this just for controlling the verbosity of the script?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-v
is only for enable/disable the script verbosity.