66import logging
77import shutil
88import textwrap
9+ from dataclasses import dataclass
910from pathlib import Path
1011
1112import plumbum
1213import tabulate
1314from dateutil import relativedelta
1415
16+ from wiki .config import Config
17+ from wiki .manifest_time import get_manifest_timestamp , get_manifest_year_month
18+
1519git = plumbum .local ["git" ]
1620
1721LOGGER = logging .getLogger (__name__ )
1822THIS_DIR = Path (__file__ ).parent .resolve ()
1923
2024
21- def calculate_monthly_stat (
22- year_month_file : Path , year_month_date : datetime .date
23- ) -> tuple [int , int , int ]:
24- year_month_file_content = year_month_file .read_text ()
25+ @dataclass
26+ class YearMonthFile :
27+ month : int
28+ content : str
29+
2530
31+ @dataclass
32+ class Statistics :
33+ builds : int
34+ images : int
35+ commits : int
36+
37+
38+ def calculate_monthly_stat (
39+ year_month_file : YearMonthFile , year_month_date : datetime .date
40+ ) -> Statistics :
2641 builds = sum (
2742 "jupyter/base-notebook" in line and "aarch64" not in line
28- for line in year_month_file_content .split ("\n " )
43+ for line in year_month_file . content .split ("\n " )
2944 )
3045
31- images = year_month_file_content .count ("Build manifest" )
46+ images = year_month_file . content .count ("Build manifest" )
3247
3348 with plumbum .local .env (TZ = "UTC" ):
3449 future = (
@@ -46,69 +61,102 @@ def calculate_monthly_stat(
4661 future .wait ()
4762 commits = len (future .stdout .splitlines ())
4863
49- return builds , images , commits
64+ return Statistics ( builds = builds , images = images , commits = commits )
5065
5166
52- def generate_home_wiki_page (wiki_dir : Path , repository : str ) -> None :
53- YEAR_MONTHLY_TABLES = "<!-- YEAR_MONTHLY_TABLES -->"
67+ @dataclass
68+ class YearFiles :
69+ year : int
70+ files : list [YearMonthFile ]
5471
55- wiki_home_content = (THIS_DIR / "Home.md" ).read_text ()
5672
57- assert YEAR_MONTHLY_TABLES in wiki_home_content
58- wiki_home_content = wiki_home_content [
59- : wiki_home_content .find (YEAR_MONTHLY_TABLES ) + len (YEAR_MONTHLY_TABLES )
60- ]
61- wiki_home_content = wiki_home_content .format (REPOSITORY = repository )
73+ def generate_home_wiki_tables (repository : str , all_years : list [YearFiles ]) -> str :
74+ tables = ""
6275
6376 GITHUB_COMMITS_URL = (
6477 f"[{{}}](https://github.com/{ repository } /commits/main/?since={{}}&until={{}})"
6578 )
6679
6780 YEAR_TABLE_HEADERS = ["Month" , "Builds" , "Images" , "Commits" ]
6881
69- for year_dir in sorted ((wiki_dir / "monthly-files" ).glob ("*" ), reverse = True ):
70- year = int (year_dir .name )
71- wiki_home_content += f"\n \n ## { year } \n \n "
82+ for year_files in all_years :
83+ year = year_files .year
84+
85+ tables += f"\n \n ## { year } \n \n "
7286 year_table_rows = []
7387
74- year_builds , year_images , year_commits = 0 , 0 , 0
75- for year_month_file in sorted ( year_dir . glob ( "*.md" ), reverse = True ) :
76- year_month = year_month_file .stem
77- year_month_date = datetime .date (year = year , month = int ( year_month [ 5 :]) , day = 1 )
78- builds , images , commits = calculate_monthly_stat (
79- year_month_file , year_month_date
80- )
81- year_builds += builds
82- year_images += images
83- year_commits += commits
88+ year_stat = Statistics ( builds = 0 , images = 0 , commits = 0 )
89+ for year_month_file in year_files . files :
90+ month = year_month_file .month
91+ year_month_date = datetime .date (year = year , month = month , day = 1 )
92+ month_stat = calculate_monthly_stat (year_month_file , year_month_date )
93+
94+ year_stat . builds += month_stat . builds
95+ year_stat . images += month_stat . images
96+ year_stat . commits += month_stat . commits
97+
8498 commits_url = GITHUB_COMMITS_URL .format (
85- commits ,
99+ month_stat . commits ,
86100 year_month_date ,
87101 year_month_date + relativedelta .relativedelta (day = 31 ),
88102 )
103+ year_month = f"{ year } -{ month :0>2} "
89104 year_table_rows .append (
90- [f"[`{ year_month } `](./{ year_month } )" , builds , images , commits_url ]
105+ [
106+ f"[`{ year_month } `](./{ year_month } )" ,
107+ month_stat .builds ,
108+ month_stat .images ,
109+ commits_url ,
110+ ]
91111 )
92112
93113 year_commits_url = GITHUB_COMMITS_URL .format (
94- year_commits , f"{ year } -01-01" , f"{ year } -12-31"
114+ year_stat . commits , f"{ year } -01-01" , f"{ year } -12-31"
95115 )
96116 year_table_rows .append (
97- ["**Total**" , year_builds , year_images , year_commits_url ]
117+ ["**Total**" , year_stat . builds , year_stat . images , year_commits_url ]
98118 )
99119
100- wiki_home_content += tabulate .tabulate (
120+ tables += tabulate .tabulate (
101121 year_table_rows , YEAR_TABLE_HEADERS , tablefmt = "github"
102122 )
103- wiki_home_content += "\n "
123+ LOGGER .info ("Generated home wiki tables" )
124+ return tables
125+
126+
127+ def write_home_wiki_page (wiki_dir : Path , repository : str ) -> None :
128+ all_years = []
129+ for year_dir in sorted ((wiki_dir / "monthly-files" ).glob ("*" ), reverse = True ):
130+ files = sorted (year_dir .glob ("*.md" ), reverse = True )
131+ all_years .append (
132+ YearFiles (
133+ int (year_dir .name ),
134+ [
135+ YearMonthFile (month = int (f .stem [5 :]), content = f .read_text ())
136+ for f in files
137+ ],
138+ )
139+ )
140+ wiki_home_tables = generate_home_wiki_tables (repository , all_years )
141+
142+ wiki_home_content = (THIS_DIR / "Home.md" ).read_text ()
143+ YEAR_MONTHLY_TABLES = "<!-- YEAR_MONTHLY_TABLES -->"
144+
145+ assert YEAR_MONTHLY_TABLES in wiki_home_content
146+ wiki_home_content = wiki_home_content [
147+ : wiki_home_content .find (YEAR_MONTHLY_TABLES ) + len (YEAR_MONTHLY_TABLES )
148+ ]
149+ wiki_home_content = wiki_home_content .format (REPOSITORY = repository )
150+ wiki_home_content += wiki_home_tables + "\n "
104151
105152 (wiki_dir / "Home.md" ).write_text (wiki_home_content )
106153 LOGGER .info ("Updated Home page" )
107154
108155
109- def update_monthly_wiki_page (
110- wiki_dir : Path , year_month : str , build_history_line : str
111- ) -> None :
156+ def update_monthly_wiki_page (wiki_dir : Path , build_history_line : str ) -> None :
157+ assert build_history_line .startswith ("| `" )
158+ year_month = build_history_line [3 :10 ]
159+
112160 MONTHLY_PAGE_HEADER = textwrap .dedent (
113161 f"""\
114162 # Images built during { year_month }
@@ -133,23 +181,6 @@ def update_monthly_wiki_page(
133181 LOGGER .info (f"Updated monthly page: { monthly_page .relative_to (wiki_dir )} " )
134182
135183
136- def get_manifest_timestamp (manifest_file : Path ) -> str :
137- file_content = manifest_file .read_text ()
138- TIMESTAMP_PREFIX = "Build timestamp: "
139- TIMESTAMP_LENGTH = 20
140- timestamp = file_content [
141- file_content .find (TIMESTAMP_PREFIX ) + len (TIMESTAMP_PREFIX ) :
142- ][:TIMESTAMP_LENGTH ]
143- # Should be good enough till year 2100
144- assert timestamp .startswith ("20" ), timestamp
145- assert timestamp .endswith ("Z" ), timestamp
146- return timestamp
147-
148-
149- def get_manifest_year_month (manifest_file : Path ) -> str :
150- return get_manifest_timestamp (manifest_file )[:7 ]
151-
152-
153184def remove_old_manifests (wiki_dir : Path ) -> None :
154185 MAX_NUMBER_OF_MANIFESTS = 4500
155186
@@ -163,40 +194,37 @@ def remove_old_manifests(wiki_dir: Path) -> None:
163194 LOGGER .info (f"Removed manifest: { file .relative_to (wiki_dir )} " )
164195
165196
166- def update_wiki (
167- * ,
168- wiki_dir : Path ,
169- hist_lines_dir : Path ,
170- manifests_dir : Path ,
171- repository : str ,
172- allow_no_files : bool ,
173- ) -> None :
174- LOGGER .info ("Updating wiki" )
175-
176- manifest_files = list (manifests_dir .rglob ("*.md" ))
177- if not allow_no_files :
197+ def copy_manifest_files (config : Config ) -> None :
198+ manifest_files = list (config .manifests_dir .rglob ("*.md" ))
199+ if not config .allow_no_files :
178200 assert manifest_files , "expected to have some manifest files"
179201 for manifest_file in manifest_files :
180202 year_month = get_manifest_year_month (manifest_file )
181203 year = year_month [:4 ]
182- copy_to = wiki_dir / "manifests" / year / year_month / manifest_file .name
204+ copy_to = config . wiki_dir / "manifests" / year / year_month / manifest_file .name
183205 copy_to .parent .mkdir (parents = True , exist_ok = True )
184206 shutil .copy (manifest_file , copy_to )
185- LOGGER .info (f"Added manifest file: { copy_to .relative_to (wiki_dir )} " )
207+ LOGGER .info (f"Added manifest file: { copy_to .relative_to (config . wiki_dir )} " )
186208
187- build_history_line_files = sorted (hist_lines_dir .rglob ("*.txt" ))
188- if not allow_no_files :
209+
210+ def update_wiki (config : Config ) -> None :
211+ LOGGER .info ("Updating wiki" )
212+
213+ copy_manifest_files (config )
214+
215+ build_history_line_files = sorted (config .hist_lines_dir .rglob ("*.txt" ))
216+ if not config .allow_no_files :
189217 assert (
190218 build_history_line_files
191219 ), "expected to have some build history line files"
192220 for build_history_line_file in build_history_line_files :
193221 build_history_line = build_history_line_file .read_text ()
194- assert build_history_line .startswith ("| `" )
195- year_month = build_history_line [3 :10 ]
196- update_monthly_wiki_page (wiki_dir , year_month , build_history_line )
222+ update_monthly_wiki_page (config .wiki_dir , build_history_line )
223+
224+ write_home_wiki_page (config .wiki_dir , config .repository )
225+ remove_old_manifests (config .wiki_dir )
197226
198- generate_home_wiki_page (wiki_dir , repository )
199- remove_old_manifests (wiki_dir )
227+ LOGGER .info ("Wiki updated" )
200228
201229
202230if __name__ == "__main__" :
@@ -233,4 +261,5 @@ def update_wiki(
233261 )
234262 args = arg_parser .parse_args ()
235263
236- update_wiki (** vars (args ))
264+ config = Config (** vars (args ))
265+ update_wiki (config )
0 commit comments