| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | #!/usr/bin/env python3 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | # pylint: disable=docstring-first-line-empty | 
					
						
							|  |  |  | # we shouldn't change this default header | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | """
 | 
					
						
							|  |  |  |  " ScummVM - Graphic Adventure Engine | 
					
						
							|  |  |  |  " | 
					
						
							|  |  |  |  " ScummVM is the legal property of its developers, whose names | 
					
						
							|  |  |  |  " are too numerous to list here. Please refer to the COPYRIGHT | 
					
						
							|  |  |  |  " file distributed with this source distribution. | 
					
						
							|  |  |  |  " | 
					
						
							|  |  |  |  " This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  " modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  " as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  " of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  " | 
					
						
							|  |  |  |  " This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  " but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  " GNU General Public License for more details. | 
					
						
							|  |  |  |  " | 
					
						
							|  |  |  |  " You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  " along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  " Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  " | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | # pylint: enable=docstring-first-line-empty | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | import argparse | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | import csv | 
					
						
							|  |  |  | import io | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | import os | 
					
						
							|  |  |  | import subprocess | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  | import sys | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | import urllib.request | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | import xml.dom.minidom | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | import xml.etree.ElementTree as ElemTree | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | from dataclasses import dataclass | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  | from datetime import date, datetime | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | from pathlib import Path | 
					
						
							|  |  |  | from typing import Tuple, final, Set, AnyStr, List | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | from zipfile import ZipFile | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 12:20:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | @dataclass(frozen=True, eq=True)  # immutable | 
					
						
							|  |  |  | class GUID: | 
					
						
							|  |  |  |     """GUID Data for XML generation""" | 
					
						
							|  |  |  |     filename_root: str | 
					
						
							|  |  |  |     gid: str | 
					
						
							|  |  |  |     element_name: str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | GUIDS: final(Set[GUID]) = {GUID(filename_root='games', gid='1946612063', element_name='game'), | 
					
						
							|  |  |  |                            GUID(filename_root='engines', gid='0', element_name='engine'), | 
					
						
							|  |  |  |                            GUID(filename_root='companies', gid='226191984', element_name='company'), | 
					
						
							|  |  |  |                            GUID(filename_root='series', gid='1095671818', element_name='serie') | 
					
						
							|  |  |  |                            } | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | MIN_PYTHON: final(Tuple[int]) = (3, 8)  # min python version is 3.8 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | URL_HEAD: final = ("https://docs.google.com/spreadsheets/d/e/" | 
					
						
							|  |  |  |                    + "2PACX-1vQamumX0p-DYQa5Umi3RxX-pHM6RZhAj1qvUP0jTmaqutN9FwzyriRSXlO9rq6kR60pGIuPvCDzZL3s" | 
					
						
							|  |  |  |                    + "/pub?output=tsv") | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | URL_ICONS_LIST: final = 'https://downloads.scummvm.org/frs/icons/LIST' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | ICON_DIR: final = 'icons' | 
					
						
							|  |  |  | ENCODING: final = 'utf-8' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | ZIP_NAME_PREFIX: final = 'gui-icons-' | 
					
						
							|  |  |  | ZIP_NAME_EXTENSION: final = '.dat' | 
					
						
							|  |  |  | ZIP_DATE_FORMAT: final = '%Y%m%d' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | LIST_NAME: final = 'LIST' | 
					
						
							|  |  |  | LIST_DELIM: final = ',' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | DATE_FORMAT: final = '%Y-%m-%d' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | FIRST_HASH: final = 'b2a20aad85714e0fea510483007e5e96d84225ca' | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | ChangedFileSet = Set[str] | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  | def main(last_update: datetime or None, last_hash: str, listfile_entries: List[str]) -> None: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     """Our main function.
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     :param last_update: datetime | 
					
						
							|  |  |  |             An optional last_update datetime. Day + 1 after the last creation of icons.zip | 
					
						
							|  |  |  |             If not present please provide last_hash | 
					
						
							|  |  |  |     :param last_hash: str | 
					
						
							|  |  |  |             The (newest) last_hash value of the LIST file. It is preferred to use this param. | 
					
						
							|  |  |  |     :param listfile_entries: List[str] | 
					
						
							|  |  |  |             When the LIST file is already read (finding last_hash) than we could reuse it. | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if last_update is None and last_hash is None: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         print('Please provider either last_update or last_hash') | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # ### Step 1: Generating XMLs | 
					
						
							|  |  |  |     xml_file_names = generate_xmls() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ### Step 2: Creating a zip file with the changed icons (only icons directory!) | 
					
						
							|  |  |  |     changed_icon_file_names = get_changed_icon_file_names(last_update, last_hash) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ### Step 3: pack xmls / icons into one zip | 
					
						
							|  |  |  |     new_iconsdat_name = write_iconsdat(list(changed_icon_file_names) + xml_file_names) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # ### Step 4: create new LIST file | 
					
						
							|  |  |  |     new_listfile_name = write_new_listfile(new_iconsdat_name, listfile_entries) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print('\nPls upload/commit the new files:') | 
					
						
							|  |  |  |     print('\t' + new_iconsdat_name) | 
					
						
							|  |  |  |     print('\t' + new_listfile_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def generate_xmls() -> List[str]: | 
					
						
							|  |  |  |     """Generates the XMLs to be stored in the new zip file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :return: a List of generated XML files. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('Step 1: generate XMLs') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |     xml_files: List[str] = [] | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |     for guid in GUIDS: | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |         url = URL_HEAD + "&gid=" + guid.gid | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |         print("Processing " + guid.filename_root + "... ", end="", flush=True) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |         root = ElemTree.Element(guid.filename_root) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         with urllib.request.urlopen(url) as file: | 
					
						
							|  |  |  |             output = csv.DictReader(io.StringIO(file.read().decode(ENCODING)), delimiter='\t') | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |             for product in output: | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |                 product_xml = ElemTree.SubElement(root, guid.element_name) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |                 for key, value in product.items(): | 
					
						
							|  |  |  |                     product_xml.set(key, value) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         dom = xml.dom.minidom.parseString(ElemTree.tostring(root).decode(ENCODING)) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         #   on win machines there could be an error without specifying utf-8 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |         xml_file_name = guid.filename_root + ".xml" | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         with open(xml_file_name, "w", encoding=ENCODING) as file: | 
					
						
							|  |  |  |             file.write(dom.toprettyxml()) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         xml_files.append(xml_file_name) | 
					
						
							|  |  |  |         print("done") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return xml_files | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def get_changed_icon_file_names(last_update: datetime, last_hash: str) -> ChangedFileSet: | 
					
						
							|  |  |  |     """Returns all changed ICON file names.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param last_update: last update as datetime (hash is preferred) | 
					
						
							|  |  |  |     :param last_hash: the hash of the last commit (stored in last entry of the LIST file) | 
					
						
							|  |  |  |     :return: a ChangedFileSet with all changed icons. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if last_hash: | 
					
						
							|  |  |  |         print('\nStep 2: fetching changed icons using hash ' + last_hash) | 
					
						
							|  |  |  |         last_iconsdat_date = None | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         last_iconsdat_date = last_update.strftime(DATE_FORMAT) | 
					
						
							|  |  |  |         print('\nStep 2: fetching changed icons since ' + last_iconsdat_date) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     check_isscummvmicons_repo() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     is_repo_uptodate() | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if last_hash: | 
					
						
							|  |  |  |         commit_hash = last_hash | 
					
						
							|  |  |  |     else: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         commit_hashes = get_commit_hashes(last_iconsdat_date) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # no changes nothing to do | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |         if len(commit_hashes) < 1: | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |             print('no new /changed icons since: ' + last_iconsdat_date) | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |             sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # last (sorted reverse!) commit_hash is sufficient | 
					
						
							|  |  |  |         commit_hash = commit_hashes[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return collect_commit_file_names(commit_hash) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def write_new_listfile(new_iconsdat_name: str, listfile_entries: List[str]) -> str: | 
					
						
							|  |  |  |     """Writes a new LIST file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |     :param new_iconsdat_name: the name of the new icons-dat file. | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     :param listfile_entries: the entries of the LIST file (if already read) - an empty list is Ok. | 
					
						
							|  |  |  |     :return: the name of the LIST file written. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('\nStep 4: generating a new ' + LIST_NAME + ' file') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |     if len(listfile_entries) < 1: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         tmp_listfile_entries = get_listfile_entries() | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     else: | 
					
						
							|  |  |  |         print(LIST_NAME + ' already read - using given values') | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         tmp_listfile_entries = listfile_entries | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     last_commit_master = get_last_hash_from_master() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     new_iconsdat_size = os.path.getsize(new_iconsdat_name) | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     tmp_listfile_entries.append( | 
					
						
							|  |  |  |         new_iconsdat_name + LIST_DELIM + str(new_iconsdat_size) + LIST_DELIM + last_commit_master) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if os.path.exists(LIST_NAME): | 
					
						
							|  |  |  |         print(LIST_NAME + ' exists - file will be overwritten') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print('writing new ' + LIST_NAME + ' entries...', end='', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |     with open(LIST_NAME, mode='w', encoding=ENCODING) as outfile: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         outfile.write('\n'.join(tmp_listfile_entries)) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print('done') | 
					
						
							|  |  |  |     return LIST_NAME | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | def get_last_hash_from_master() -> str: | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     """Reads the last hash code from the origin/master.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :return: the hash of the latest commit. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     lines = run_git('rev-parse', 'HEAD') | 
					
						
							|  |  |  |     if len(lines) < 1: | 
					
						
							|  |  |  |         print('ERROR: no commit found') | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return lines[0].decode(ENCODING).rstrip() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | def get_listfile_lasthash() -> Tuple[str, List[str]]: | 
					
						
							|  |  |  |     """Reads the LIST file and returns the last hash and the list of lines.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :return: A String with the last hash (from the LIST file) and a List containing all the lines of the LIST file. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('no inputDate argument - fetching last hash from ' + LIST_NAME + '... ', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     listfile_entries = get_listfile_entries() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     last_entry_values = listfile_entries[-1].split(LIST_DELIM) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     if len(last_entry_values) == 1 or len(last_entry_values) == 2: | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         # remove this if/else after LIST file is committed with FIRST_HASH and just use else print/quit() | 
					
						
							|  |  |  |         if len(listfile_entries) == 1: | 
					
						
							|  |  |  |             print("WARNING: Workaround - fixing first line of LIST file! Pls remove this fix after the first run") | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |             last_entry_values.append(FIRST_HASH) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |             listfile_entries[0] = listfile_entries[0].rstrip() + "," + FIRST_HASH | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     else: | 
					
						
							|  |  |  |         print("Wrong LIST entry format - please add inputDate argument yyyymmdd and run the script again") | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return last_entry_values[2], listfile_entries | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def get_listfile_entries() -> List[str]: | 
					
						
							|  |  |  |     """Reads and returns all lines / entries of the LIST file.
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     :return: a List of strings with the content of the LIST file. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('reading existing ' + LIST_NAME + ' entries...', end='', flush=True) | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |     with urllib.request.urlopen(URL_ICONS_LIST) as file: | 
					
						
							|  |  |  |         output = file.read().decode(ENCODING).splitlines() | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         print('done') | 
					
						
							|  |  |  |         return output | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def check_isscummvmicons_repo() -> None: | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |     """Different checks for the local repo - will quit() the script if there is any error.""" | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('checking local directory is scummvm-icons repo ... ', end='', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     output_show_origin = run_git('remote', 'show', 'origin') | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     if not is_any_git_repo(output_show_origin): | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         print('error') | 
					
						
							|  |  |  |         print('not a git repository (or any of the parent directories)') | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # wrong repo | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     if not is_scummvmicons_repo(output_show_origin): | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         print('error') | 
					
						
							|  |  |  |         print('local folder is not a scummvm-icons git repo') | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         sys.exit(1) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print('done') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def is_scummvmicons_repo(output_showorigin: List[AnyStr]) -> bool: | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     """ Checks if the local repo is a scummvm-icons repo""" | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # should be the correct repo | 
					
						
							|  |  |  |     if any('Fetch URL: https://github.com/scummvm/scummvm-icons' in line.decode(ENCODING) | 
					
						
							|  |  |  |            for line in output_showorigin): | 
					
						
							|  |  |  |         return True | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def is_any_git_repo(output_showorigin: List[AnyStr]) -> bool: | 
					
						
							|  |  |  |     """Checks if the local folder belongs to a git repo.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param output_showorigin: The output of 'show origin'. | 
					
						
							|  |  |  |     :return: True if it is a git repo | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # outside of any local git repo | 
					
						
							|  |  |  |     if any('fatal: not a git repository' in line.decode(ENCODING) for line in output_showorigin): | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def is_repo_uptodate() -> bool: | 
					
						
							|  |  |  |     """Checks if the local repo is up to date.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :return: True if the local repo is up-to-date | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # ### check local repo is up to date | 
					
						
							|  |  |  |     print('checking local repo is up to date...', end='', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if len(run_git('fetch', '--dry-run')) > 0: | 
					
						
							|  |  |  |         print('warning') | 
					
						
							|  |  |  |         print('fetch with changes - make sure that your local branch is up to date') | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # second variant of check | 
					
						
							|  |  |  |     run_git('update-index', '--refresh', '--unmerged') | 
					
						
							|  |  |  |     if len(run_git('diff-index', '--quiet', 'HEAD')) > 0: | 
					
						
							|  |  |  |         print('warning') | 
					
						
							|  |  |  |         print('fetch with changes - make sure that your local branch is up to date') | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |         return False | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     print('done') | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     return True | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def get_commit_hashes(last_icondat_date: str) -> List[str]: | 
					
						
							|  |  |  |     """Collects all commit hashes since a given date.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param last_icondat_date: last icon-dat generation date. | 
					
						
							|  |  |  |     :return: all commits since last_icondat_date. | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |     commit_hashes: List[str] = [] | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     # using log with reverse to fetch the commit_hashes | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |     for commit_lines in run_git('log', '--reverse', '--oneline', "--since='" + last_icondat_date + "'"): | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         # split without sep - runs of consecutive whitespace are regarded as a single separator | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         commit_hashes.append(commit_lines.decode(ENCODING).split(maxsplit=1)[0]) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return commit_hashes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def collect_commit_file_names(commit_hash: str) -> ChangedFileSet: | 
					
						
							|  |  |  |     """Collects all filnames (icons) from a git commit.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param commit_hash: the hash of the git commit. | 
					
						
							|  |  |  |     :return: all changed icons (from the 'icons' directory) | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |     changed_file_set: Set[str] = set()  # set, no duplicates | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('fetching file names for commit:' + commit_hash + ' ... ', end='', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for file in run_git('diff', '--name-only', commit_hash + '..'): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # stdout will contain bytes - convert to utf-8 and strip cr/lf if present | 
					
						
							|  |  |  |         git_file_name = file.decode(ENCODING).rstrip() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if git_file_name.startswith(ICON_DIR + '/') or git_file_name.startswith(ICON_DIR + 'icons\\'): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # build local path with a defined local folder / sanitize filenames | 
					
						
							|  |  |  |             local_path = '.' + os.path.sep + ICON_DIR + os.path.sep + Path(git_file_name).name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 16:37:36 +02:00
										 |  |  |             # file must exist / running from wrong path would result in non-existing files | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |             if os.path.exists(local_path): | 
					
						
							|  |  |  |                 changed_file_set.add(local_path) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 print('WARNING: file "' + local_path + '" is not in local repo - deleted? ') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print('done') | 
					
						
							|  |  |  |     print(f'icons (files) changed: {len(changed_file_set)}') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return changed_file_set | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def write_iconsdat(changed_files: List[str]) -> str: | 
					
						
							|  |  |  |     """Creates a new file (will overwrite existing files) packing all changed_files into it.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     :param changed_files: The changes files (icons) for the new icons-dat file. | 
					
						
							|  |  |  |     :return: a string with the name of the created zip (icons-dat) file. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('\nStep 3: generating a new zip file...') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # using today for the zip name | 
					
						
							|  |  |  |     today = date.today() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     zip_name = ZIP_NAME_PREFIX + today.strftime(ZIP_DATE_FORMAT) + ZIP_NAME_EXTENSION | 
					
						
							|  |  |  |     if os.path.exists(zip_name): | 
					
						
							|  |  |  |         print(zip_name + ' exists - file will be overwritten') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print('creating zip ' + zip_name + '... ', end='', flush=True) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     with ZipFile(zip_name, mode='w', compresslevel=9) as new_entries: | 
					
						
							| 
									
										
										
										
											2022-03-27 18:29:44 +02:00
										 |  |  |         for changed_file in changed_files: | 
					
						
							|  |  |  |             new_entries.write(changed_file) | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |     print('done') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return zip_name | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | def run_git(*git_args) -> List[AnyStr]: | 
					
						
							|  |  |  |     """Executes a git command and returns the stdout (as Line[AnyStr])
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 13:28:13 +02:00
										 |  |  |     :param *git_args:  A string, or a sequence of program arguments. | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  |     :return: The StdOut as List[AnyStr] | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     my_env = os.environ.copy()  # copy current environ | 
					
						
							|  |  |  |     my_env["LANG"] = "C"  # add lang C | 
					
						
							|  |  |  |     with subprocess.Popen(args=['git'] + list(git_args), stdout=subprocess.PIPE, env=my_env) as child_proc: | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  |         return child_proc.stdout.readlines() | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-27 15:08:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | ########### | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 12:20:59 +02:00
										 |  |  | if sys.version_info < MIN_PYTHON: | 
					
						
							|  |  |  |     sys.exit(f"Python {MIN_PYTHON[0]}.{MIN_PYTHON[1]} or later is required.\n") | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | # check args / get date | 
					
						
							|  |  |  | argParser = argparse.ArgumentParser(usage='%(prog)s [lastUpdate]') | 
					
						
							|  |  |  | argParser.add_argument('lastUpdate', help='last update - date format: yyyymmdd', default=argparse.SUPPRESS, nargs='?') | 
					
						
							|  |  |  | args = argParser.parse_args() | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | # optional param, if not present fetch last_update from the LIST file | 
					
						
							|  |  |  | if 'lastUpdate' in args: | 
					
						
							| 
									
										
										
										
											2022-03-29 12:20:59 +02:00
										 |  |  |     arg_last_update = datetime.strptime(args.lastUpdate, '%Y%m%d') | 
					
						
							|  |  |  |     print('using provided inputDate: ' + arg_last_update.strftime(DATE_FORMAT) + '\n') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # we have to read the LIST later (if needed) | 
					
						
							|  |  |  |     main(arg_last_update, "", []) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-21 21:12:45 +01:00
										 |  |  | else: | 
					
						
							| 
									
										
										
										
											2022-03-29 12:20:59 +02:00
										 |  |  |     arg_last_hash, arg_listfile_entries = get_listfile_lasthash() | 
					
						
							|  |  |  |     print('using last hash from ' + LIST_NAME + ': ' + arg_last_hash + '\n') | 
					
						
							| 
									
										
										
										
											2021-11-12 15:55:46 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-29 12:20:59 +02:00
										 |  |  |     # listfile_entries as param, no need the read the LIST file twice | 
					
						
							|  |  |  |     main(None, arg_last_hash, arg_listfile_entries) |