Skip to content
Merged
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
103 changes: 32 additions & 71 deletions diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,33 @@
# Licensed under the terms of the MIT License
# (see winpython/__init__.py for details)


import os
from pathlib import Path
import re
import shutil
from packaging import version
from winpython import utils

CHANGELOGS_DIR = Path(__file__).parent / "changelogs"
assert CHANGELOGS_DIR.is_dir()


class Package(object):
class Package:
# SourceForge Wiki syntax:
PATTERN = r"\[([a-zA-Z\-\:\/\.\_0-9]*)\]\(([^\]\ ]*)\) \| ([^\|]*) \| ([^\|]*)"
# Google Code Wiki syntax:
PATTERN_OLD = r"\[([a-zA-Z\-\:\/\.\_0-9]*) ([^\]\ ]*)\] \| ([^\|]*) \| ([^\|]*)"

def __init__(self):
self.name = None
self.version = None
self.description = None
self.url = None
self.name = self.version = self.description = self.url = None

def __str__(self):
text = f"{self.name} {self.version}"
text += f"\r\n{self.description}\r\nWebsite: {self.url}"
return text
return f"{self.name} {self.version}\r\n{self.description}\r\nWebsite: {self.url}"

def from_text(self, text):
try:
self.url, self.name, self.version, self.description = re.match(
self.PATTERN_OLD, text
).groups()
except AttributeError:
self.name, self.url, self.version, self.description = re.match(
self.PATTERN, text
).groups()
match = re.match(self.PATTERN_OLD, text) or re.match(self.PATTERN, text)
if not match:
raise ValueError("Text does not match expected pattern")
self.name, self.url, self.version, self.description = match.groups()

def to_wiki(self):
return f" * [{self.name}]({self.url}) {self.version} ({self.description})\r\n"
Expand All @@ -51,8 +41,7 @@ def upgrade_wiki(self, other):
assert self.name.replace("-", "_").lower() == other.name.replace("-", "_").lower()
return f" * [{self.name}]({self.url}) {other.version} → {self.version} ({self.description})\r\n"


class PackageIndex(object):
class PackageIndex:
WINPYTHON_PATTERN = r"\#\# WinPython\-*[0-9b-t]* ([0-9\.a-zA-Z]*)"
TOOLS_LINE = "### Tools"
PYTHON_PACKAGES_LINE = "### Python packages"
Expand All @@ -72,9 +61,8 @@ def from_file(self, basedir):
fname = CHANGELOGS_DIR / f"WinPython{self.flavor}-{self.architecture}bit-{self.version}.md"
if not fname.exists():
raise FileNotFoundError(f"Changelog file not found: {fname}")
with open(fname, "r", encoding = 'utf-8') as fdesc:
text = fdesc.read()
self.from_text(text)
with open(fname, "r", encoding=utils.guess_encoding(fname)[0]) as fdesc:
self.from_text(fdesc.read())

def from_text(self, text):
version = re.match(self.WINPYTHON_PATTERN + self.flavor, text).groups()[0]
Expand All @@ -88,12 +76,7 @@ def from_text(self, text):
elif line == self.PYTHON_PACKAGES_LINE:
tools_flag, python_flag = False, True
continue
elif line in (
self.HEADER_LINE1,
self.HEADER_LINE2,
"<details>",
"</details>",
):
elif line in (self.HEADER_LINE1, self.HEADER_LINE2, "<details>", "</details>"):
continue
if tools_flag or python_flag:
package = Package()
Expand All @@ -103,105 +86,83 @@ def from_text(self, text):
else:
self.python_packages[package.name] = package


def diff_package_dicts(old_packages, new_packages):
"""Return difference between package old and package new"""

# wheel replace '-' per '_' in key
old = {k.replace("-", "_").lower(): v for k, v in old_packages.items()}
new = {k.replace("-", "_").lower(): v for k, v in new_packages.items()}
text = ""
# New packages

if new_keys := sorted(set(new) - set(old)):
text += "New packages:\r\n\r\n" + "".join(new[k].to_wiki() for k in new_keys) + "\r\n"

# Upgraded packages
if upgraded := [new[k].upgrade_wiki(old[k]) for k in sorted(set(old) & set(new)) if old[k].version != new[k].version]:
text += "Upgraded packages:\r\n\r\n" + f"{''.join(upgraded)}" + "\r\n"

# Removed packages
if removed_keys := sorted(set(old) - set(new)):
text += "Removed packages:\r\n\r\n" + "".join(old[k].to_wiki() for k in removed_keys) + "\r\n"
return text


def find_closer_version(version1, basedir=None, flavor="", architecture=64):
"""Find version which is the closest to `version`"""
builddir = str(Path(basedir) / f"bu{flavor}")
func = lambda name: re.match(
r"WinPython%s-%sbit-([0-9\.]*)\.(txt|md)" % (flavor, architecture),
name,
)
versions = [func(name).groups()[0] for name in os.listdir(builddir) if func(name)]
# versions:['3.10.0.1', '3.10.10.0', '3.10.2.0'.... '3.10.8.1', '3.10.9.0']
try:
index = versions.index(version1)
except ValueError:
builddir = Path(basedir) / f"bu{flavor}"
pattern = re.compile(rf"WinPython{flavor}-{architecture}bit-([0-9\.]*)\.(txt|md)")
versions = [pattern.match(name).groups()[0] for name in os.listdir(builddir) if pattern.match(name)]

if version1 not in versions:
raise ValueError(f"Unknown version {version1}")

from packaging import version
version_below = '0.0.0.0'
for v in versions:
if version.parse(v) > version.parse(version_below) and version.parse(v)<version.parse(version1):
if version.parse(version_below) < version.parse(v) and version.parse(v) < version.parse(version1):
version_below = v
if version_below =='0.0.0.0':
return version1
else:
return version_below

return version_below if version_below != '0.0.0.0' else version1

def compare_package_indexes(version2, version1=None, basedir=None, flavor="", flavor1=None,architecture=64):
"""Compare two package index Wiki pages"""
version1 = version1 if version1 else find_closer_version(version2, basedir, flavor, architecture)
flavor1 = flavor1 if flavor1 else flavor
pi1 = PackageIndex(version1, basedir, flavor1, architecture)
pi2 = PackageIndex(version2, basedir, flavor, architecture)

text = "\r\n".join(
[
f"## History of changes for WinPython-{architecture}bit {version2 + flavor}",
"",
f"The following changes were made to WinPython-{architecture}bit"
f" distribution since version {version1 + flavor1}.",
"",
"<details>",
"",
]

text = (
f"## History of changes for WinPython-{architecture}bit {version2 + flavor}\r\n\r\n"
f"The following changes were made to WinPython-{architecture}bit distribution since version {version1 + flavor1}.\r\n\r\n"
"<details>\r\n\r\n"
)

tools_text = diff_package_dicts(pi1.other_packages, pi2.other_packages)
if tools_text:
text += PackageIndex.TOOLS_LINE + "\r\n\r\n" + tools_text

py_text = diff_package_dicts(pi1.python_packages, pi2.python_packages)
if py_text:
text += PackageIndex.PYTHON_PACKAGES_LINE + "\r\n\r\n" + py_text

text += "\r\n</details>\r\n* * *\r\n"
return text


def _copy_all_changelogs(version, basedir, flavor="", architecture=64):
basever = ".".join(version.split(".")[:2])
pattern = re.compile(rf"WinPython{flavor}-{architecture}bit-{basever}([0-9\.]*)\.(txt|md)")
for name in os.listdir(CHANGELOGS_DIR):
if re.match(
r"WinPython%s-%sbit-%s([0-9\.]*)\.(txt|md)"
% (flavor, architecture, basever),
name,
):
if pattern.match(name):
shutil.copyfile(CHANGELOGS_DIR / name, Path(basedir) / f"bu{flavor}" / name)


def write_changelog(version2, version1=None, basedir=None, flavor="", architecture=64):
"""Write changelog between version1 and version2 of WinPython"""
_copy_all_changelogs(version2, basedir, flavor, architecture)
print("comparing_package_indexes", version2, basedir, flavor, architecture)
changelog_text = compare_package_indexes(version2, version1, basedir, flavor, architecture=architecture)
output_file = Path(basedir) / f"bu{flavor}" / f"WinPython{flavor}-{architecture}bit-{version2}_History.md"

with open(output_file, "w", encoding="utf-8-sig") as fdesc:
with open(output_file, "w", encoding="utf-8") as fdesc:
fdesc.write(changelog_text)
# Copy to winpython/changelogs
shutil.copyfile(output_file, CHANGELOGS_DIR / output_file.name)


if __name__ == "__main__":
print(compare_package_indexes("3.7.4.0", "3.7.2.0", "C:\WinP\bd37", "Zero", architecture=32))
print(compare_package_indexes("3.7.4.0", "3.7.2.0", r"C:\WinP\bd37", "Zero", architecture=32))
write_changelog("3.7.4.0", "3.7.2.0", r"C:\WinP\bd37", "Ps2", architecture=64)