forked from iqm-finland/KQCircuits
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup_helper.py
129 lines (117 loc) · 6.22 KB
/
setup_helper.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# This code is part of KQCircuits
# Copyright (C) 2022 IQM Finland Oy
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program. If not, see
# https://www.gnu.org/licenses/gpl-3.0.html.
#
# The software distribution should follow IQM trademark policy for open-source software
# (meetiqm.com/iqm-open-source-trademark-policy). IQM welcomes contributions to the code.
# Please see our contribution agreements for individuals (meetiqm.com/iqm-individual-contributor-license-agreement)
# and organizations (meetiqm.com/iqm-organization-contributor-license-agreement).
import os
import platform
import subprocess
from shutil import which
# Retuns KLayout's configuration directory already associated with `root_path`.
# If it is not found then creates and returns the right directory to use.
# If the default .klayout is used by an other KQC then use .klayout_alt/This_KQC
def klayout_configdir(root_path, configdir=""):
if not configdir:
if os.name == "nt":
config_dir_name = "KLayout"
elif os.name == "posix":
config_dir_name = ".klayout"
else:
raise SystemError("Error: unsupported operating system")
configdir = os.path.join(os.path.expanduser("~"), config_dir_name)
# Directories may not exist, create them, if needed.
if not os.path.exists(f"{configdir}/drc"):
os.makedirs(f"{configdir}/drc")
klayout_python_path = f"{configdir}/python"
if not os.path.exists(klayout_python_path):
os.makedirs(klayout_python_path)
return configdir
kqc_link = os.path.realpath(f"{klayout_python_path}/kqcircuits")
kqc_target = f"{root_path}/klayout_package/python/kqcircuits"
if not os.path.exists(kqc_link) or os.path.samefile(kqc_link, kqc_target): # found it
return configdir
elif not configdir.endswith("_alt"): # look for alternative location, like ".klayout_alt/my_2nd_kqc_dir"
dir_name = os.path.split(root_path)[1]
return klayout_configdir(root_path, f"{configdir}_alt/{dir_name}")
else: # Several alternatives with identical name. Discourage and overwrite.
print(f"Warning: {configdir} already used! Reconfiguring for this source directory.")
return configdir
# This function createst KLayout symlinks. Used by setup_within_klayout.py.
def setup_symlinks(root_path, configdir, link_map, unlink=False):
for target, name in link_map:
if target is not None:
link_target = os.path.join(root_path, target)
else:
link_target = "Unknown"
link_name = os.path.join(configdir, name)
if os.path.lexists(link_name):
os.unlink(link_name)
if unlink:
print(f'Removed symlink "{link_name}" to "{link_target}"')
elif unlink:
print(
f'You set `unlink=True`, but symlink "{link_name}" to "{link_target}" does not exist... This is doing nothing.'
)
if not unlink:
if os.name == "nt":
# On Windows, create a Junction to avoid requiring Administrative privileges
subprocess.check_call(
["cmd", "/c", "mklink", "/J", os.path.normpath(link_name), os.path.normpath(link_target)]
)
else:
os.symlink(link_target, link_name, target_is_directory=True)
print(f'Created symlink "{link_name}" to "{link_target}"')
# Returns the python version, expected platform and site-packages path of KLayout's python distribution.
# A small script is run by KLayout in batch mode, and the output is read from external file.
def get_klayout_python_info():
if platform.system() == "Windows":
klayout_path = which("klayout_app.exe")
if klayout_path is None: # try the default location
dwp = os.path.join(os.getenv("APPDATA"), "KLayout", "klayout_app.exe")
if os.path.exists(dwp):
klayout_path = str(dwp)
else:
klayout_path = which("klayout") # Linux is simple :)
if klayout_path is None and platform.system() == "Darwin":
dwp = "/Applications/klayout.app/Contents/MacOS/klayout"
if os.path.exists(dwp):
klayout_path = dwp
dwp = "/Applications/KLayout/klayout.app/Contents/MacOS/klayout"
if os.path.exists(dwp):
klayout_path = dwp
if not klayout_path:
raise Exception("Can't find klayout executable command!")
if os.path.exists(".klayout-python.info"):
os.remove(".klayout-python.info")
subprocess.check_call([klayout_path, "-b", "-r", os.path.join("util", "get_klayout_python_info.py")])
while not os.path.exists(".klayout-python.info"):
continue
klayout_py_version, klayout_py_platforms, klayout_site_packages = None, [], None
for _ in range(10):
with open(".klayout-python.info", encoding="utf-8") as f:
for line in f:
if line.startswith("KLayout python platform: "):
klayout_py_platforms.append(line.split("KLayout python platform: ")[1].strip())
elif line.startswith("KLayout python version: "):
klayout_py_version = line.split("KLayout python version: ")[1].strip()
elif line.startswith("KLayout site-packages: "):
klayout_site_packages = line.split("KLayout site-packages: ")[1].strip()
if klayout_py_platforms and klayout_py_version and klayout_site_packages:
break
if os.path.exists(".klayout-python.info"):
os.remove(".klayout-python.info")
if not (klayout_py_platforms and klayout_py_version and klayout_site_packages):
raise Exception("Couldn't get KLayout python's info")
return klayout_py_version, klayout_py_platforms, klayout_site_packages