-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix cairo for Windows #77
Open
Li-Xiang-Ideal
wants to merge
12
commits into
Mathics3:master
Choose a base branch
from
Li-Xiang-Ideal:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 10 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
40bedc6
Update format.py
Li-Xiang-Ideal ae671e1
Update format.py
Li-Xiang-Ideal ab2f448
Update format.py
Li-Xiang-Ideal 01f9b25
Create fixcairo.py
Li-Xiang-Ideal bb0fa86
Update format.py
Li-Xiang-Ideal 364c654
Update setup.py
Li-Xiang-Ideal f75c8e6
Update fixcairo.py
Li-Xiang-Ideal c424acd
Update __init__.py
Li-Xiang-Ideal 45f3f9c
Update fixcairo.py
Li-Xiang-Ideal f58f1b8
Update fixcairo.py
Li-Xiang-Ideal a6621f3
Update setup.py
Li-Xiang-Ideal dc1d44b
Update fixcairo.py
Li-Xiang-Ideal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Fix cairo for Windows | ||
""" | ||
|
||
import os | ||
import platform | ||
import subprocess | ||
from ctypes.util import find_library | ||
from importlib.util import find_spec | ||
|
||
import requests | ||
from tqdm import tqdm | ||
|
||
mathicsscript_path = find_spec("mathicsscript").submodule_search_locations[0] | ||
|
||
if platform.architecture()[0] == "64bit": | ||
release_url = "https://api.github.com/repos/tschoonj/GTK-for-Windows-Runtime-Environment-Installer/releases/latest" | ||
else: | ||
release_url = "https://api.github.com/repos/miegir/GTK-for-Windows-Runtime-Environment-Installer-32/releases/latest" | ||
|
||
fix_cairo_long_intro = f""" | ||
We noticed that you are using mathicsscript on Windows. Due to a well known bug in the dependency | ||
package cairocffi for mathicsscript on Windows, mathicsscript is not working properly right now. | ||
We will now try to fix it, or you can visit https://github.com/Mathics3/mathicsscript/issues/76 | ||
to fix it yourself. | ||
|
||
Specifically, cairocffi needs libcairo-2.dll and some other dll files to work properly on Windows. | ||
To get these libraries, we will download the latest GTK+ for Windows Runtime Environment Installer | ||
from {release_url} | ||
and install it for you. After installation, whenever you run mathicsscript, the GTK+ for Windows | ||
dll libraries will be automatically loaded to make mathicsscript run properly. | ||
|
||
IMPORTANT: Remember to check the "Set up PATH environment variable to include GTK+" option! | ||
|
||
Please note that now the GTK+ for Windows dll libraries will only be loaded when mathicsscript is | ||
imported. If you want to load them when importing cairocffi, see | ||
https://github.com/Mathics3/mathicsscript/issues/76. | ||
|
||
Do you want us to install GTK+ for Windows Runtime Environment for you? [Y/n] (default: Y) | ||
""" | ||
|
||
|
||
def download_file(url, dest, name=None): | ||
response = requests.get(url, stream=True, timeout=5) | ||
total_size = int(response.headers.get("content-length", 0)) | ||
if response.status_code == 200: | ||
with open(dest, "wb") as file: | ||
with tqdm( | ||
total=total_size, | ||
unit="B", | ||
unit_scale=True, | ||
unit_divisor=1024, | ||
desc=f"Downloading {name}", | ||
) as pbar: | ||
for chunk in response.iter_content(chunk_size=1024): | ||
if chunk: | ||
file.write(chunk) | ||
file.flush() | ||
pbar.update(len(chunk)) | ||
pbar.refresh() | ||
else: | ||
print(f"Failed to download: {url}") | ||
|
||
|
||
def download_GTK_installer(): | ||
response = requests.get(release_url, timeout=5) | ||
if response.status_code == 200: | ||
name = response.json()["assets"][0]["name"] | ||
file_url = response.json()["assets"][0]["browser_download_url"] | ||
file_path = os.path.join(mathicsscript_path, name) | ||
download_file(file_url, file_path, name) | ||
print("Done.") | ||
return file_path | ||
else: | ||
print("Failed to retrieve directory contents.") | ||
|
||
|
||
def set_dll_search_path(): | ||
""" | ||
Python 3.8+ no longer searches for DLLs in PATH, so we have to add | ||
everything in PATH manually. Note that unlike PATH add_dll_directory | ||
has no defined order, so if there are two cairo DLLs in PATH we | ||
might get a random one. | ||
""" | ||
if not hasattr(os, "add_dll_directory"): | ||
return | ||
for path in os.environ.get("PATH", "").split(os.pathsep): | ||
try: | ||
os.add_dll_directory(path) | ||
except OSError: | ||
pass | ||
|
||
|
||
def search_folders(root_path, folder_name): | ||
found_folders = [] | ||
with os.scandir(root_path) as entries: | ||
for entry in entries: | ||
if entry.is_dir() and folder_name in entry.name: | ||
found_folders.append(entry.path) | ||
return found_folders | ||
|
||
|
||
def search_file_in_folders(folders, file_name): | ||
found_paths = [] | ||
for folder_path in folders: | ||
file_paths = search_file_recursive(folder_path, file_name) | ||
found_paths.extend(file_paths) | ||
return found_paths | ||
|
||
|
||
def search_file_recursive(folder_path, file_name): | ||
found_paths = [] | ||
for dirpath, _, filenames in os.walk(folder_path): | ||
for filename in filenames: | ||
if filename == file_name: | ||
found_paths.append(dirpath) | ||
return found_paths | ||
|
||
|
||
def fix_cairo(): | ||
set_dll_search_path() | ||
if find_library("libcairo-2"): | ||
return | ||
else: | ||
choice = input(fix_cairo_long_intro).lower() | ||
if choice == "y" or choice == "": | ||
GTK_installer = download_GTK_installer() | ||
GTK_install_cmd = os.path.join(mathicsscript_path, "install_GTK.cmd") | ||
with open(os.path.join(mathicsscript_path, "install_GTK.cmd"), "w") as file: | ||
file.write(f'"{GTK_installer}"') | ||
subprocess.run( | ||
GTK_install_cmd | ||
) # Allow users to run installer as administrators. Tried to run it directly with subprocess.run(['runas', '/user:Administrator', ...]) and failed :( | ||
os.remove(GTK_install_cmd) | ||
set_dll_search_path() | ||
# Manually add GTK+ for Windows dll libraries to os.environ["PATH"] | ||
GTK_folders = search_folders("C:\\Program Files", "GTK") | ||
GTK_dll_paths = search_file_in_folders(GTK_folders, "libcairo-2.dll") | ||
if GTK_dll_paths: | ||
os.environ["PATH"] += os.pathsep + GTK_dll_paths[0] | ||
if find_library("libcairo-2"): | ||
print("Successfully fixed cairocffi for mathicsscript.") | ||
else: | ||
print( | ||
"Please restart the current terminal to make the changes take effect." | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,6 +86,7 @@ def read(*rnames): | |
# "mathics_pygments @ https://github.com/Mathics3/mathics-pygments/archive/master.zip#egg=mathics_pygments", | ||
"mathics_pygments>=1.0.2", | ||
"term-background >= 1.0.1", | ||
'tqdm', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a dependency that is only needed for Windows right now. |
||
], | ||
entry_points={ | ||
"console_scripts": [ | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kind of thing is better done in setup.py rather than as part of the that gets run on every invocation of mathicsscript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll move the GTK+ installation part to setup.py when I have time. As for
set_dll_search_path()
, it should get run on every invocation of mathicsscript unless cairocffi itself is fixed. I've put in a PR to cairocffi and if they approve it, everything can be done in setup.py.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome!