diff --git a/docs/developer-guide.md b/docs/developer-guide.md index c016024..eff56aa 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -78,7 +78,13 @@ dotnet publish -c Release -r linux-x64 --self-contained dotnet publish -c Release -r win-x64 --self-contained ``` -3. Archive and package binaries into `./dist/`: +3. Build a binary for MacOS: + +```bash +dotnet publish -c Release -r osx-x64 --self-contained +``` + +4. Archive and package binaries into `./dist/`: ## Running Tests diff --git a/src/python_redlines/engines.py b/src/python_redlines/engines.py index 0775630..2d64a94 100644 --- a/src/python_redlines/engines.py +++ b/src/python_redlines/engines.py @@ -12,9 +12,9 @@ class XmlPowerToolsEngine(object): def __init__(self): - self.extracted_binaries_path = self._unzip_binary() + self.extracted_binaries_path = self.__unzip_binary() - def _unzip_binary(self): + def __unzip_binary(self): """ Unzips the appropriate C# binary for the current platform. """ @@ -25,37 +25,60 @@ def _unzip_binary(self): if not os.path.exists(target_path): os.makedirs(target_path) + # Get the binary name and zip name based on the OS and architecture + binary_name, zip_name = self.__get_binaries_info() + + # Check if the binary already exists. If not, extract it. + full_binary_path = os.path.join(target_path, binary_name) + + if not os.path.exists(full_binary_path): + zip_path = os.path.join(binaries_path, zip_name) + self.__extract_binary(zip_path, target_path) + + return os.path.join(target_path, binary_name) + + def __extract_binary(self, zip_path: str, target_path: str): + """ + Extracts the binary from the zip file based on the extension. Supports .zip and .tar.gz files + :parameter + zip_path: str - The path to the zip file + target_path: str - The path to extract the binary to + """ + + if zip_path.endswith('.zip'): + with zipfile.ZipFile(zip_path, 'r') as zip_ref: + zip_ref.extractall(target_path) + + elif zip_path.endswith('.tar.gz'): + with tarfile.open(zip_path, 'r:gz') as tar_ref: + tar_ref.extractall(target_path) + + def __get_binaries_info(self): + """ + Returns the binary name and zip name based on the OS and architecture + :return + binary_name: str - The name of the binary file + zip_name: str - The name of the zip file + """ os_name = platform.system().lower() arch = 'x64' # Assuming x64 architecture if os_name == 'linux': zip_name = f"linux-{arch}-{__version__}.tar.gz" binary_name = 'linux-x64/redlines' - zip_path = os.path.join(binaries_path, zip_name) - if not os.path.exists(zip_path): - with tarfile.open(zip_path, 'r:gz') as tar_ref: - tar_ref.extractall(target_path) elif os_name == 'windows': zip_name = f"win-{arch}-{__version__}.zip" binary_name = 'win-x64/redlines.exe' - zip_path = os.path.join(binaries_path, zip_name) - if not os.path.exists(zip_path): - with zipfile.ZipFile(zip_path, 'r') as zip_ref: - zip_ref.extractall(target_path) elif os_name == 'darwin': zip_name = f"osx-{arch}-{__version__}.tar.gz" binary_name = 'osx-x64/redlines' - zip_path = os.path.join(binaries_path, zip_name) - if not os.path.exists(zip_path): - with tarfile.open(zip_path, 'r:gz') as tar_ref: - tar_ref.extractall(target_path) else: raise EnvironmentError("Unsupported OS") - return os.path.join(target_path, binary_name) + return binary_name, zip_name def run_redline(self, author_tag: str, original: Union[bytes, Path], modified: Union[bytes, Path]) \ -> Tuple[bytes, Optional[str], Optional[str]]: