Skip to content
Open
Show file tree
Hide file tree
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
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ jobs:
run: |
uv pip install pyinstaller

- name: Generate the embedded credits file for all packages
if: ${{ matrix.installer }}
run: |
uv pip install pip-licenses
python build_tools/compile_licenses.py installers/credits.html

- name: Build sasview with pyinstaller
if: ${{ matrix.installer }}
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,4 @@ tests.log
/installers/build
/installers/dist
*.exe
installers/credits.html
128 changes: 128 additions & 0 deletions build_tools/compile_licenses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#!/usr/bin/python3

import argparse
import json
import subprocess
import sys
from pathlib import Path

from mako.template import Template

# Define Mako template for HTML output
html_template = Template(
r"""
<html>
<head>
<meta charset="UTF-8">
<title>SasView Dependencies</title>
<style>
body { font-family: Arial, sans-serif; margin: 1em; }
h1 { font-size: 1.3em; }
h2 { margin-top: 2em; font-size: 1.2em; }
pre { background-color: #f4f4f4; padding: 0.8em; white-space: pre-wrap; }
ul { line-height: 1.6; }
a { text-decoration: none; color: #0645ad; }
</style>
</head>
<body>
<h1>SasView Dependencies</h1>
SasView is built upon a foundation of free and open-source software packages.
% if minimal:
The following modules are part of this release of SasView.
% else:
The following modules are used as part of the build process and are bundled
in the binary distributions that are released.
% endif
<ul>
% for pkg in modules:
<li><a href="#${pkg['Name']}">${pkg['Name']}</a></li>
% endfor
</ul>

% for pkg in modules:
<h2 id="${pkg['Name']}">${pkg['Name']}</h2>
<p><strong>Author(s):</strong> ${pkg.get('Author', 'N/A')}</p>
<p><strong>License:</strong> ${pkg.get('License', 'N/A')}</p>
<pre>${pkg.get('LicenseText', 'No license text available.')}</pre>
% endfor
</body>
</html>
"""
)


# minimal list of modules to include when distributing only in wheel form
minimal_modules = [
"sasdata",
"sasmodels",
"sasview",
]


def get_modules():
"""Load pip-licenses JSON output"""
result = subprocess.run(
[
"pip-licenses",
"--format=json",
"--with-system",
"--with-authors",
"--with-license-file",
],
capture_output=True,
text=True,
check=True,
)
modules = json.loads(result.stdout)
# Sort the data by package name (case-insensitive)
modules.sort(key=lambda pkg: pkg["Name"].lower())
return modules


def filter_modules(modules, included):
"""Filter the list of packages to only include the specified packages"""
return [m for m in modules if m["Name"].lower() in included]


def format_html(filename, modules, minimal):
"""Create the HTML output"""
# Render the template with license data
html_output = html_template.render(modules=modules, minimal=minimal)

# Save the HTML to a file
Path(filename).write_text(html_output, encoding="utf-8")


def main(argv):
parser = argparse.ArgumentParser(
description="Extract license information for modules in the environment",
)

parser.add_argument(
"--minimal",
action="store_true",
help="Only include information about a minimal set of modules",
)
parser.add_argument(
"filename",
help="output filename",
metavar="OUTPUT",
)

args = parser.parse_args(argv)

minimal = args.minimal
filename = args.filename

modules = get_modules()

if minimal:
modules = filter_modules(modules, minimal_modules)

format_html(filename, modules, minimal)

return True


if __name__ == "__main__":
sys.exit(not main(sys.argv[1:]))
17 changes: 15 additions & 2 deletions build_tools/release_automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import json
import logging
import os
import subprocess
import sys
from csv import DictReader
from pathlib import Path

import requests

from sas.system.legal import legal
from sas.system import legal

USAGE = '''This script should be run from one directory above the base sasview directory. This script also requires both
sasmodels and sasdata repositories to be in the same directory as the sasview repository.
Expand Down Expand Up @@ -293,6 +294,17 @@ def update_file(license_file: Path, license_line: str, line_to_update: int):
f.writelines(output_lines)


def update_credits(credits_file: Path):
"""Update the credits.html file with relevant license info"""
subprocess.check_call(
[
sys.executable,
"--minimal",
"build_tools/release_automation.py",
credits_file,
])


def update_acknowledgement_widget():
"""

Expand All @@ -308,7 +320,7 @@ def prepare_release_notes(issues_list, repository, username, password):
"""
issue_titles = []
for issue in issues_list:
# WARNING: One can try running with auth but there is limitted number of requests
# WARNING: One can try running with auth but there is limited number of requests
response = requests.get('https://api.github.com/repos/SasView/' + repository + '/issues/' + issue,
auth=(username, password))
if response.status_code != 200:
Expand Down Expand Up @@ -365,6 +377,7 @@ def main(args=None):
update_file(SASMODELS_PATH / 'LICENSE.txt', license_line, 0)
update_file(SASDATA_PATH / 'LICENSE.TXT', license_line, 0)
update_file(SASVIEW_PATH / 'installers' / 'license.txt', license_line, -1)
update_credits(SASVIEW_PATH / "src" / "sas" / "system" / "credits.html")

sasview_issues_list = args.sasview_list
sasmodels_issues_list = args.sasmodels_list
Expand Down
13 changes: 11 additions & 2 deletions build_tools/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
build
# The list of dependencies needed to build sasview, this should be kept in
# sync with pyproject.toml's build-system.requires list.
# Additional tools for developers can be listed in this file.
# Developers may also want the test dependencies in requirements-test.txt

bumps
dominate
hatchling
Expand All @@ -8,7 +12,6 @@ hatch-sphinx
hatch-vcs
html2text
numpy
pre-commit
periodictable
pyopengl
pyside6
Expand All @@ -17,3 +20,9 @@ scipy
superqt
twisted
uncertainties

# not build-dependencies but important for developers
build # build is special: it doesn't get listed in build-system.requires but is needed
pip-licenses
pre-commit
-r requirements-test.txt
3 changes: 3 additions & 0 deletions installers/sasview.spec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ datas.append((os.path.join(PYTHON_PACKAGES, 'jedi'), 'jedi'))
datas.append((os.path.join(PYTHON_PACKAGES, 'zmq'), 'zmq'))
datas.append(('../src/sas/example_data', './example_data'))

# clobber the minimal file with the full one for the installer bundle
datas.append(('credits.html', 'sas/system/'))

def add_data(data):
for component in data:
target = component[0]
Expand Down
10 changes: 10 additions & 0 deletions src/sas/qtgui/MainWindow/GuiManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from sas.qtgui.Perspectives.perspective import Perspective
from sas.qtgui.Perspectives.SizeDistribution.SizeDistributionPerspective import SizeDistributionWindow
from sas.qtgui.Utilities.About.About import About
from sas.qtgui.Utilities.About.Credits import Credits

# from sas.qtgui.Utilities.DocViewWidget import DocViewWindow
from sas.qtgui.Utilities.FileConverter import FileConverterWidget
Expand Down Expand Up @@ -775,6 +776,7 @@ def addTriggers(self):
self._workspace.actionModel_Marketplace.triggered.connect(self.actionMarketplace)
self._workspace.actionAcknowledge.triggered.connect(self.actionAcknowledge)
self._workspace.actionAbout.triggered.connect(self.actionAbout)
self._workspace.actionCredits.triggered.connect(self.actionCredits)
self._workspace.actionWelcomeWidget.triggered.connect(self.actionWelcome)
self._workspace.actionCheck_for_update.triggered.connect(self.actionCheck_for_update)
self._workspace.actionWhat_s_New.triggered.connect(self.actionWhatsNew)
Expand Down Expand Up @@ -1318,6 +1320,14 @@ def actionAbout(self):
about = About()
about.exec()

def actionCredits(self):
"""
Open the Credits/Licenses box
"""
# TODO: proper sizing
credits = Credits()
credits.exec()

def actionCheck_for_update(self):
"""
Menu Help/Check for Update
Expand Down
Loading