Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 29 additions & 8 deletions src/fosslight_util/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@
# SPDX-License-Identifier: Apache-2.0

import os
import re
import sys
import yaml
from fosslight_util.help import print_package_version
from fosslight_util.time import format_display_time, format_running_time


def dump_result_log(result_log):
log_text = yaml.safe_dump(result_log, allow_unicode=True, sort_keys=True)
log_text = re.sub(r"Running time: ['\"](.+?)['\"]\n", r"Running time: \1\n", log_text)
return log_text.strip()


class CoverItem:
tool_name_key = "Tool information"
start_time_key = "Start time"
start_time_key = "Running time"
python_ver_key = "Python version"
analyzed_path_key = "Analyzed path"
excluded_path_key = "Excluded path"
Expand All @@ -23,7 +32,8 @@ class CoverItem:
"fosslight_binary"
]

def __init__(self, tool_name="", start_time="", input_path="", comment="", exclude_path=[], simple_mode=True):
def __init__(self, tool_name="", start_time="", input_path="", comment="", exclude_path=[], simple_mode=True,
finish_time=""):
if simple_mode:
self.tool_name = f'{tool_name} v{print_package_version(tool_name, "", False)}'
else:
Expand All @@ -34,11 +44,9 @@ def __init__(self, tool_name="", start_time="", input_path="", comment="", exclu
])
self.tool_name = f'{first_pkg} ({remaining_pkgs})'

if start_time:
date, time = start_time.split('_')
self.start_time = f'{date}, {time[0:2]}:{time[2:4]}'
else:
self.start_time = ""
self.start_time = start_time
self.finish_time = finish_time
self.running_time = self._format_running_time()
self.input_path = os.path.abspath(input_path)
self.exclude_path = ", ".join(exclude_path)
self.comment = comment
Expand All @@ -57,6 +65,19 @@ def get_sort_order(self):
def __lt__(self, other):
return self.get_sort_order() < other.get_sort_order()

def set_finish_time(self, finish_time):
self.finish_time = finish_time
self.running_time = self._format_running_time()

def _format_running_time(self):
if not self.start_time:
return ""

if not self.finish_time:
return format_display_time(self.start_time)

return format_running_time(self.start_time, self.finish_time)

def create_merged_comment(self, cover_items):
if not cover_items:
return ""
Expand All @@ -69,7 +90,7 @@ def create_merged_comment(self, cover_items):
def get_print_json(self):
json_item = {}
json_item[self.tool_name_key] = self.tool_name
json_item[self.start_time_key] = self.start_time
json_item[self.start_time_key] = self.running_time
json_item[self.python_ver_key] = self.python_version
json_item[self.analyzed_path_key] = self.input_path
json_item[self.excluded_path_key] = self.exclude_path
Expand Down
6 changes: 6 additions & 0 deletions src/fosslight_util/oss_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import hashlib
from fosslight_util.constant import LOGGER_NAME, FOSSLIGHT_SCANNER, COMMENT_DELIMITER
from fosslight_util.cover import CoverItem
from fosslight_util.time import current_timestamp_utc
from typing import List, Dict

_logger = logging.getLogger(LOGGER_NAME)
Expand Down Expand Up @@ -211,6 +212,11 @@ def set_cover_comment(self, value):
else:
self.cover.comment = value

def set_cover_finish_time(self, finish_time=""):
if not finish_time:
finish_time = current_timestamp_utc()
self.cover.set_finish_time(finish_time)

def get_cover_comment(self):
return [item.strip() for item in self.cover.comment.split(COMMENT_DELIMITER)]

Expand Down
60 changes: 60 additions & 0 deletions src/fosslight_util/time.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2024 LG Electronics Inc.
# SPDX-License-Identifier: Apache-2.0

from datetime import datetime, timezone, timedelta

_TIMESTAMP_FMT = '%Y%m%d_%H%M%S'
_DISPLAY_TZ = timezone(timedelta(hours=9)) # KST (UTC+9)


def current_timestamp_utc() -> str:
"""Return current time as UTC wall-clock string for internal storage."""
return datetime.now(timezone.utc).strftime(_TIMESTAMP_FMT)


def timestamp_for_filename(utc_timestamp: str) -> str:
"""Convert UTC storage timestamp to KST for file and directory names."""
if not utc_timestamp:
return current_timestamp_for_filename()
return _parse_utc_timestamp(utc_timestamp).astimezone(_DISPLAY_TZ).strftime(_TIMESTAMP_FMT)


def current_timestamp_for_filename() -> str:
"""Return current time as KST wall-clock string for file and directory names."""
return timestamp_for_filename(current_timestamp_utc())


def _parse_utc_timestamp(value: str) -> datetime:
return datetime.strptime(value, _TIMESTAMP_FMT).replace(tzinfo=timezone.utc)


def format_display_time(value: str) -> str:
return _parse_utc_timestamp(value).astimezone(_DISPLAY_TZ).strftime('%Y%m%d_%H:%M:%S')


def _format_duration_compact(total_seconds: int) -> str:
total_seconds = max(0, total_seconds)
hours, remaining_seconds = divmod(total_seconds, 3600)
minutes, seconds = divmod(remaining_seconds, 60)

duration_items = []
if hours > 0:
duration_items.append(f'{hours}h')
if minutes > 0:
duration_items.append(f'{minutes}m')
duration_items.append(f'{seconds}s')
return f'({" ".join(duration_items)})'


def format_running_time(start_time: str, finish_time: str) -> str:
start_utc = _parse_utc_timestamp(start_time)
finish_utc = _parse_utc_timestamp(finish_time)
total_seconds = int((finish_utc - start_utc).total_seconds())

start_display = start_utc.astimezone(_DISPLAY_TZ).strftime('%Y%m%d_%H:%M:%S')
finish_display = finish_utc.astimezone(_DISPLAY_TZ).strftime('%Y%m%d_%H:%M:%S')
duration = _format_duration_compact(total_seconds)

return f'{start_display} ~ {finish_display} {duration}'
Loading