Skip to content

Commit

Permalink
Some restructuring.
Browse files Browse the repository at this point in the history
  • Loading branch information
Paebbels committed Mar 1, 2022
1 parent 6408645 commit f1c1aea
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 72 deletions.
12 changes: 6 additions & 6 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,20 @@ How does it work?
2. Scan the Xilinx installation directory for available Vivado versions.
3. If a matching version was found, start Vivado and pass the ``*.xpr`` as a parameter.

Differences to opening the ``*.xpr`` from GUI?
==============================================
Differences to opening the ``*.xpr`` from within Vivado GUI?
============================================================

By default, Xilinx Vivado has its working directory in ``AppData``, but the working directory should be in the directory
where the ``*.xpr`` file is located. This is fixed by **pyEDAA.Launcher** as a side effect. Now, Vivado saves log and
journal files to the correct locations.


.. _usecase:
.. #_usecase:
Use Cases
*********
Use Cases
*********
* Handle multiple parallel Xilinx Vivado installations.
* Handle multiple parallel Xilinx Vivado installations.
.. _news:
Expand Down
159 changes: 95 additions & 64 deletions pyEDAA/Launcher/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,84 +36,129 @@
__version__ = "0.1.0"
__keywords__ = ["launcher", "version selector", "xilinx", "vivado"]

from re import compile as re_compile

import sys
import subprocess
from pathlib import Path
from textwrap import dedent
import time
from typing import NoReturn
from typing import NoReturn, Generator

from pyTooling.Decorators import export

sub_path_bat = Path("bin/vivado.bat")
sub_path_vvgl = Path("bin/unwrapped/win64.o/vvgl.exe")
match_line = "<!-- Product Version: Vivado v"


@export
def get_version(file_path):
if not file_path.exists():
raise Exception(f"Vivado project file '{file_path}' not found.") from FileNotFoundError(f"File '{file_path}' not found.")

project_file = file_path.open()
versionLineRegExp = re_compile(r"^<!--\s*Product\sVersion:\s+Vivado\s+v(?P<major>\d+).(?P<minor>\d+)(?:.(?P<patch>\d+))?\s+\(64-bit\)\s+-->")

while True:
line = project_file.readline()
if match_line in line:
break

version = line.split(match_line)[1]
version = version.split(" ")[0]
version = version.split(".")
version_major = version[0]
version_minor = version[1]
project_file.close()
return str(version_major + "." + version_minor)
@export
class Program:
"""Program instance of pyEDAA.Launcher."""

_projectFilePath: Path

def __init__(self, projectFilePath: Path):
"""Initializer.
:param projectFilePath: Path to the ``*.xpr`` file.
:raises Exception: When the given ``*.xpr`` file doesn't exist.
"""
if not projectFilePath.exists():
raise Exception(f"Vivado project file '{projectFilePath}' not found.") from FileNotFoundError(f"File '{projectFilePath}' not found.")

self._projectFilePath = projectFilePath

def GetVersion(self) -> str:
"""Opens an ``*.xpr`` file and returns the Vivado version used to save this file.
:returns: Used Vivado version to save the given ``*.xpr`` file.
:raises Exception: When the version information isn't found in the file.
"""
with self._projectFilePath.open("r") as file:
for line in file:
match = versionLineRegExp.match(line)
if match is not None:
return f"{match['major']}.{match['minor']}"
else:
raise Exception(f"Pattern not found in '{self._projectFilePath}'.")

@classmethod
def GetVivadoVersions(self, installPath: Path) -> Generator[str, None, None]:
"""Scan a given directory for installed Vivado versions.
:param installPath: Xilinx installation directory.
:returns: A generator for a sequence of installed Vivado versions.
"""
for item in installPath.iterdir():
if item.is_dir():
yield item.name

@classmethod
def PrintHelp(cls, scriptPath: Path) -> None:
"""Print a help page.
:param scriptPath: Path to this script.
"""
print(dedent(f"""\
Run-Path '{scriptPath}'
For using this Launcher, please bind the *.xpr file extension to this executable with:
* Put this executable into the Vivado installation folder. E.g: C:\\Xilinx\\Vivado\\
* Change *.xpr association: right-click -> open with -> VivadoManager.exe
"""))


@export
def get_vivado_versions(install_path):
return [item.name for item in install_path.iterdir() if item.is_dir()]
def main() -> NoReturn:
"""Entry point function.
It creates an instance of :class:`Program` and hands over the execution to the OOP world.
"""
install_path = Path.cwd()
script_path = Path(sys.argv[0])

@export
def PrintHelp(script_path: Path) -> None:
print(dedent(f"""\
Run-Path '{script_path}'
if len(sys.argv) == 0:
Program.PrintHelp(script_path)

For using this VivadoManager please bind xpr extension to this executable with:
* Put this executable into the Vivado installation folder. E.g: c:\\Xilinx\\Vivado\\
* Change *.xpr association: right-click-> open-width-> VivadoManager.exe
"""))
print(f"Current path '{install_path}' has following folders in it:")
for version in Program.GetVivadoVersions(install_path):
print(version)

print("")
print("Press any key to exit.")

@export
def main() -> NoReturn:
install_path = Path.cwd()
script_path = Path(sys.argv[0])
# wait on user interaction
input()
sys.exit(0)

if len(sys.argv) > 1:
inputArg1 = sys.argv[1]
file_path = Path(inputArg1)
elif len(sys.argv) == 1:
projectFileArgument = sys.argv[1]
projectFilePath = Path(projectFileArgument)

file_version = get_version(file_path)
vivado_versions = get_vivado_versions(install_path)
program = Program(projectFilePath)

for version in vivado_versions:
if file_version == str(version):
exec_path1 = install_path / file_version / sub_path_vvgl
exec_path2 = install_path / file_version / sub_path_bat
a = str(file_path)
cmd = [str(exec_path1), str(exec_path2), a]
subprocess.Popen(cmd, cwd=file_path.parent)#, creationflags=subprocess.DETACHED_PROCESS)
try:
versionFromXPRFile = program.GetVersion()
except Exception as ex:
print(f"[ERROR] {ex}")
exit(1)

for version in program.GetVivadoVersions(install_path):
if version == versionFromXPRFile:
vvglWrapperPath = install_path / versionFromXPRFile / sub_path_vvgl
vivadoBatchfilePath = install_path / versionFromXPRFile / sub_path_bat
cmd = [str(vvglWrapperPath), str(vivadoBatchfilePath), str(projectFilePath)]
subprocess.Popen(cmd, cwd=projectFilePath.parent)#, creationflags=subprocess.DETACHED_PROCESS)
print("")
print(f"Open Project with Vivado Version {file_version}.")
print(f"Open Project with Vivado Version {versionFromXPRFile}.")
time.sleep(2)
sys.exit(0)
else:
vivadoPath = install_path / file_version
vivadoPath = install_path / versionFromXPRFile
print(dedent(f"""\
ERROR: Vivado version {file_version} not available at path '{vivadoPath}'. Please start manually!
ERROR: Vivado version {versionFromXPRFile} not available at path '{vivadoPath}'. Please start manually!
Press any key to exit.
"""))
Expand All @@ -122,22 +167,8 @@ def main() -> NoReturn:
input()
sys.exit(1)

else:
PrintHelp(script_path)

vivado_versions = get_vivado_versions(install_path)
print(f"Current path '{install_path}' has following files/folders in it:")
for version in vivado_versions:
print(version)

print("")
print("Press any key to exit.")

# wait on user interaction
input()
sys.exit(0)


# Entry point
if __name__ == "__main__":
main()
main()
5 changes: 3 additions & 2 deletions tests/unit/Vivado.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@
from pathlib import Path
from unittest import TestCase

from pyEDAA.Launcher import get_version
from pyEDAA.Launcher import Program


class ReadXPRFile(TestCase):
def test_ExtractVersionFromXPRFile(self):
xprFilePath = Path("StopWatch.xpr")
version = get_version(xprFilePath)
program = Program(xprFilePath)
version = program.GetVersion()

self.assertEqual("2021.2", version)

0 comments on commit f1c1aea

Please sign in to comment.