Skip to content

Commit

Permalink
EdkRepo: Add the log command
Browse files Browse the repository at this point in the history
Add the log command which generates an interleaved log
of all repositories in the workspace allowing the user to view
a single unified history of the project.

Signed-off-by: Ashley E Desimone <[email protected]>
  • Loading branch information
ashedesimone committed Jun 7, 2021
1 parent 19fd597 commit 8f17d70
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 3 deletions.
18 changes: 18 additions & 0 deletions edkrepo/commands/arguments/log_args.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env python3
#
## @file
# log_args.py
#
# Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#

''' Contains the help and description strings for arguments in the
combo command meta data.
'''

#Args for log_command.py
LOG_COMMAND_DESCRIPTION = 'Combined log output for all repos across the workspace'
NUMBER_HELP = 'Only show NUMBER most recent commits'
ONELINE_HELP = 'Show a single-line summary for each commit'
COLOR_HELP = 'Force color output (useful with \'less -r\')'
113 changes: 113 additions & 0 deletions edkrepo/commands/log_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env python3
#
## @file
# log_command.py
#
# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#

import os
import subprocess
import sys

from datetime import datetime

from colorama import Fore

from edkrepo.commands.edkrepo_command import EdkrepoCommand
from edkrepo.commands.edkrepo_command import ColorArgument
import edkrepo.commands.arguments.log_args as arguments
from edkrepo.common.common_repo_functions import sort_commits, find_less
from edkrepo.common.ui_functions import init_color_console, print_safe, safe_str
from edkrepo.config.config_factory import get_workspace_path, get_workspace_manifest

class LogCommand(EdkrepoCommand):
def __init__(self):
super().__init__()

def get_metadata(self):
metadata = {}
metadata['name'] = 'log'
metadata['help-text'] = arguments.LOG_COMMAND_DESCRIPTION
args = []
metadata['arguments'] = args
args.append({'name' : 'number',
'short-name': 'n',
'action': 'store',
'positional' : False,
'required' : False,
'help-text' : arguments.NUMBER_HELP})
args.append({'name' : 'oneline',
'short-name': 'o',
'positional' : False,
'required' : False,
'help-text' : arguments.ONELINE_HELP})
args.append(ColorArgument)
return metadata

def run_command(self, args, config):
if args.number:
try:
args.number = int(args.number)
except ValueError:
print("Error: \'{}\' is not an integer".format(args.number))
return

init_color_console(args.color)

workspace_path = get_workspace_path()
manifest = get_workspace_manifest()

sorted_commit_list = sort_commits(manifest, workspace_path, args.number)

less_path, use_less = find_less()

if use_less:
output_string = ''
separator = '\n'

for commit in sorted_commit_list:
if args.oneline:
oneline = "{}{:.9s}{} {:15.15s}{} {:.80s}".format(Fore.YELLOW,
commit.hexsha,
Fore.CYAN,
os.path.basename(commit.repo.working_dir),
Fore.RESET,
safe_str(commit.summary))
if use_less:
output_string = separator.join((output_string, oneline))

else:
print(oneline)
else:
time_string = datetime.utcfromtimestamp(commit.authored_date - commit.author_tz_offset).strftime("%c")
time_zone_string = "{}{:04.0f}".format("-" if commit.author_tz_offset > 0 else "+",
abs(commit.author_tz_offset/36))
hexsha_string = "{}commit {}{} ({}){}".format(Fore.YELLOW,
commit.hexsha,
Fore.CYAN,
os.path.basename(commit.repo.working_dir),
Fore.RESET)
author_string = "Author: {} <{}>".format(commit.author.name, commit.author.email)
date_string = "Date: {} {}".format(time_string, time_zone_string)
if use_less:
output_string = separator.join((output_string, hexsha_string, safe_str(author_string), date_string))

commit_string = ""
for line in commit.message.splitlines():
commit_string = separator.join((commit_string, safe_str(" {}".format(line))))

output_string = separator.join((output_string, commit_string, separator))
else:
print(hexsha_string)
print_safe(author_string)
print(date_string)
print("")
for line in commit.message.splitlines():
print_safe(" {}".format(line))
print("")
if less_path:
less_output = subprocess.Popen([str(less_path), '-F', '-R', '-S', '-X', '-K'], stdin=subprocess.PIPE, stdout=sys.stdout, universal_newlines=True)
less_output.communicate(input=output_string)

23 changes: 22 additions & 1 deletion edkrepo/common/common_repo_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,4 +644,25 @@ def find_project_in_index(project, ci_index_file, global_manifest_dir, except_me
else:
raise EdkrepoInvalidParametersException(except_message)

return global_manifest_path
return global_manifest_path

def find_less():
use_less = False
if sys.platform == 'win32':
git_path = get_full_path('git.exe')
if git_path is not None:
less_path = os.path.join(os.path.dirname(os.path.dirname(git_path)), 'usr', 'bin', 'less.exe')
if os.path.isfile(less_path):
use_less = True
return less_path, use_less
less_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(git_path))), 'usr', 'bin', 'less.exe')
if os.path.isfile(less_path):
use_less = True
return less_path, use_less
return None, use_less
else:
use_less = False
less_path = get_full_path('less')
if less_path:
use_less = True
return less_path, use_less
14 changes: 12 additions & 2 deletions edkrepo/common/ui_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## @file
# ui_functions.py
#
# Copyright (c) 2017- 2020, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2017- 2021, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#

Expand All @@ -12,7 +12,6 @@
import string

import git

import colorama

from edkrepo.common.pathfix import expanduser
Expand Down Expand Up @@ -47,3 +46,14 @@ def display_git_output(output_data, verbose=False):
print(output_data[1])
if verbose and output_data[2]:
print(output_data[2])

def print_safe(input_string):
print(safe_str(input_string))

def safe_str(input_string):
safe_str = ''
for char in input_string:
if char not in string.printable:
char = '?'
safe_str = ''.join((safe_str, str(char)))
return safe_str

0 comments on commit 8f17d70

Please sign in to comment.