diff --git a/agents/build.py b/agents/build.py index 64086f9..f2479ae 100644 --- a/agents/build.py +++ b/agents/build.py @@ -4,9 +4,10 @@ import subprocess import sys from pathlib import Path +from typing import List -def main(argv: list[str]): +def main(argv: List[str]): npm = argv[1] paths = [Path(p).resolve() for p in argv[2:]] inputs = paths[:-2] @@ -24,7 +25,7 @@ def main(argv: list[str]): sys.exit(1) -def build(npm: Path, inputs: list[Path], output_js: Path, priv_dir: Path): +def build(npm: Path, inputs: List[Path], output_js: Path, priv_dir: Path): pkg_file = next((f for f in inputs if f.name == "package.json")) pkg_parent = pkg_file.parent entrypoint = inputs[0].relative_to(pkg_parent) diff --git a/apps/build.py b/apps/build.py index 672cd73..4c93878 100644 --- a/apps/build.py +++ b/apps/build.py @@ -3,10 +3,11 @@ import subprocess import sys from pathlib import Path +from typing import List from zipfile import ZipFile -def main(argv: list[str]): +def main(argv: List[str]): npm = argv[1] paths = [Path(p).resolve() for p in argv[2:]] inputs = paths[:-2] @@ -24,7 +25,7 @@ def main(argv: list[str]): sys.exit(1) -def build(npm: Path, inputs: list[Path], output_zip: Path, priv_dir: Path): +def build(npm: Path, inputs: List[Path], output_zip: Path, priv_dir: Path): pkg_file = next((f for f in inputs if f.name == "package.json")) pkg_parent = pkg_file.parent diff --git a/bridges/build.py b/bridges/build.py index ace3f1e..7b87dc5 100644 --- a/bridges/build.py +++ b/bridges/build.py @@ -2,6 +2,7 @@ import subprocess import sys from pathlib import Path +from typing import List def main(argv): @@ -18,7 +19,7 @@ def main(argv): sys.exit(1) -def compile_bridges(inputs: list[Path], output_dir: Path, priv_dir: Path, npm: Path): +def compile_bridges(inputs: List[Path], output_dir: Path, priv_dir: Path, npm: Path): pkg_file = next((f for f in inputs if f.name == "package.json")) pkg_parent = pkg_file.parent diff --git a/meson.build b/meson.build index 96f8a57..2554735 100644 --- a/meson.build +++ b/meson.build @@ -1,11 +1,20 @@ -project('frida-tools', 'c', - version: run_command(find_program('python3'), files('setup.py'), '-V', +project( + 'frida-tools', + 'c', + version: run_command( + find_program('python3'), + meson.current_source_dir() / 'releng' / 'frida_version.py', capture: true, - check: true).stdout().strip(), + check: true, + ).stdout().strip(), meson_version: '>=1.1.0', ) -subproject('frida-python') +meson.add_dist_script( + find_program('python'), + meson.current_source_dir() / 'set_dist_version.py', + meson.project_version(), +) python = import('python').find_installation() diff --git a/pyproject.toml b/pyproject.toml index 5331f3f..58003b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,79 @@ +[project] +name = "frida-tools" +dynamic = ['version'] +description = "Frida CLI tools" +authors = [{ name = "Frida Developers", email = "oleavr@frida.re" }] +urls = { homepage = "https://frida.re", repository = "https://github.com/frida/frida-tools" } +license = "wxWindows" +keywords = [ + "frida", + "debugger", + "dynamic", + "instrumentation", + "inject", + "javascript", + "windows", + "macos", + "linux", + "ios", + "iphone", + "ipad", + "android", + "qnx", +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Environment :: MacOS X", + "Environment :: Win32 (MS Windows)", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Natural Language :: English", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: JavaScript", + "Topic :: Software Development :: Debuggers", + "Topic :: Software Development :: Libraries :: Python Modules", +] + +requires-python = ">=3.7" +dependencies = [ + "colorama >= 0.2.7, < 1.0.0", + "frida >= 17.2.8, < 18.0.0", + "prompt-toolkit >= 2.0.0, < 4.0.0", + "pygments >= 2.0.2, < 3.0.0", + "websockets >= 13.0.0, < 14.0.0", +] + +[project.scripts] +frida = "frida_tools.repl:main" +frida-ls-devices = "frida_tools.lsd:main" +frida-ps = "frida_tools.ps:main" +frida-kill = "frida_tools.kill:main" +frida-ls = "frida_tools.ls:main" +frida-rm = "frida_tools.rm:main" +frida-pull = "frida_tools.pull:main" +frida-push = "frida_tools.push:main" +frida-discover = "frida_tools.discoverer:main" +frida-trace = "frida_tools.tracer:main" +frida-itrace = "frida_tools.itracer:main" +frida-join = "frida_tools.join:main" +frida-create = "frida_tools.creator:main" +frida-compile = "frida_tools.compiler:main" +frida-apk = "frida_tools.apk:main" +frida-pm = "frida_tools.pm:main" + +[build-system] +build-backend = 'mesonpy' +requires = ['meson-python'] + + [tool.black] line-length = 120 diff --git a/set_dist_version.py b/set_dist_version.py new file mode 100755 index 0000000..c5d2e80 --- /dev/null +++ b/set_dist_version.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import argparse +import os +import shlex +import subprocess +import sys +from typing import List + + +def main(argv: List[str]) -> None: + parser = argparse.ArgumentParser() + parser.add_argument("version", type=str) + args = parser.parse_args() + set_dist_version(args.version) + + +def set_dist_version(version: str) -> None: + """ + Used to replace the version in the meson.build file when building a dist build + """ + subprocess.run( + [ + *shlex.split(os.environ["MESONREWRITE"]), + "--sourcedir", + os.environ["MESON_PROJECT_DIST_ROOT"], + "kwargs", + "set", + "project", + "/", + "version", + version, + ], + check=True, + ) + print(version) + return + + +if __name__ == "__main__": + main(sys.argv) diff --git a/setup.py b/setup.py deleted file mode 100644 index ecf3c47..0000000 --- a/setup.py +++ /dev/null @@ -1,154 +0,0 @@ -import os -import shutil -import sys -from pathlib import Path -from typing import Iterator, List - -from setuptools import setup - -SOURCE_ROOT = Path(__file__).resolve().parent - -pkg_info = SOURCE_ROOT / "PKG-INFO" -in_source_package = pkg_info.exists() - - -def main(): - setup( - name="frida-tools", - version=detect_version(), - description="Frida CLI tools", - long_description="CLI tools for [Frida](https://frida.re).", - long_description_content_type="text/markdown", - author="Frida Developers", - author_email="oleavr@frida.re", - url="https://frida.re", - install_requires=[ - "colorama >= 0.2.7, < 1.0.0", - "frida >= 17.2.8, < 18.0.0", - "prompt-toolkit >= 2.0.0, < 4.0.0", - "pygments >= 2.0.2, < 3.0.0", - "websockets >= 13.0.0, < 14.0.0", - ], - license="wxWindows Library Licence, Version 3.1", - zip_safe=False, - keywords="frida debugger dynamic instrumentation inject javascript windows macos linux ios iphone ipad android qnx", - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Environment :: Console", - "Environment :: MacOS X", - "Environment :: Win32 (MS Windows)", - "Intended Audience :: Developers", - "Intended Audience :: Science/Research", - "License :: OSI Approved", - "Natural Language :: English", - "Operating System :: MacOS :: MacOS X", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: JavaScript", - "Topic :: Software Development :: Debuggers", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - packages=["frida_tools"], - package_data={ - "frida_tools": fetch_built_assets(), - }, - entry_points={ - "console_scripts": [ - "frida = frida_tools.repl:main", - "frida-ls-devices = frida_tools.lsd:main", - "frida-ps = frida_tools.ps:main", - "frida-kill = frida_tools.kill:main", - "frida-ls = frida_tools.ls:main", - "frida-rm = frida_tools.rm:main", - "frida-pull = frida_tools.pull:main", - "frida-push = frida_tools.push:main", - "frida-discover = frida_tools.discoverer:main", - "frida-trace = frida_tools.tracer:main", - "frida-itrace = frida_tools.itracer:main", - "frida-join = frida_tools.join:main", - "frida-create = frida_tools.creator:main", - "frida-compile = frida_tools.compiler:main", - "frida-pm = frida_tools.pm:main", - "frida-apk = frida_tools.apk:main", - ] - }, - ) - - -def detect_version() -> str: - if in_source_package: - version_line = [ - line for line in pkg_info.read_text(encoding="utf-8").split("\n") if line.startswith("Version: ") - ][0].strip() - version = version_line[9:] - else: - releng_location = next(enumerate_releng_locations(), None) - if releng_location is not None: - sys.path.insert(0, str(releng_location.parent)) - from releng.frida_version import detect - - version = detect(SOURCE_ROOT).name.replace("-dev.", ".dev") - else: - version = "0.0.0" - return version - - -def fetch_built_assets() -> List[str]: - assets = [] - - if in_source_package: - pkgdir = SOURCE_ROOT / "frida_tools" - assets += [f.name for f in pkgdir.glob("*_agent.js")] - assets += [f.relative_to(pkgdir).as_posix() for f in (pkgdir / "bridges").glob("*.js")] - assets += [f.name for f in pkgdir.glob("*.zip")] - else: - agents_builddir = SOURCE_ROOT / "build" / "agents" - if agents_builddir.exists(): - for child in agents_builddir.iterdir(): - if child.is_dir(): - for f in child.glob("*_agent.js"): - shutil.copy(f, SOURCE_ROOT / "frida_tools") - assets.append(f.name) - - bridges_builddir = SOURCE_ROOT / "build" / "bridges" - if bridges_builddir.exists(): - bridges_dir = SOURCE_ROOT / "frida_tools" / "bridges" - bridges_dir.mkdir(exist_ok=True) - for f in bridges_builddir.glob("*.js"): - shutil.copy(f, bridges_dir) - assets.append((Path("bridges") / f.name).as_posix()) - - apps_builddir = SOURCE_ROOT / "build" / "apps" - if apps_builddir.exists(): - for child in apps_builddir.iterdir(): - if child.is_dir(): - for f in child.glob("*.zip"): - shutil.copy(f, SOURCE_ROOT / "frida_tools") - assets.append(f.name) - - return assets - - -def enumerate_releng_locations() -> Iterator[Path]: - val = os.environ.get("MESON_SOURCE_ROOT") - if val is not None: - parent_releng = Path(val) / "releng" - if releng_location_exists(parent_releng): - yield parent_releng - - local_releng = SOURCE_ROOT / "releng" - if releng_location_exists(local_releng): - yield local_releng - - -def releng_location_exists(location: Path) -> bool: - return (location / "frida_version.py").exists() - - -if __name__ == "__main__": - main()