6
6
# Licensed under the terms of the MIT License
7
7
# (see winpython/__init__.py for details)
8
8
9
-
10
9
import os
11
10
from pathlib import Path
12
11
import re
13
12
import shutil
13
+ from packaging import version
14
14
from winpython import utils
15
15
16
16
CHANGELOGS_DIR = Path (__file__ ).parent / "changelogs"
17
17
assert CHANGELOGS_DIR .is_dir ()
18
18
19
-
20
- class Package (object ):
19
+ class Package :
21
20
# SourceForge Wiki syntax:
22
21
PATTERN = r"\[([a-zA-Z\-\:\/\.\_0-9]*)\]\(([^\]\ ]*)\) \| ([^\|]*) \| ([^\|]*)"
23
22
# Google Code Wiki syntax:
24
23
PATTERN_OLD = r"\[([a-zA-Z\-\:\/\.\_0-9]*) ([^\]\ ]*)\] \| ([^\|]*) \| ([^\|]*)"
25
24
26
25
def __init__ (self ):
27
- self .name = None
28
- self .version = None
29
- self .description = None
30
- self .url = None
26
+ self .name = self .version = self .description = self .url = None
31
27
32
28
def __str__ (self ):
33
- text = f"{ self .name } { self .version } "
34
- text += f"\r \n { self .description } \r \n Website: { self .url } "
35
- return text
29
+ return f"{ self .name } { self .version } \r \n { self .description } \r \n Website: { self .url } "
36
30
37
31
def from_text (self , text ):
38
- try :
39
- self .url , self .name , self .version , self .description = re .match (
40
- self .PATTERN_OLD , text
41
- ).groups ()
42
- except AttributeError :
43
- self .name , self .url , self .version , self .description = re .match (
44
- self .PATTERN , text
45
- ).groups ()
32
+ match = re .match (self .PATTERN_OLD , text ) or re .match (self .PATTERN , text )
33
+ if not match :
34
+ raise ValueError ("Text does not match expected pattern" )
35
+ self .name , self .url , self .version , self .description = match .groups ()
46
36
47
37
def to_wiki (self ):
48
38
return f" * [{ self .name } ]({ self .url } ) { self .version } ({ self .description } )\r \n "
@@ -51,8 +41,7 @@ def upgrade_wiki(self, other):
51
41
assert self .name .replace ("-" , "_" ).lower () == other .name .replace ("-" , "_" ).lower ()
52
42
return f" * [{ self .name } ]({ self .url } ) { other .version } → { self .version } ({ self .description } )\r \n "
53
43
54
-
55
- class PackageIndex (object ):
44
+ class PackageIndex :
56
45
WINPYTHON_PATTERN = r"\#\# WinPython\-*[0-9b-t]* ([0-9\.a-zA-Z]*)"
57
46
TOOLS_LINE = "### Tools"
58
47
PYTHON_PACKAGES_LINE = "### Python packages"
@@ -72,9 +61,8 @@ def from_file(self, basedir):
72
61
fname = CHANGELOGS_DIR / f"WinPython{ self .flavor } -{ self .architecture } bit-{ self .version } .md"
73
62
if not fname .exists ():
74
63
raise FileNotFoundError (f"Changelog file not found: { fname } " )
75
- with open (fname , "r" , encoding = 'utf-8' ) as fdesc :
76
- text = fdesc .read ()
77
- self .from_text (text )
64
+ with open (fname , "r" , encoding = utils .guess_encoding (fname )[0 ]) as fdesc :
65
+ self .from_text (fdesc .read ())
78
66
79
67
def from_text (self , text ):
80
68
version = re .match (self .WINPYTHON_PATTERN + self .flavor , text ).groups ()[0 ]
@@ -88,12 +76,7 @@ def from_text(self, text):
88
76
elif line == self .PYTHON_PACKAGES_LINE :
89
77
tools_flag , python_flag = False , True
90
78
continue
91
- elif line in (
92
- self .HEADER_LINE1 ,
93
- self .HEADER_LINE2 ,
94
- "<details>" ,
95
- "</details>" ,
96
- ):
79
+ elif line in (self .HEADER_LINE1 , self .HEADER_LINE2 , "<details>" , "</details>" ):
97
80
continue
98
81
if tools_flag or python_flag :
99
82
package = Package ()
@@ -103,105 +86,83 @@ def from_text(self, text):
103
86
else :
104
87
self .python_packages [package .name ] = package
105
88
106
-
107
89
def diff_package_dicts (old_packages , new_packages ):
108
90
"""Return difference between package old and package new"""
109
91
110
92
# wheel replace '-' per '_' in key
111
93
old = {k .replace ("-" , "_" ).lower (): v for k , v in old_packages .items ()}
112
94
new = {k .replace ("-" , "_" ).lower (): v for k , v in new_packages .items ()}
113
95
text = ""
114
- # New packages
96
+
115
97
if new_keys := sorted (set (new ) - set (old )):
116
98
text += "New packages:\r \n \r \n " + "" .join (new [k ].to_wiki () for k in new_keys ) + "\r \n "
117
99
118
- # Upgraded packages
119
100
if upgraded := [new [k ].upgrade_wiki (old [k ]) for k in sorted (set (old ) & set (new )) if old [k ].version != new [k ].version ]:
120
101
text += "Upgraded packages:\r \n \r \n " + f"{ '' .join (upgraded )} " + "\r \n "
121
102
122
- # Removed packages
123
103
if removed_keys := sorted (set (old ) - set (new )):
124
104
text += "Removed packages:\r \n \r \n " + "" .join (old [k ].to_wiki () for k in removed_keys ) + "\r \n "
125
105
return text
126
106
127
-
128
107
def find_closer_version (version1 , basedir = None , flavor = "" , architecture = 64 ):
129
108
"""Find version which is the closest to `version`"""
130
- builddir = str (Path (basedir ) / f"bu{ flavor } " )
131
- func = lambda name : re .match (
132
- r"WinPython%s-%sbit-([0-9\.]*)\.(txt|md)" % (flavor , architecture ),
133
- name ,
134
- )
135
- versions = [func (name ).groups ()[0 ] for name in os .listdir (builddir ) if func (name )]
136
- # versions:['3.10.0.1', '3.10.10.0', '3.10.2.0'.... '3.10.8.1', '3.10.9.0']
137
- try :
138
- index = versions .index (version1 )
139
- except ValueError :
109
+ builddir = Path (basedir ) / f"bu{ flavor } "
110
+ pattern = re .compile (rf"WinPython{ flavor } -{ architecture } bit-([0-9\.]*)\.(txt|md)" )
111
+ versions = [pattern .match (name ).groups ()[0 ] for name in os .listdir (builddir ) if pattern .match (name )]
112
+
113
+ if version1 not in versions :
140
114
raise ValueError (f"Unknown version { version1 } " )
141
115
142
- from packaging import version
143
116
version_below = '0.0.0.0'
144
117
for v in versions :
145
- if version .parse (v ) > version .parse (version_below ) and version .parse (v )< version .parse (version1 ):
118
+ if version .parse (version_below ) < version .parse (v ) and version .parse (v ) < version .parse (version1 ):
146
119
version_below = v
147
- if version_below == '0.0.0.0' :
148
- return version1
149
- else :
150
- return version_below
120
+
121
+ return version_below if version_below != '0.0.0.0' else version1
151
122
152
123
def compare_package_indexes (version2 , version1 = None , basedir = None , flavor = "" , flavor1 = None ,architecture = 64 ):
153
124
"""Compare two package index Wiki pages"""
154
125
version1 = version1 if version1 else find_closer_version (version2 , basedir , flavor , architecture )
155
126
flavor1 = flavor1 if flavor1 else flavor
156
127
pi1 = PackageIndex (version1 , basedir , flavor1 , architecture )
157
128
pi2 = PackageIndex (version2 , basedir , flavor , architecture )
158
-
159
- text = "\r \n " .join (
160
- [
161
- f"## History of changes for WinPython-{ architecture } bit { version2 + flavor } " ,
162
- "" ,
163
- f"The following changes were made to WinPython-{ architecture } bit"
164
- f" distribution since version { version1 + flavor1 } ." ,
165
- "" ,
166
- "<details>" ,
167
- "" ,
168
- ]
129
+
130
+ text = (
131
+ f"## History of changes for WinPython-{ architecture } bit { version2 + flavor } \r \n \r \n "
132
+ f"The following changes were made to WinPython-{ architecture } bit distribution since version { version1 + flavor1 } .\r \n \r \n "
133
+ "<details>\r \n \r \n "
169
134
)
170
135
171
136
tools_text = diff_package_dicts (pi1 .other_packages , pi2 .other_packages )
172
137
if tools_text :
173
138
text += PackageIndex .TOOLS_LINE + "\r \n \r \n " + tools_text
139
+
174
140
py_text = diff_package_dicts (pi1 .python_packages , pi2 .python_packages )
175
141
if py_text :
176
142
text += PackageIndex .PYTHON_PACKAGES_LINE + "\r \n \r \n " + py_text
143
+
177
144
text += "\r \n </details>\r \n * * *\r \n "
178
145
return text
179
146
180
-
181
147
def _copy_all_changelogs (version , basedir , flavor = "" , architecture = 64 ):
182
148
basever = "." .join (version .split ("." )[:2 ])
149
+ pattern = re .compile (rf"WinPython{ flavor } -{ architecture } bit-{ basever } ([0-9\.]*)\.(txt|md)" )
183
150
for name in os .listdir (CHANGELOGS_DIR ):
184
- if re .match (
185
- r"WinPython%s-%sbit-%s([0-9\.]*)\.(txt|md)"
186
- % (flavor , architecture , basever ),
187
- name ,
188
- ):
151
+ if pattern .match (name ):
189
152
shutil .copyfile (CHANGELOGS_DIR / name , Path (basedir ) / f"bu{ flavor } " / name )
190
153
191
-
192
154
def write_changelog (version2 , version1 = None , basedir = None , flavor = "" , architecture = 64 ):
193
155
"""Write changelog between version1 and version2 of WinPython"""
194
156
_copy_all_changelogs (version2 , basedir , flavor , architecture )
195
157
print ("comparing_package_indexes" , version2 , basedir , flavor , architecture )
196
158
changelog_text = compare_package_indexes (version2 , version1 , basedir , flavor , architecture = architecture )
197
159
output_file = Path (basedir ) / f"bu{ flavor } " / f"WinPython{ flavor } -{ architecture } bit-{ version2 } _History.md"
198
160
199
- with open (output_file , "w" , encoding = "utf-8-sig " ) as fdesc :
161
+ with open (output_file , "w" , encoding = "utf-8" ) as fdesc :
200
162
fdesc .write (changelog_text )
201
163
# Copy to winpython/changelogs
202
164
shutil .copyfile (output_file , CHANGELOGS_DIR / output_file .name )
203
165
204
-
205
166
if __name__ == "__main__" :
206
- print (compare_package_indexes ("3.7.4.0" , "3.7.2.0" , "C:\WinP\b d37" , "Zero" , architecture = 32 ))
167
+ print (compare_package_indexes ("3.7.4.0" , "3.7.2.0" , r "C:\WinP\bd37" , "Zero" , architecture = 32 ))
207
168
write_changelog ("3.7.4.0" , "3.7.2.0" , r"C:\WinP\bd37" , "Ps2" , architecture = 64 )
0 commit comments