Skip to content

Commit ab82675

Browse files
committed
Enhance FAQ page layout, add package info parsing utility, and update workflow schedule
1 parent 7180bfe commit ab82675

6 files changed

Lines changed: 167 additions & 136 deletions

File tree

.github/workflows/build_packages_info.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Start with a list of packages in packages.csv, and get external data about them (e.g. last commit date) to generate an HTML page with the package information. This workflow is triggered manually from the Actions tab.
22
# Olly Butters
3-
# 15/5/26
3+
# 9/6/26
44
name: Package list
55

66
# Controls when the workflow will run
77
on:
88
schedule:
9-
- cron: '30 5 * * 0'
9+
- cron: '30 5 * * *'
1010
timezone: "Europe/London"
1111
push:
1212
branches: [ "main" ]
@@ -89,7 +89,7 @@ jobs:
8989
fi
9090
fi
9191

92-
# Use the GitHub API to pull in info about the repoisitory
92+
# Use the GitHub API to pull in info about the repository
9393
echo "\nGitHub API information"
9494
gh repo view --json codeOfConduct,description,homepageUrl,latestRelease,licenseInfo,owner,parent,updatedAt > gh_repo_info.json
9595
echo "API response:"

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/output/*
22
output.csv
3-
/cache/*
3+
/cache/*
4+
*.pyc

build_web_pages/build_packages_long_page.py

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import csv
21
import datetime
32
import shutil
43
import os
54
import re
65
from parse_DESCRIPTION_file import parse_description_file
6+
from utils import parse_package_info
77

88
def main(package_file_path, functions_file_path, html_file_path):
99
"""
@@ -23,28 +23,8 @@ def main(package_file_path, functions_file_path, html_file_path):
2323
if not os.path.exists("output"):
2424
os.makedirs("output")
2525

26-
# Initialize a dictionary to hold package information
27-
package_info = {}
28-
29-
# Parse the package information from the CSV file
30-
with open(package_file_path, 'r', encoding='utf-8') as csv_file:
31-
reader = csv.reader(csv_file)
32-
next(reader)
33-
34-
for row in reader:
35-
package_name = row[0]
36-
package_info[package_name] = {
37-
"short_description": row[1],
38-
"cran_link": row[2],
39-
"cran_version": row[3],
40-
"cran_license": row[4],
41-
"github_link": row[5],
42-
"github_last_update": row[6],
43-
"github_version": row[7],
44-
"github_license": row[9],
45-
"github_owner": row[10],
46-
"status": row[11]
47-
}
26+
# Dictionary to hold package information
27+
package_info = parse_package_info(package_file_path)
4828

4929
# Parse the functions.txt file
5030
with open(functions_file_path, 'r', encoding='utf-8') as file:
@@ -57,6 +37,10 @@ def main(package_file_path, functions_file_path, html_file_path):
5737
functions = match.group(2).split(',')
5838
package_info[package_name]["functions"] = functions
5939

40+
with open(functions_file_path, 'r', encoding='utf-8') as functions_file:
41+
full_function_file_text = functions_file.read()
42+
number_of_functions = full_function_file_text.count(",")
43+
6044
# Parse the DESCRIPTION files
6145
for package_name in package_info.keys():
6246
try:
@@ -88,10 +72,13 @@ def main(package_file_path, functions_file_path, html_file_path):
8872

8973
top_content = '<div class="top-content">'
9074
top_content += '<h1>DataSHIELD packages</h1>'
91-
top_content += '<p>This page lists all the packages that are used in the DataSHIELD ecosystem. It includes packages that are in production, in development, retired, and unknown status.</p>'
75+
top_content += '<p>This page lists all the packages that have been developed in the <a href="https://www.datashield.org">DataSHIELD</a> ecosystem. It includes packages that are in production, in development, retired, and unknown status. More info is in the <a href="./faq.html">FAQ</a>.</p>'
9276

9377
html_file.write(top_content)
9478

79+
stats = f'<p>There are {len(package_info)} packages and {number_of_functions} functions listed on these pages.</p>'
80+
html_file.write(stats)
81+
9582
for this_package_name, this_package_info in package_info.items():
9683
try:
9784
html_content = f"""
@@ -102,7 +89,7 @@ def main(package_file_path, functions_file_path, html_file_path):
10289
<tr><td class="label">Short description</td><td class="left">{this_package_info.get('short_description', 'No short description available.')}</td></tr>
10390
<tr><td class="label">Long description</td><td class="left">{this_package_info.get('DESCRIPTION', {}).get('Description', 'No long description available.')}</td></tr>
10491
"""
105-
92+
10693
if this_package_info.get('cran_link'):
10794
html_content += f"""
10895
<tr><td class="label">CRAN link</td><td class="left"><a href="{this_package_info.get('cran_link')}" target="_blank">{this_package_info.get('cran_link')}</a></td></tr>
@@ -123,8 +110,14 @@ def main(package_file_path, functions_file_path, html_file_path):
123110
else:
124111
html_content += '<tr><td class="label">CRAN link</td><td class="left">N/A</td></tr>'
125112

113+
if this_package_info.get('github_version_url') == 'null':
114+
html_content += '<tr><td class="label">GitHub version</td><td class="left"></td></tr>'
115+
else:
116+
html_content += f"""
117+
<tr><td class="label">GitHub version</td><td class="left"><a href="{this_package_info.get('github_version_url')}" target="_blank">{this_package_info.get('github_version')}</a></td></tr>
118+
"""
119+
126120
html_content += f"""
127-
<tr><td class="label">GitHub version</td><td class="left">{this_package_info.get('github_version', 'No GitHub version available.')}</td></tr>
128121
<tr><td class="label">GitHub license</td><td class="left">{this_package_info.get('github_license', 'No GitHub license available.')}</td></tr>
129122
<tr><td class="label">GitHub owner</td><td class="left">{this_package_info.get('github_owner', 'No GitHub owner available.')}</td></tr>
130123
<tr><td class="label">Status</td><td class="left">{this_package_info.get('status', 'Unknown')}</td></tr>
@@ -138,6 +131,7 @@ def main(package_file_path, functions_file_path, html_file_path):
138131
continue
139132

140133
# Footer
134+
html_file.write('<hr/>')
141135
html_file.write('Generated on ' + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
142136
html_file.write('&nbsp;&nbsp;Made by the <a href="https://github.com/FederatedMethods">Federated Methods team</a>')
143137

@@ -146,3 +140,4 @@ def main(package_file_path, functions_file_path, html_file_path):
146140
if __name__ == '__main__':
147141
main('cache/output.csv', 'cache/functions.txt', './output/packages.html')
148142
shutil.copy('./build_web_pages/template/style_main.css', './output/style_main.css')
143+
shutil.copy('./build_web_pages/template/faq.html', './output/faq.html')

build_web_pages/build_packages_summary_page.py

Lines changed: 107 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import csv
21
import datetime
32
import shutil
43
import os
4+
from utils import parse_package_info
55

66
def main(csv_file_path, html_file_path, functions_file_path):
77
print(f"Current working directory: {os.getcwd()}")
@@ -32,109 +32,115 @@ def main(csv_file_path, html_file_path, functions_file_path):
3232

3333
top_content = '<div class="top-content">'
3434
top_content += '<h1>DataSHIELD packages</h1>'
35-
top_content += '<p>This page lists all the packages that have been developed in the DataSHIELD ecosystem. It includes packages that are in production, in development, retired, and unknown status.</p>'
35+
top_content += '<p>This page lists all the packages that have been developed in the <a href="https://www.datashield.org">DataSHIELD</a> ecosystem. It includes packages that are in production, in development, retired, and unknown status.</p>'
3636

3737
html_file.write(top_content)
3838

39-
with open(csv_file_path, 'r', encoding='utf-8') as csv_file:
40-
package_list = csv.reader(csv_file)
41-
42-
# Count the number of lines in the CSV file then go back to the beginning
43-
row_count = sum(1 for row in package_list) # fileObject is your csv.reader
44-
csv_file.seek(0)
45-
46-
stats = f'<p>There are {row_count - 1} packages and {number_of_functions} functions listed on these pages.</p>'
47-
html_file.write(stats)
48-
49-
# Skip header
50-
next(package_list)
51-
52-
html_file.write('<table border="1">\n')
53-
54-
html_file.write('<tr><td></td>')
55-
html_file.write('<th>Name</th>')
56-
html_file.write('<th>Description</th>')
57-
html_file.write('<th>CRAN version</th>')
58-
html_file.write('<th>CRAN license</th>')
59-
html_file.write('<th>GitHub last update</th>')
60-
html_file.write('<th>GitHub version</th>')
61-
html_file.write('<th>GitHub license</th>')
62-
html_file.write('<th>GitHub owner</th>')
63-
html_file.write('</tr>')
64-
65-
production_rows = ""
66-
development_rows = ""
67-
retired_rows = ""
68-
unknown_rows = ""
69-
70-
# Counts for each rows
71-
production_rows_count = 1
72-
development_rows_count = 1
73-
retired_rows_count = 1
74-
unknown_rows_count = 1
75-
76-
for row in package_list:
77-
print(row)
78-
this_row = ""
79-
80-
# Add GitHub link if available, otherwise just the name
81-
this_row += '<td class="left"><a href="packages.html#' + row[0] + '">' + row[0] + '</a></td>'
82-
83-
# Description
84-
if len(row[1]) > 0:
85-
this_row += '<td class="left">' + row[1] + '</td>'
86-
else:
87-
this_row += '<td></td>'
88-
89-
# CRAN version with link
90-
if len(row[2]) > 0:
91-
this_row += '<td><a href="' + row[2] + '" target="blank">' + row[3] + '</a></td>'
92-
else:
93-
this_row += '<td></td>'
94-
95-
this_row += '<td>' + row[4] + '</td>' # CRAN license
96-
this_row += '<td>' + row[6] + '</td>' # GH last update
97-
this_row += '<td>' + row[7] + '</td>' # GH version
98-
this_row += '<td>' + row[9] + '</td>' # GH license
99-
this_row += '<td class="left">' + row[10] + '</td>' # GH owner
100-
101-
# Group rows by status and add put a row number in
102-
if row[11].strip() == 'production':
103-
production_rows += '<tr>'
104-
production_rows += '<td>' + str(production_rows_count) + '</td>' # Row number
105-
production_rows += this_row
106-
production_rows += '</tr>'
107-
production_rows_count += 1
108-
elif row[11].strip() == 'development':
109-
development_rows += '<tr>'
110-
development_rows += '<td>' + str(development_rows_count) + '</td>'
111-
development_rows += this_row
112-
development_rows += '</tr>'
113-
development_rows_count += 1
114-
elif row[11].strip() == 'retired':
115-
retired_rows += '<tr>'
116-
retired_rows += '<td>' + str(retired_rows_count) + '</td>'
117-
retired_rows += this_row
118-
retired_rows += '</tr>'
119-
retired_rows_count += 1
120-
else:
121-
unknown_rows += '<tr>'
122-
unknown_rows += '<td>' + str(unknown_rows_count) + '</td>'
123-
unknown_rows += this_row
124-
unknown_rows += '</tr>'
125-
unknown_rows_count += 1
126-
127-
# Build the table with the rows grouped by status
128-
html_file.write('<tr><td colspan="9">Production</td></tr>')
129-
html_file.write(production_rows)
130-
html_file.write('<tr><td colspan="9">Development</td></tr>')
131-
html_file.write(development_rows)
132-
html_file.write('<tr><td colspan="9">Retired</td></tr>')
133-
html_file.write(retired_rows)
134-
html_file.write('<tr><td colspan="9">Unknown</td></tr>')
135-
html_file.write(unknown_rows)
136-
html_file.write('</table>')
137-
39+
package_info = parse_package_info(csv_file_path)
40+
41+
stats = f'<p>There are {len(package_info)} packages and {number_of_functions} functions listed on these pages.</p>'
42+
html_file.write(stats)
43+
44+
html_file.write('<table border="1">\n')
45+
46+
html_file.write('<tr><td></td>')
47+
html_file.write('<th>Name</th>')
48+
html_file.write('<th>Description</th>')
49+
html_file.write('<th>CRAN version</th>')
50+
html_file.write('<th>CRAN license</th>')
51+
html_file.write('<th>GitHub last update</th>')
52+
html_file.write('<th>GitHub version</th>')
53+
html_file.write('<th>GitHub license</th>')
54+
html_file.write('<th>GitHub owner</th>')
55+
html_file.write('</tr>')
56+
57+
production_rows = ""
58+
development_rows = ""
59+
retired_rows = ""
60+
unknown_rows = ""
61+
62+
# Counts for each rows
63+
production_rows_count = 1
64+
development_rows_count = 1
65+
retired_rows_count = 1
66+
unknown_rows_count = 1
67+
68+
#for row in package_list:
69+
for this_package_name, this_package_info in package_info.items():
70+
print(this_package_name)
71+
print(this_package_info)
72+
this_row = ""
73+
74+
# Add GitHub link if available, otherwise just the name
75+
this_row += '<td class="left"><a href="packages.html#' + this_package_name + '">' + this_package_name + '</a></td>'
76+
77+
# Description
78+
if len(this_package_info['short_description']) > 0:
79+
this_row += '<td class="left">' + this_package_info['short_description'] + '</td>'
80+
else:
81+
this_row += '<td></td>'
82+
83+
# CRAN version with link
84+
if len(this_package_info.get('cran_link')) > 0:
85+
this_row += '<td><a href="' + this_package_info['cran_link'] + '" target="blank">' + this_package_info['cran_version'] + '</a></td>'
86+
else:
87+
this_row += '<td></td>'
88+
89+
this_row += '<td>' + this_package_info.get('cran_license', "") + '</td>' # CRAN license
90+
this_row += '<td>' + this_package_info.get('github_last_update', "") + '</td>' # GH last update
91+
92+
# GH version with link
93+
if this_package_info.get('github_version_url') == "null":
94+
this_row += '<td></td>'
95+
else:
96+
this_row += '<td><a href="' + this_package_info['github_version_url'] + '" target="_blank">' + this_package_info['github_version'] + '</a></td>'
97+
98+
# GH license
99+
if this_package_info.get('github_license') == "null":
100+
this_row += '<td></td>'
101+
else:
102+
this_row += '<td>' + this_package_info.get('github_license', "") + '</td>'
103+
104+
this_row += '<td class="left"><a href="https://github.com/' + this_package_info['github_owner'] + '" target="_blank">' + this_package_info['github_owner'] + '</a></td>' # GH owner
105+
106+
# Group rows by status and add put a row number in
107+
if this_package_info['status'].strip() == 'production':
108+
production_rows += '<tr>'
109+
production_rows += '<td>' + str(production_rows_count) + '</td>' # Row number
110+
production_rows += this_row
111+
production_rows += '</tr>'
112+
production_rows_count += 1
113+
elif this_package_info['status'].strip() == 'development':
114+
development_rows += '<tr>'
115+
development_rows += '<td>' + str(development_rows_count) + '</td>'
116+
development_rows += this_row
117+
development_rows += '</tr>'
118+
development_rows_count += 1
119+
elif this_package_info['status'].strip() == 'retired':
120+
retired_rows += '<tr>'
121+
retired_rows += '<td>' + str(retired_rows_count) + '</td>'
122+
retired_rows += this_row
123+
retired_rows += '</tr>'
124+
retired_rows_count += 1
125+
else:
126+
unknown_rows += '<tr>'
127+
unknown_rows += '<td>' + str(unknown_rows_count) + '</td>'
128+
unknown_rows += this_row
129+
unknown_rows += '</tr>'
130+
unknown_rows_count += 1
131+
132+
# Build the table with the rows grouped by status
133+
html_file.write('<tr><td colspan="9">Production</td></tr>')
134+
html_file.write(production_rows)
135+
html_file.write('<tr><td colspan="9">Development</td></tr>')
136+
html_file.write(development_rows)
137+
html_file.write('<tr><td colspan="9">Retired</td></tr>')
138+
html_file.write(retired_rows)
139+
html_file.write('<tr><td colspan="9">Unknown</td></tr>')
140+
html_file.write(unknown_rows)
141+
html_file.write('</table>')
142+
143+
html_file.write('<hr/>')
138144
html_file.write('Generated on ' + datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
139145
html_file.write('&nbsp;&nbsp;Made by the <a href="https://github.com/FederatedMethods">Federated Methods team</a>')
140146

build_web_pages/template/faq.html

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
</head>
55
<body>
66
<h1>Frequently Asked Questions</h1>
7-
<p>
8-
What is a DataSHIELD package?
9-
</p>
107

11-
<p>
12-
How can I add my package to this list?
8+
9+
<h2>What is a DataSHIELD package?</h2>
10+
<p></p>
11+
12+
13+
<h2>How can I add my package to this list or update some information?</h2>
14+
<p>You could submit an issue or a pull request to update the csv file at <a href="https://github.com/FederatedMethods/packages/blob/main/package_list.csv">https://github.com/FederatedMethods/packages/blob/main/package_list.csv</a>. Most of this information is gathered from the package info on GitHub or the CRAN, so you may need to update the information there, then it will appear here tomorrow.
1315
</p>
1416

1517
<h2>Why are retired packages listed?</h2>

0 commit comments

Comments
 (0)