frida 16.2.1 → 16.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BSDmakefile +6 -0
- package/Makefile +16 -0
- package/README.md +14 -11
- package/configure +18 -0
- package/configure.bat +22 -0
- package/dist/native.js +0 -8
- package/lib/application.ts +98 -0
- package/lib/authentication.ts +3 -0
- package/lib/build.py +50 -0
- package/lib/bus.ts +30 -0
- package/lib/cancellable.ts +33 -0
- package/lib/child.ts +15 -0
- package/lib/crash.ts +11 -0
- package/lib/device.ts +329 -0
- package/lib/device_manager.ts +69 -0
- package/lib/endpoint_parameters.ts +56 -0
- package/lib/icon.ts +15 -0
- package/lib/index.ts +311 -0
- package/lib/iostream.ts +78 -0
- package/lib/meson.build +53 -0
- package/lib/native.ts +9 -0
- package/lib/portal_membership.ts +10 -0
- package/lib/portal_service.ts +105 -0
- package/lib/process.ts +57 -0
- package/lib/relay.ts +44 -0
- package/lib/script.ts +352 -0
- package/lib/session.ts +113 -0
- package/lib/signals.ts +45 -0
- package/lib/socket_address.ts +35 -0
- package/lib/spawn.ts +4 -0
- package/lib/system_parameters.ts +78 -0
- package/make.bat +23 -0
- package/meson.build +160 -0
- package/meson.options +11 -0
- package/package.json +27 -6
- package/releng/deps.py +1133 -0
- package/releng/deps.toml +391 -0
- package/releng/devkit-assets/frida-core-example-unix.c +188 -0
- package/releng/devkit-assets/frida-core-example-windows.c +197 -0
- package/releng/devkit-assets/frida-core-example.sln +28 -0
- package/releng/devkit-assets/frida-core-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-core-example.vcxproj.filters +27 -0
- package/releng/devkit-assets/frida-gum-example-unix.c +122 -0
- package/releng/devkit-assets/frida-gum-example-windows.c +132 -0
- package/releng/devkit-assets/frida-gum-example.sln +28 -0
- package/releng/devkit-assets/frida-gum-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-gum-example.vcxproj.filters +27 -0
- package/releng/devkit-assets/frida-gumjs-example-unix.c +84 -0
- package/releng/devkit-assets/frida-gumjs-example-windows.c +91 -0
- package/releng/devkit-assets/frida-gumjs-example.sln +28 -0
- package/releng/devkit-assets/frida-gumjs-example.vcxproj +157 -0
- package/releng/devkit-assets/frida-gumjs-example.vcxproj.filters +27 -0
- package/releng/devkit.py +535 -0
- package/releng/env.py +420 -0
- package/releng/env_android.py +150 -0
- package/releng/env_apple.py +176 -0
- package/releng/env_generic.py +373 -0
- package/releng/frida_version.py +69 -0
- package/releng/machine_file.py +44 -0
- package/releng/machine_spec.py +290 -0
- package/releng/meson/meson.py +27 -0
- package/releng/meson/mesonbuild/__init__.py +0 -0
- package/releng/meson/mesonbuild/_pathlib.py +63 -0
- package/releng/meson/mesonbuild/_typing.py +69 -0
- package/releng/meson/mesonbuild/arglist.py +321 -0
- package/releng/meson/mesonbuild/ast/__init__.py +23 -0
- package/releng/meson/mesonbuild/ast/interpreter.py +441 -0
- package/releng/meson/mesonbuild/ast/introspection.py +374 -0
- package/releng/meson/mesonbuild/ast/postprocess.py +109 -0
- package/releng/meson/mesonbuild/ast/printer.py +620 -0
- package/releng/meson/mesonbuild/ast/visitor.py +161 -0
- package/releng/meson/mesonbuild/backend/__init__.py +0 -0
- package/releng/meson/mesonbuild/backend/backends.py +2047 -0
- package/releng/meson/mesonbuild/backend/ninjabackend.py +3808 -0
- package/releng/meson/mesonbuild/backend/nonebackend.py +26 -0
- package/releng/meson/mesonbuild/backend/vs2010backend.py +2078 -0
- package/releng/meson/mesonbuild/backend/vs2012backend.py +35 -0
- package/releng/meson/mesonbuild/backend/vs2013backend.py +34 -0
- package/releng/meson/mesonbuild/backend/vs2015backend.py +35 -0
- package/releng/meson/mesonbuild/backend/vs2017backend.py +59 -0
- package/releng/meson/mesonbuild/backend/vs2019backend.py +54 -0
- package/releng/meson/mesonbuild/backend/vs2022backend.py +54 -0
- package/releng/meson/mesonbuild/backend/xcodebackend.py +1781 -0
- package/releng/meson/mesonbuild/build.py +3249 -0
- package/releng/meson/mesonbuild/cargo/__init__.py +5 -0
- package/releng/meson/mesonbuild/cargo/builder.py +238 -0
- package/releng/meson/mesonbuild/cargo/cfg.py +274 -0
- package/releng/meson/mesonbuild/cargo/interpreter.py +733 -0
- package/releng/meson/mesonbuild/cargo/manifest.py +227 -0
- package/releng/meson/mesonbuild/cargo/version.py +95 -0
- package/releng/meson/mesonbuild/cmake/__init__.py +28 -0
- package/releng/meson/mesonbuild/cmake/common.py +331 -0
- package/releng/meson/mesonbuild/cmake/data/__init__.py +0 -0
- package/releng/meson/mesonbuild/cmake/data/preload.cmake +82 -0
- package/releng/meson/mesonbuild/cmake/executor.py +241 -0
- package/releng/meson/mesonbuild/cmake/fileapi.py +324 -0
- package/releng/meson/mesonbuild/cmake/generator.py +186 -0
- package/releng/meson/mesonbuild/cmake/interpreter.py +1267 -0
- package/releng/meson/mesonbuild/cmake/toolchain.py +248 -0
- package/releng/meson/mesonbuild/cmake/traceparser.py +814 -0
- package/releng/meson/mesonbuild/cmake/tracetargets.py +161 -0
- package/releng/meson/mesonbuild/compilers/__init__.py +86 -0
- package/releng/meson/mesonbuild/compilers/asm.py +307 -0
- package/releng/meson/mesonbuild/compilers/c.py +788 -0
- package/releng/meson/mesonbuild/compilers/c_function_attributes.py +143 -0
- package/releng/meson/mesonbuild/compilers/compilers.py +1388 -0
- package/releng/meson/mesonbuild/compilers/cpp.py +1035 -0
- package/releng/meson/mesonbuild/compilers/cs.py +136 -0
- package/releng/meson/mesonbuild/compilers/cuda.py +806 -0
- package/releng/meson/mesonbuild/compilers/cython.py +91 -0
- package/releng/meson/mesonbuild/compilers/d.py +861 -0
- package/releng/meson/mesonbuild/compilers/detect.py +1396 -0
- package/releng/meson/mesonbuild/compilers/fortran.py +523 -0
- package/releng/meson/mesonbuild/compilers/java.py +113 -0
- package/releng/meson/mesonbuild/compilers/mixins/__init__.py +0 -0
- package/releng/meson/mesonbuild/compilers/mixins/arm.py +167 -0
- package/releng/meson/mesonbuild/compilers/mixins/ccrx.py +113 -0
- package/releng/meson/mesonbuild/compilers/mixins/clang.py +170 -0
- package/releng/meson/mesonbuild/compilers/mixins/clike.py +1330 -0
- package/releng/meson/mesonbuild/compilers/mixins/compcert.py +117 -0
- package/releng/meson/mesonbuild/compilers/mixins/elbrus.py +93 -0
- package/releng/meson/mesonbuild/compilers/mixins/emscripten.py +89 -0
- package/releng/meson/mesonbuild/compilers/mixins/gnu.py +629 -0
- package/releng/meson/mesonbuild/compilers/mixins/intel.py +167 -0
- package/releng/meson/mesonbuild/compilers/mixins/islinker.py +120 -0
- package/releng/meson/mesonbuild/compilers/mixins/metrowerks.py +279 -0
- package/releng/meson/mesonbuild/compilers/mixins/pgi.py +88 -0
- package/releng/meson/mesonbuild/compilers/mixins/ti.py +130 -0
- package/releng/meson/mesonbuild/compilers/mixins/visualstudio.py +458 -0
- package/releng/meson/mesonbuild/compilers/mixins/xc16.py +111 -0
- package/releng/meson/mesonbuild/compilers/objc.py +120 -0
- package/releng/meson/mesonbuild/compilers/objcpp.py +102 -0
- package/releng/meson/mesonbuild/compilers/rust.py +230 -0
- package/releng/meson/mesonbuild/compilers/swift.py +131 -0
- package/releng/meson/mesonbuild/compilers/vala.py +121 -0
- package/releng/meson/mesonbuild/coredata.py +1532 -0
- package/releng/meson/mesonbuild/dependencies/__init__.py +252 -0
- package/releng/meson/mesonbuild/dependencies/base.py +663 -0
- package/releng/meson/mesonbuild/dependencies/boost.py +1083 -0
- package/releng/meson/mesonbuild/dependencies/cmake.py +656 -0
- package/releng/meson/mesonbuild/dependencies/coarrays.py +80 -0
- package/releng/meson/mesonbuild/dependencies/configtool.py +163 -0
- package/releng/meson/mesonbuild/dependencies/cuda.py +295 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakeLists.txt +102 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakeListsLLVM.txt +204 -0
- package/releng/meson/mesonbuild/dependencies/data/CMakePathInfo.txt +31 -0
- package/releng/meson/mesonbuild/dependencies/data/__init__.py +0 -0
- package/releng/meson/mesonbuild/dependencies/detect.py +225 -0
- package/releng/meson/mesonbuild/dependencies/dev.py +707 -0
- package/releng/meson/mesonbuild/dependencies/dub.py +424 -0
- package/releng/meson/mesonbuild/dependencies/factory.py +146 -0
- package/releng/meson/mesonbuild/dependencies/framework.py +111 -0
- package/releng/meson/mesonbuild/dependencies/hdf5.py +168 -0
- package/releng/meson/mesonbuild/dependencies/misc.py +618 -0
- package/releng/meson/mesonbuild/dependencies/mpi.py +231 -0
- package/releng/meson/mesonbuild/dependencies/pkgconfig.py +570 -0
- package/releng/meson/mesonbuild/dependencies/platform.py +52 -0
- package/releng/meson/mesonbuild/dependencies/python.py +431 -0
- package/releng/meson/mesonbuild/dependencies/qt.py +484 -0
- package/releng/meson/mesonbuild/dependencies/scalapack.py +142 -0
- package/releng/meson/mesonbuild/dependencies/ui.py +281 -0
- package/releng/meson/mesonbuild/depfile.py +82 -0
- package/releng/meson/mesonbuild/envconfig.py +480 -0
- package/releng/meson/mesonbuild/environment.py +987 -0
- package/releng/meson/mesonbuild/interpreter/__init__.py +47 -0
- package/releng/meson/mesonbuild/interpreter/compiler.py +900 -0
- package/releng/meson/mesonbuild/interpreter/dependencyfallbacks.py +386 -0
- package/releng/meson/mesonbuild/interpreter/interpreter.py +3595 -0
- package/releng/meson/mesonbuild/interpreter/interpreterobjects.py +1096 -0
- package/releng/meson/mesonbuild/interpreter/kwargs.py +479 -0
- package/releng/meson/mesonbuild/interpreter/mesonmain.py +487 -0
- package/releng/meson/mesonbuild/interpreter/primitives/__init__.py +29 -0
- package/releng/meson/mesonbuild/interpreter/primitives/array.py +108 -0
- package/releng/meson/mesonbuild/interpreter/primitives/boolean.py +52 -0
- package/releng/meson/mesonbuild/interpreter/primitives/dict.py +88 -0
- package/releng/meson/mesonbuild/interpreter/primitives/integer.py +86 -0
- package/releng/meson/mesonbuild/interpreter/primitives/range.py +38 -0
- package/releng/meson/mesonbuild/interpreter/primitives/string.py +247 -0
- package/releng/meson/mesonbuild/interpreter/type_checking.py +853 -0
- package/releng/meson/mesonbuild/interpreterbase/__init__.py +126 -0
- package/releng/meson/mesonbuild/interpreterbase/_unholder.py +25 -0
- package/releng/meson/mesonbuild/interpreterbase/baseobjects.py +174 -0
- package/releng/meson/mesonbuild/interpreterbase/decorators.py +806 -0
- package/releng/meson/mesonbuild/interpreterbase/disabler.py +35 -0
- package/releng/meson/mesonbuild/interpreterbase/exceptions.py +22 -0
- package/releng/meson/mesonbuild/interpreterbase/helpers.py +67 -0
- package/releng/meson/mesonbuild/interpreterbase/interpreterbase.py +665 -0
- package/releng/meson/mesonbuild/interpreterbase/operator.py +32 -0
- package/releng/meson/mesonbuild/linkers/__init__.py +20 -0
- package/releng/meson/mesonbuild/linkers/base.py +39 -0
- package/releng/meson/mesonbuild/linkers/detect.py +229 -0
- package/releng/meson/mesonbuild/linkers/linkers.py +1614 -0
- package/releng/meson/mesonbuild/mcompile.py +380 -0
- package/releng/meson/mesonbuild/mconf.py +368 -0
- package/releng/meson/mesonbuild/mdevenv.py +234 -0
- package/releng/meson/mesonbuild/mdist.py +376 -0
- package/releng/meson/mesonbuild/mesondata.py +38 -0
- package/releng/meson/mesonbuild/mesonlib.py +23 -0
- package/releng/meson/mesonbuild/mesonmain.py +289 -0
- package/releng/meson/mesonbuild/minit.py +204 -0
- package/releng/meson/mesonbuild/minstall.py +864 -0
- package/releng/meson/mesonbuild/mintro.py +667 -0
- package/releng/meson/mesonbuild/mlog.py +542 -0
- package/releng/meson/mesonbuild/modules/__init__.py +270 -0
- package/releng/meson/mesonbuild/modules/cmake.py +442 -0
- package/releng/meson/mesonbuild/modules/cuda.py +377 -0
- package/releng/meson/mesonbuild/modules/dlang.py +117 -0
- package/releng/meson/mesonbuild/modules/external_project.py +306 -0
- package/releng/meson/mesonbuild/modules/fs.py +323 -0
- package/releng/meson/mesonbuild/modules/gnome.py +2215 -0
- package/releng/meson/mesonbuild/modules/hotdoc.py +487 -0
- package/releng/meson/mesonbuild/modules/i18n.py +405 -0
- package/releng/meson/mesonbuild/modules/icestorm.py +123 -0
- package/releng/meson/mesonbuild/modules/java.py +112 -0
- package/releng/meson/mesonbuild/modules/keyval.py +65 -0
- package/releng/meson/mesonbuild/modules/modtest.py +33 -0
- package/releng/meson/mesonbuild/modules/pkgconfig.py +744 -0
- package/releng/meson/mesonbuild/modules/python.py +556 -0
- package/releng/meson/mesonbuild/modules/python3.py +85 -0
- package/releng/meson/mesonbuild/modules/qt.py +621 -0
- package/releng/meson/mesonbuild/modules/qt4.py +23 -0
- package/releng/meson/mesonbuild/modules/qt5.py +23 -0
- package/releng/meson/mesonbuild/modules/qt6.py +22 -0
- package/releng/meson/mesonbuild/modules/rust.py +355 -0
- package/releng/meson/mesonbuild/modules/simd.py +114 -0
- package/releng/meson/mesonbuild/modules/sourceset.py +291 -0
- package/releng/meson/mesonbuild/modules/wayland.py +151 -0
- package/releng/meson/mesonbuild/modules/windows.py +207 -0
- package/releng/meson/mesonbuild/mparser.py +1114 -0
- package/releng/meson/mesonbuild/msetup.py +365 -0
- package/releng/meson/mesonbuild/msubprojects.py +764 -0
- package/releng/meson/mesonbuild/mtest.py +2201 -0
- package/releng/meson/mesonbuild/munstable_coredata.py +107 -0
- package/releng/meson/mesonbuild/optinterpreter.py +276 -0
- package/releng/meson/mesonbuild/programs.py +367 -0
- package/releng/meson/mesonbuild/rewriter.py +1075 -0
- package/releng/meson/mesonbuild/scripts/__init__.py +10 -0
- package/releng/meson/mesonbuild/scripts/clangformat.py +55 -0
- package/releng/meson/mesonbuild/scripts/clangtidy.py +30 -0
- package/releng/meson/mesonbuild/scripts/cleantrees.py +35 -0
- package/releng/meson/mesonbuild/scripts/cmake_run_ctgt.py +103 -0
- package/releng/meson/mesonbuild/scripts/cmd_or_ps.ps1 +17 -0
- package/releng/meson/mesonbuild/scripts/copy.py +19 -0
- package/releng/meson/mesonbuild/scripts/coverage.py +214 -0
- package/releng/meson/mesonbuild/scripts/delwithsuffix.py +27 -0
- package/releng/meson/mesonbuild/scripts/depfixer.py +495 -0
- package/releng/meson/mesonbuild/scripts/depscan.py +198 -0
- package/releng/meson/mesonbuild/scripts/dirchanger.py +20 -0
- package/releng/meson/mesonbuild/scripts/env2mfile.py +402 -0
- package/releng/meson/mesonbuild/scripts/externalproject.py +106 -0
- package/releng/meson/mesonbuild/scripts/gettext.py +86 -0
- package/releng/meson/mesonbuild/scripts/gtkdochelper.py +286 -0
- package/releng/meson/mesonbuild/scripts/hotdochelper.py +40 -0
- package/releng/meson/mesonbuild/scripts/itstool.py +77 -0
- package/releng/meson/mesonbuild/scripts/meson_exe.py +115 -0
- package/releng/meson/mesonbuild/scripts/msgfmthelper.py +29 -0
- package/releng/meson/mesonbuild/scripts/pycompile.py +54 -0
- package/releng/meson/mesonbuild/scripts/python_info.py +121 -0
- package/releng/meson/mesonbuild/scripts/regen_checker.py +55 -0
- package/releng/meson/mesonbuild/scripts/run_tool.py +58 -0
- package/releng/meson/mesonbuild/scripts/scanbuild.py +57 -0
- package/releng/meson/mesonbuild/scripts/symbolextractor.py +322 -0
- package/releng/meson/mesonbuild/scripts/tags.py +44 -0
- package/releng/meson/mesonbuild/scripts/test_loaded_modules.py +14 -0
- package/releng/meson/mesonbuild/scripts/uninstall.py +41 -0
- package/releng/meson/mesonbuild/scripts/vcstagger.py +35 -0
- package/releng/meson/mesonbuild/scripts/yasm.py +24 -0
- package/releng/meson/mesonbuild/templates/__init__.py +0 -0
- package/releng/meson/mesonbuild/templates/cpptemplates.py +143 -0
- package/releng/meson/mesonbuild/templates/cstemplates.py +90 -0
- package/releng/meson/mesonbuild/templates/ctemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/cudatemplates.py +143 -0
- package/releng/meson/mesonbuild/templates/dlangtemplates.py +109 -0
- package/releng/meson/mesonbuild/templates/fortrantemplates.py +101 -0
- package/releng/meson/mesonbuild/templates/javatemplates.py +94 -0
- package/releng/meson/mesonbuild/templates/mesontemplates.py +70 -0
- package/releng/meson/mesonbuild/templates/objcpptemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/objctemplates.py +126 -0
- package/releng/meson/mesonbuild/templates/rusttemplates.py +79 -0
- package/releng/meson/mesonbuild/templates/samplefactory.py +41 -0
- package/releng/meson/mesonbuild/templates/sampleimpl.py +160 -0
- package/releng/meson/mesonbuild/templates/valatemplates.py +82 -0
- package/releng/meson/mesonbuild/utils/__init__.py +0 -0
- package/releng/meson/mesonbuild/utils/core.py +166 -0
- package/releng/meson/mesonbuild/utils/platform.py +27 -0
- package/releng/meson/mesonbuild/utils/posix.py +32 -0
- package/releng/meson/mesonbuild/utils/universal.py +2445 -0
- package/releng/meson/mesonbuild/utils/vsenv.py +126 -0
- package/releng/meson/mesonbuild/utils/win32.py +29 -0
- package/releng/meson/mesonbuild/wrap/__init__.py +59 -0
- package/releng/meson/mesonbuild/wrap/wrap.py +846 -0
- package/releng/meson/mesonbuild/wrap/wraptool.py +198 -0
- package/releng/meson-scripts/BSDmakefile +6 -0
- package/releng/meson-scripts/Makefile +16 -0
- package/releng/meson-scripts/configure +18 -0
- package/releng/meson-scripts/configure.bat +22 -0
- package/releng/meson-scripts/make.bat +23 -0
- package/releng/meson_configure.py +506 -0
- package/releng/meson_make.py +131 -0
- package/releng/mkdevkit.py +107 -0
- package/releng/mkfatmacho.py +54 -0
- package/releng/post-process-oabi.py +97 -0
- package/releng/progress.py +14 -0
- package/releng/sync-from-upstream.py +185 -0
- package/releng/tomlkit/tomlkit/__init__.py +59 -0
- package/releng/tomlkit/tomlkit/_compat.py +22 -0
- package/releng/tomlkit/tomlkit/_types.py +83 -0
- package/releng/tomlkit/tomlkit/_utils.py +158 -0
- package/releng/tomlkit/tomlkit/api.py +308 -0
- package/releng/tomlkit/tomlkit/container.py +875 -0
- package/releng/tomlkit/tomlkit/exceptions.py +227 -0
- package/releng/tomlkit/tomlkit/items.py +1967 -0
- package/releng/tomlkit/tomlkit/parser.py +1141 -0
- package/releng/tomlkit/tomlkit/py.typed +0 -0
- package/releng/tomlkit/tomlkit/source.py +180 -0
- package/releng/tomlkit/tomlkit/toml_char.py +52 -0
- package/releng/tomlkit/tomlkit/toml_document.py +7 -0
- package/releng/tomlkit/tomlkit/toml_file.py +58 -0
- package/releng/winenv.py +140 -0
- package/scripts/adjust-version.py +19 -0
- package/scripts/detect-version.py +40 -0
- package/scripts/fetch-abi-bits.py +343 -0
- package/scripts/install.js +23 -0
- package/scripts/package.py +15 -0
- package/src/addon.cc +76 -0
- package/src/application.cc +148 -0
- package/src/application.h +31 -0
- package/src/authentication.cc +174 -0
- package/src/authentication.h +24 -0
- package/src/bus.cc +167 -0
- package/src/bus.h +33 -0
- package/src/cancellable.cc +117 -0
- package/src/cancellable.h +31 -0
- package/src/child.cc +150 -0
- package/src/child.h +32 -0
- package/src/crash.cc +122 -0
- package/src/crash.h +30 -0
- package/src/device.cc +1302 -0
- package/src/device.h +55 -0
- package/src/device_manager.cc +362 -0
- package/src/device_manager.h +35 -0
- package/src/endpoint_parameters.cc +171 -0
- package/src/endpoint_parameters.h +28 -0
- package/src/glib_context.cc +62 -0
- package/src/glib_context.h +29 -0
- package/src/glib_object.cc +25 -0
- package/src/glib_object.h +37 -0
- package/src/iostream.cc +247 -0
- package/src/iostream.h +30 -0
- package/src/meson.build +26 -0
- package/src/operation.h +94 -0
- package/src/portal_membership.cc +100 -0
- package/src/portal_membership.h +26 -0
- package/src/portal_service.cc +401 -0
- package/src/portal_service.h +40 -0
- package/src/process.cc +135 -0
- package/src/process.h +30 -0
- package/src/relay.cc +139 -0
- package/src/relay.h +31 -0
- package/src/runtime.cc +443 -0
- package/src/runtime.h +64 -0
- package/src/script.cc +301 -0
- package/src/script.h +36 -0
- package/src/session.cc +860 -0
- package/src/session.h +42 -0
- package/src/signals.cc +334 -0
- package/src/signals.h +47 -0
- package/src/spawn.cc +95 -0
- package/src/spawn.h +27 -0
- package/src/usage_monitor.h +117 -0
- package/src/uv_context.cc +118 -0
- package/src/uv_context.h +40 -0
- package/src/win_delay_load_hook.cc +63 -0
- package/subprojects/frida-core.wrap +8 -0
- package/subprojects/nan.wrap +9 -0
- package/subprojects/packagefiles/nan.patch +13 -0
- package/test/data/index.ts +13 -0
- package/test/data/unixvictim-linux-x86 +0 -0
- package/test/data/unixvictim-linux-x86_64 +0 -0
- package/test/data/unixvictim-macos +0 -0
- package/test/device.ts +27 -0
- package/test/device_manager.ts +16 -0
- package/test/labrat.ts +32 -0
- package/test/script.ts +176 -0
- package/test/session.ts +73 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,1075 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2016 The Meson development team
|
|
3
|
+
|
|
4
|
+
# This tool is used to manipulate an existing Meson build definition.
|
|
5
|
+
#
|
|
6
|
+
# - add a file to a target
|
|
7
|
+
# - remove files from a target
|
|
8
|
+
# - move targets
|
|
9
|
+
# - reindent?
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstPrinter
|
|
13
|
+
from mesonbuild.mesonlib import MesonException, setup_vsenv
|
|
14
|
+
from . import mlog, environment
|
|
15
|
+
from functools import wraps
|
|
16
|
+
from .mparser import Token, ArrayNode, ArgumentNode, AssignmentNode, BaseStringNode, BooleanNode, ElementaryNode, IdNode, FunctionNode, StringNode, SymbolNode
|
|
17
|
+
import json, os, re, sys
|
|
18
|
+
import typing as T
|
|
19
|
+
|
|
20
|
+
if T.TYPE_CHECKING:
|
|
21
|
+
from argparse import ArgumentParser, HelpFormatter
|
|
22
|
+
from .mparser import BaseNode
|
|
23
|
+
|
|
24
|
+
class RewriterException(MesonException):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
# Note: when adding arguments, please also add them to the completion
|
|
28
|
+
# scripts in $MESONSRC/data/shell-completions/
|
|
29
|
+
def add_arguments(parser: ArgumentParser, formatter: T.Callable[[str], HelpFormatter]) -> None:
|
|
30
|
+
parser.add_argument('-s', '--sourcedir', type=str, default='.', metavar='SRCDIR', help='Path to source directory.')
|
|
31
|
+
parser.add_argument('-V', '--verbose', action='store_true', default=False, help='Enable verbose output')
|
|
32
|
+
parser.add_argument('-S', '--skip-errors', dest='skip', action='store_true', default=False, help='Skip errors instead of aborting')
|
|
33
|
+
subparsers = parser.add_subparsers(dest='type', title='Rewriter commands', description='Rewrite command to execute')
|
|
34
|
+
|
|
35
|
+
# Target
|
|
36
|
+
tgt_parser = subparsers.add_parser('target', aliases=['tgt'], help='Modify a target', formatter_class=formatter)
|
|
37
|
+
tgt_parser.add_argument('-s', '--subdir', default='', dest='subdir', help='Subdirectory of the new target (only for the "add_target" action)')
|
|
38
|
+
tgt_parser.add_argument('--type', dest='tgt_type', choices=rewriter_keys['target']['target_type'][2], default='executable',
|
|
39
|
+
help='Type of the target to add (only for the "add_target" action)')
|
|
40
|
+
tgt_parser.add_argument('target', help='Name or ID of the target')
|
|
41
|
+
tgt_parser.add_argument('operation', choices=['add', 'rm', 'add_target', 'rm_target', 'add_extra_files', 'rm_extra_files', 'info'],
|
|
42
|
+
help='Action to execute')
|
|
43
|
+
tgt_parser.add_argument('sources', nargs='*', help='Sources to add/remove')
|
|
44
|
+
|
|
45
|
+
# KWARGS
|
|
46
|
+
kw_parser = subparsers.add_parser('kwargs', help='Modify keyword arguments', formatter_class=formatter)
|
|
47
|
+
kw_parser.add_argument('operation', choices=rewriter_keys['kwargs']['operation'][2],
|
|
48
|
+
help='Action to execute')
|
|
49
|
+
kw_parser.add_argument('function', choices=list(rewriter_func_kwargs.keys()),
|
|
50
|
+
help='Function type to modify')
|
|
51
|
+
kw_parser.add_argument('id', help='ID of the function to modify (can be anything for "project")')
|
|
52
|
+
kw_parser.add_argument('kwargs', nargs='*', help='Pairs of keyword and value')
|
|
53
|
+
|
|
54
|
+
# Default options
|
|
55
|
+
def_parser = subparsers.add_parser('default-options', aliases=['def'], help='Modify the project default options', formatter_class=formatter)
|
|
56
|
+
def_parser.add_argument('operation', choices=rewriter_keys['default_options']['operation'][2],
|
|
57
|
+
help='Action to execute')
|
|
58
|
+
def_parser.add_argument('options', nargs='*', help='Key, value pairs of configuration option')
|
|
59
|
+
|
|
60
|
+
# JSON file/command
|
|
61
|
+
cmd_parser = subparsers.add_parser('command', aliases=['cmd'], help='Execute a JSON array of commands', formatter_class=formatter)
|
|
62
|
+
cmd_parser.add_argument('json', help='JSON string or file to execute')
|
|
63
|
+
|
|
64
|
+
class RequiredKeys:
|
|
65
|
+
def __init__(self, keys):
|
|
66
|
+
self.keys = keys
|
|
67
|
+
|
|
68
|
+
def __call__(self, f):
|
|
69
|
+
@wraps(f)
|
|
70
|
+
def wrapped(*wrapped_args, **wrapped_kwargs):
|
|
71
|
+
assert len(wrapped_args) >= 2
|
|
72
|
+
cmd = wrapped_args[1]
|
|
73
|
+
for key, val in self.keys.items():
|
|
74
|
+
typ = val[0] # The type of the value
|
|
75
|
+
default = val[1] # The default value -- None is required
|
|
76
|
+
choices = val[2] # Valid choices -- None is for everything
|
|
77
|
+
if key not in cmd:
|
|
78
|
+
if default is not None:
|
|
79
|
+
cmd[key] = default
|
|
80
|
+
else:
|
|
81
|
+
raise RewriterException('Key "{}" is missing in object for {}'
|
|
82
|
+
.format(key, f.__name__))
|
|
83
|
+
if not isinstance(cmd[key], typ):
|
|
84
|
+
raise RewriterException('Invalid type of "{}". Required is {} but provided was {}'
|
|
85
|
+
.format(key, typ.__name__, type(cmd[key]).__name__))
|
|
86
|
+
if choices is not None:
|
|
87
|
+
assert isinstance(choices, list)
|
|
88
|
+
if cmd[key] not in choices:
|
|
89
|
+
raise RewriterException('Invalid value of "{}": Possible values are {} but provided was "{}"'
|
|
90
|
+
.format(key, choices, cmd[key]))
|
|
91
|
+
return f(*wrapped_args, **wrapped_kwargs)
|
|
92
|
+
|
|
93
|
+
return wrapped
|
|
94
|
+
|
|
95
|
+
def _symbol(val: str) -> SymbolNode:
|
|
96
|
+
return SymbolNode(Token('', '', 0, 0, 0, (0, 0), val))
|
|
97
|
+
|
|
98
|
+
class MTypeBase:
|
|
99
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
100
|
+
if node is None:
|
|
101
|
+
self.node = self.new_node()
|
|
102
|
+
else:
|
|
103
|
+
self.node = node
|
|
104
|
+
self.node_type = None
|
|
105
|
+
for i in self.supported_nodes():
|
|
106
|
+
if isinstance(self.node, i):
|
|
107
|
+
self.node_type = i
|
|
108
|
+
|
|
109
|
+
@classmethod
|
|
110
|
+
def new_node(cls, value=None):
|
|
111
|
+
# Overwrite in derived class
|
|
112
|
+
raise RewriterException('Internal error: new_node of MTypeBase was called')
|
|
113
|
+
|
|
114
|
+
@classmethod
|
|
115
|
+
def supported_nodes(cls):
|
|
116
|
+
# Overwrite in derived class
|
|
117
|
+
return []
|
|
118
|
+
|
|
119
|
+
def can_modify(self):
|
|
120
|
+
return self.node_type is not None
|
|
121
|
+
|
|
122
|
+
def get_node(self):
|
|
123
|
+
return self.node
|
|
124
|
+
|
|
125
|
+
def add_value(self, value):
|
|
126
|
+
# Overwrite in derived class
|
|
127
|
+
mlog.warning('Cannot add a value of type', mlog.bold(type(self).__name__), '--> skipping')
|
|
128
|
+
|
|
129
|
+
def remove_value(self, value):
|
|
130
|
+
# Overwrite in derived class
|
|
131
|
+
mlog.warning('Cannot remove a value of type', mlog.bold(type(self).__name__), '--> skipping')
|
|
132
|
+
|
|
133
|
+
def remove_regex(self, value):
|
|
134
|
+
# Overwrite in derived class
|
|
135
|
+
mlog.warning('Cannot remove a regex in type', mlog.bold(type(self).__name__), '--> skipping')
|
|
136
|
+
|
|
137
|
+
class MTypeStr(MTypeBase):
|
|
138
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
139
|
+
super().__init__(node)
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def new_node(cls, value=None):
|
|
143
|
+
if value is None:
|
|
144
|
+
value = ''
|
|
145
|
+
return StringNode(Token('', '', 0, 0, 0, None, str(value)))
|
|
146
|
+
|
|
147
|
+
@classmethod
|
|
148
|
+
def supported_nodes(cls):
|
|
149
|
+
return [StringNode]
|
|
150
|
+
|
|
151
|
+
class MTypeBool(MTypeBase):
|
|
152
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
153
|
+
super().__init__(node)
|
|
154
|
+
|
|
155
|
+
@classmethod
|
|
156
|
+
def new_node(cls, value=None):
|
|
157
|
+
return BooleanNode(Token('', '', 0, 0, 0, None, bool(value)))
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def supported_nodes(cls):
|
|
161
|
+
return [BooleanNode]
|
|
162
|
+
|
|
163
|
+
class MTypeID(MTypeBase):
|
|
164
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
165
|
+
super().__init__(node)
|
|
166
|
+
|
|
167
|
+
@classmethod
|
|
168
|
+
def new_node(cls, value=None):
|
|
169
|
+
if value is None:
|
|
170
|
+
value = ''
|
|
171
|
+
return IdNode(Token('', '', 0, 0, 0, None, str(value)))
|
|
172
|
+
|
|
173
|
+
@classmethod
|
|
174
|
+
def supported_nodes(cls):
|
|
175
|
+
return [IdNode]
|
|
176
|
+
|
|
177
|
+
class MTypeList(MTypeBase):
|
|
178
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
179
|
+
super().__init__(node)
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def new_node(cls, value=None):
|
|
183
|
+
if value is None:
|
|
184
|
+
value = []
|
|
185
|
+
elif not isinstance(value, list):
|
|
186
|
+
return cls._new_element_node(value)
|
|
187
|
+
args = ArgumentNode(Token('', '', 0, 0, 0, None, ''))
|
|
188
|
+
args.arguments = [cls._new_element_node(i) for i in value]
|
|
189
|
+
return ArrayNode(_symbol('['), args, _symbol(']'))
|
|
190
|
+
|
|
191
|
+
@classmethod
|
|
192
|
+
def _new_element_node(cls, value):
|
|
193
|
+
# Overwrite in derived class
|
|
194
|
+
raise RewriterException('Internal error: _new_element_node of MTypeList was called')
|
|
195
|
+
|
|
196
|
+
def _ensure_array_node(self):
|
|
197
|
+
if not isinstance(self.node, ArrayNode):
|
|
198
|
+
tmp = self.node
|
|
199
|
+
self.node = self.new_node()
|
|
200
|
+
self.node.args.arguments = [tmp]
|
|
201
|
+
|
|
202
|
+
@staticmethod
|
|
203
|
+
def _check_is_equal(node, value) -> bool:
|
|
204
|
+
# Overwrite in derived class
|
|
205
|
+
return False
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def _check_regex_matches(node, regex: str) -> bool:
|
|
209
|
+
# Overwrite in derived class
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
def get_node(self):
|
|
213
|
+
if isinstance(self.node, ArrayNode):
|
|
214
|
+
if len(self.node.args.arguments) == 1:
|
|
215
|
+
return self.node.args.arguments[0]
|
|
216
|
+
return self.node
|
|
217
|
+
|
|
218
|
+
@classmethod
|
|
219
|
+
def supported_element_nodes(cls):
|
|
220
|
+
# Overwrite in derived class
|
|
221
|
+
return []
|
|
222
|
+
|
|
223
|
+
@classmethod
|
|
224
|
+
def supported_nodes(cls):
|
|
225
|
+
return [ArrayNode] + cls.supported_element_nodes()
|
|
226
|
+
|
|
227
|
+
def add_value(self, value):
|
|
228
|
+
if not isinstance(value, list):
|
|
229
|
+
value = [value]
|
|
230
|
+
self._ensure_array_node()
|
|
231
|
+
for i in value:
|
|
232
|
+
self.node.args.arguments += [self._new_element_node(i)]
|
|
233
|
+
|
|
234
|
+
def _remove_helper(self, value, equal_func):
|
|
235
|
+
def check_remove_node(node):
|
|
236
|
+
for j in value:
|
|
237
|
+
if equal_func(i, j):
|
|
238
|
+
return True
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
if not isinstance(value, list):
|
|
242
|
+
value = [value]
|
|
243
|
+
self._ensure_array_node()
|
|
244
|
+
removed_list = []
|
|
245
|
+
for i in self.node.args.arguments:
|
|
246
|
+
if not check_remove_node(i):
|
|
247
|
+
removed_list += [i]
|
|
248
|
+
self.node.args.arguments = removed_list
|
|
249
|
+
|
|
250
|
+
def remove_value(self, value):
|
|
251
|
+
self._remove_helper(value, self._check_is_equal)
|
|
252
|
+
|
|
253
|
+
def remove_regex(self, regex: str):
|
|
254
|
+
self._remove_helper(regex, self._check_regex_matches)
|
|
255
|
+
|
|
256
|
+
class MTypeStrList(MTypeList):
|
|
257
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
258
|
+
super().__init__(node)
|
|
259
|
+
|
|
260
|
+
@classmethod
|
|
261
|
+
def _new_element_node(cls, value):
|
|
262
|
+
return StringNode(Token('', '', 0, 0, 0, None, str(value)))
|
|
263
|
+
|
|
264
|
+
@staticmethod
|
|
265
|
+
def _check_is_equal(node, value) -> bool:
|
|
266
|
+
if isinstance(node, BaseStringNode):
|
|
267
|
+
return node.value == value
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
@staticmethod
|
|
271
|
+
def _check_regex_matches(node, regex: str) -> bool:
|
|
272
|
+
if isinstance(node, BaseStringNode):
|
|
273
|
+
return re.match(regex, node.value) is not None
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
@classmethod
|
|
277
|
+
def supported_element_nodes(cls):
|
|
278
|
+
return [StringNode]
|
|
279
|
+
|
|
280
|
+
class MTypeIDList(MTypeList):
|
|
281
|
+
def __init__(self, node: T.Optional[BaseNode] = None):
|
|
282
|
+
super().__init__(node)
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def _new_element_node(cls, value):
|
|
286
|
+
return IdNode(Token('', '', 0, 0, 0, None, str(value)))
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
def _check_is_equal(node, value) -> bool:
|
|
290
|
+
if isinstance(node, IdNode):
|
|
291
|
+
return node.value == value
|
|
292
|
+
return False
|
|
293
|
+
|
|
294
|
+
@staticmethod
|
|
295
|
+
def _check_regex_matches(node, regex: str) -> bool:
|
|
296
|
+
if isinstance(node, BaseStringNode):
|
|
297
|
+
return re.match(regex, node.value) is not None
|
|
298
|
+
return False
|
|
299
|
+
|
|
300
|
+
@classmethod
|
|
301
|
+
def supported_element_nodes(cls):
|
|
302
|
+
return [IdNode]
|
|
303
|
+
|
|
304
|
+
rewriter_keys = {
|
|
305
|
+
'default_options': {
|
|
306
|
+
'operation': (str, None, ['set', 'delete']),
|
|
307
|
+
'options': (dict, {}, None)
|
|
308
|
+
},
|
|
309
|
+
'kwargs': {
|
|
310
|
+
'function': (str, None, None),
|
|
311
|
+
'id': (str, None, None),
|
|
312
|
+
'operation': (str, None, ['set', 'delete', 'add', 'remove', 'remove_regex', 'info']),
|
|
313
|
+
'kwargs': (dict, {}, None)
|
|
314
|
+
},
|
|
315
|
+
'target': {
|
|
316
|
+
'target': (str, None, None),
|
|
317
|
+
'operation': (str, None, ['src_add', 'src_rm', 'target_rm', 'target_add', 'extra_files_add', 'extra_files_rm', 'info']),
|
|
318
|
+
'sources': (list, [], None),
|
|
319
|
+
'subdir': (str, '', None),
|
|
320
|
+
'target_type': (str, 'executable', ['both_libraries', 'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library']),
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
rewriter_func_kwargs = {
|
|
325
|
+
'dependency': {
|
|
326
|
+
'language': MTypeStr,
|
|
327
|
+
'method': MTypeStr,
|
|
328
|
+
'native': MTypeBool,
|
|
329
|
+
'not_found_message': MTypeStr,
|
|
330
|
+
'required': MTypeBool,
|
|
331
|
+
'static': MTypeBool,
|
|
332
|
+
'version': MTypeStrList,
|
|
333
|
+
'modules': MTypeStrList
|
|
334
|
+
},
|
|
335
|
+
'target': {
|
|
336
|
+
'build_by_default': MTypeBool,
|
|
337
|
+
'build_rpath': MTypeStr,
|
|
338
|
+
'dependencies': MTypeIDList,
|
|
339
|
+
'gui_app': MTypeBool,
|
|
340
|
+
'link_with': MTypeIDList,
|
|
341
|
+
'export_dynamic': MTypeBool,
|
|
342
|
+
'implib': MTypeBool,
|
|
343
|
+
'install': MTypeBool,
|
|
344
|
+
'install_dir': MTypeStr,
|
|
345
|
+
'install_rpath': MTypeStr,
|
|
346
|
+
'pie': MTypeBool
|
|
347
|
+
},
|
|
348
|
+
'project': {
|
|
349
|
+
'default_options': MTypeStrList,
|
|
350
|
+
'meson_version': MTypeStr,
|
|
351
|
+
'license': MTypeStrList,
|
|
352
|
+
'subproject_dir': MTypeStr,
|
|
353
|
+
'version': MTypeStr
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
class Rewriter:
|
|
358
|
+
def __init__(self, sourcedir: str, generator: str = 'ninja', skip_errors: bool = False):
|
|
359
|
+
self.sourcedir = sourcedir
|
|
360
|
+
self.interpreter = IntrospectionInterpreter(sourcedir, '', generator, visitors = [AstIDGenerator(), AstIndentationGenerator(), AstConditionLevel()])
|
|
361
|
+
self.skip_errors = skip_errors
|
|
362
|
+
self.modified_nodes = []
|
|
363
|
+
self.to_remove_nodes = []
|
|
364
|
+
self.to_add_nodes = []
|
|
365
|
+
self.functions = {
|
|
366
|
+
'default_options': self.process_default_options,
|
|
367
|
+
'kwargs': self.process_kwargs,
|
|
368
|
+
'target': self.process_target,
|
|
369
|
+
}
|
|
370
|
+
self.info_dump = None
|
|
371
|
+
|
|
372
|
+
def analyze_meson(self):
|
|
373
|
+
mlog.log('Analyzing meson file:', mlog.bold(os.path.join(self.sourcedir, environment.build_filename)))
|
|
374
|
+
self.interpreter.analyze()
|
|
375
|
+
mlog.log(' -- Project:', mlog.bold(self.interpreter.project_data['descriptive_name']))
|
|
376
|
+
mlog.log(' -- Version:', mlog.cyan(self.interpreter.project_data['version']))
|
|
377
|
+
|
|
378
|
+
def add_info(self, cmd_type: str, cmd_id: str, data: dict):
|
|
379
|
+
if self.info_dump is None:
|
|
380
|
+
self.info_dump = {}
|
|
381
|
+
if cmd_type not in self.info_dump:
|
|
382
|
+
self.info_dump[cmd_type] = {}
|
|
383
|
+
self.info_dump[cmd_type][cmd_id] = data
|
|
384
|
+
|
|
385
|
+
def print_info(self):
|
|
386
|
+
if self.info_dump is None:
|
|
387
|
+
return
|
|
388
|
+
sys.stderr.write(json.dumps(self.info_dump, indent=2))
|
|
389
|
+
|
|
390
|
+
def on_error(self):
|
|
391
|
+
if self.skip_errors:
|
|
392
|
+
return mlog.cyan('-->'), mlog.yellow('skipping')
|
|
393
|
+
return mlog.cyan('-->'), mlog.red('aborting')
|
|
394
|
+
|
|
395
|
+
def handle_error(self):
|
|
396
|
+
if self.skip_errors:
|
|
397
|
+
return None
|
|
398
|
+
raise MesonException('Rewriting the meson.build failed')
|
|
399
|
+
|
|
400
|
+
def find_target(self, target: str):
|
|
401
|
+
def check_list(name: str) -> T.List[BaseNode]:
|
|
402
|
+
result = []
|
|
403
|
+
for i in self.interpreter.targets:
|
|
404
|
+
if name in {i['name'], i['id']}:
|
|
405
|
+
result += [i]
|
|
406
|
+
return result
|
|
407
|
+
|
|
408
|
+
targets = check_list(target)
|
|
409
|
+
if targets:
|
|
410
|
+
if len(targets) == 1:
|
|
411
|
+
return targets[0]
|
|
412
|
+
else:
|
|
413
|
+
mlog.error('There are multiple targets matching', mlog.bold(target))
|
|
414
|
+
for i in targets:
|
|
415
|
+
mlog.error(' -- Target name', mlog.bold(i['name']), 'with ID', mlog.bold(i['id']))
|
|
416
|
+
mlog.error('Please try again with the unique ID of the target', *self.on_error())
|
|
417
|
+
self.handle_error()
|
|
418
|
+
return None
|
|
419
|
+
|
|
420
|
+
# Check the assignments
|
|
421
|
+
tgt = None
|
|
422
|
+
if target in self.interpreter.assignments:
|
|
423
|
+
node = self.interpreter.assignments[target]
|
|
424
|
+
if isinstance(node, FunctionNode):
|
|
425
|
+
if node.func_name.value in {'executable', 'jar', 'library', 'shared_library', 'shared_module', 'static_library', 'both_libraries'}:
|
|
426
|
+
tgt = self.interpreter.assign_vals[target]
|
|
427
|
+
|
|
428
|
+
return tgt
|
|
429
|
+
|
|
430
|
+
def find_dependency(self, dependency: str):
|
|
431
|
+
def check_list(name: str):
|
|
432
|
+
for i in self.interpreter.dependencies:
|
|
433
|
+
if name == i['name']:
|
|
434
|
+
return i
|
|
435
|
+
return None
|
|
436
|
+
|
|
437
|
+
dep = check_list(dependency)
|
|
438
|
+
if dep is not None:
|
|
439
|
+
return dep
|
|
440
|
+
|
|
441
|
+
# Check the assignments
|
|
442
|
+
if dependency in self.interpreter.assignments:
|
|
443
|
+
node = self.interpreter.assignments[dependency]
|
|
444
|
+
if isinstance(node, FunctionNode):
|
|
445
|
+
if node.func_name.value == 'dependency':
|
|
446
|
+
name = self.interpreter.flatten_args(node.args)[0]
|
|
447
|
+
dep = check_list(name)
|
|
448
|
+
|
|
449
|
+
return dep
|
|
450
|
+
|
|
451
|
+
@RequiredKeys(rewriter_keys['default_options'])
|
|
452
|
+
def process_default_options(self, cmd):
|
|
453
|
+
# First, remove the old values
|
|
454
|
+
kwargs_cmd = {
|
|
455
|
+
'function': 'project',
|
|
456
|
+
'id': "/",
|
|
457
|
+
'operation': 'remove_regex',
|
|
458
|
+
'kwargs': {
|
|
459
|
+
'default_options': [f'{x}=.*' for x in cmd['options'].keys()]
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
self.process_kwargs(kwargs_cmd)
|
|
463
|
+
|
|
464
|
+
# Then add the new values
|
|
465
|
+
if cmd['operation'] != 'set':
|
|
466
|
+
return
|
|
467
|
+
|
|
468
|
+
kwargs_cmd['operation'] = 'add'
|
|
469
|
+
kwargs_cmd['kwargs']['default_options'] = []
|
|
470
|
+
|
|
471
|
+
cdata = self.interpreter.coredata
|
|
472
|
+
options = {
|
|
473
|
+
**{str(k): v for k, v in cdata.options.items()},
|
|
474
|
+
**{str(k): v for k, v in cdata.options.items()},
|
|
475
|
+
**{str(k): v for k, v in cdata.options.items()},
|
|
476
|
+
**{str(k): v for k, v in cdata.options.items()},
|
|
477
|
+
**{str(k): v for k, v in cdata.options.items()},
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
for key, val in sorted(cmd['options'].items()):
|
|
481
|
+
if key not in options:
|
|
482
|
+
mlog.error('Unknown options', mlog.bold(key), *self.on_error())
|
|
483
|
+
self.handle_error()
|
|
484
|
+
continue
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
val = options[key].validate_value(val)
|
|
488
|
+
except MesonException as e:
|
|
489
|
+
mlog.error('Unable to set', mlog.bold(key), mlog.red(str(e)), *self.on_error())
|
|
490
|
+
self.handle_error()
|
|
491
|
+
continue
|
|
492
|
+
|
|
493
|
+
kwargs_cmd['kwargs']['default_options'] += [f'{key}={val}']
|
|
494
|
+
|
|
495
|
+
self.process_kwargs(kwargs_cmd)
|
|
496
|
+
|
|
497
|
+
@RequiredKeys(rewriter_keys['kwargs'])
|
|
498
|
+
def process_kwargs(self, cmd):
|
|
499
|
+
mlog.log('Processing function type', mlog.bold(cmd['function']), 'with id', mlog.cyan("'" + cmd['id'] + "'"))
|
|
500
|
+
if cmd['function'] not in rewriter_func_kwargs:
|
|
501
|
+
mlog.error('Unknown function type', cmd['function'], *self.on_error())
|
|
502
|
+
return self.handle_error()
|
|
503
|
+
kwargs_def = rewriter_func_kwargs[cmd['function']]
|
|
504
|
+
|
|
505
|
+
# Find the function node to modify
|
|
506
|
+
node = None
|
|
507
|
+
arg_node = None
|
|
508
|
+
if cmd['function'] == 'project':
|
|
509
|
+
# msys bash may expand '/' to a path. It will mangle '//' to '/'
|
|
510
|
+
# but in order to keep usage shell-agnostic, also allow `//` as
|
|
511
|
+
# the function ID such that it will work in both msys bash and
|
|
512
|
+
# other shells.
|
|
513
|
+
if {'/', '//'}.isdisjoint({cmd['id']}):
|
|
514
|
+
mlog.error('The ID for the function type project must be "/" or "//" not "' + cmd['id'] + '"', *self.on_error())
|
|
515
|
+
return self.handle_error()
|
|
516
|
+
node = self.interpreter.project_node
|
|
517
|
+
arg_node = node.args
|
|
518
|
+
elif cmd['function'] == 'target':
|
|
519
|
+
tmp = self.find_target(cmd['id'])
|
|
520
|
+
if tmp:
|
|
521
|
+
node = tmp['node']
|
|
522
|
+
arg_node = node.args
|
|
523
|
+
elif cmd['function'] == 'dependency':
|
|
524
|
+
tmp = self.find_dependency(cmd['id'])
|
|
525
|
+
if tmp:
|
|
526
|
+
node = tmp['node']
|
|
527
|
+
arg_node = node.args
|
|
528
|
+
if not node:
|
|
529
|
+
mlog.error('Unable to find the function node')
|
|
530
|
+
assert isinstance(node, FunctionNode)
|
|
531
|
+
assert isinstance(arg_node, ArgumentNode)
|
|
532
|
+
# Transform the key nodes to plain strings
|
|
533
|
+
arg_node.kwargs = {k.value: v for k, v in arg_node.kwargs.items()}
|
|
534
|
+
|
|
535
|
+
# Print kwargs info
|
|
536
|
+
if cmd['operation'] == 'info':
|
|
537
|
+
info_data = {}
|
|
538
|
+
for key, val in sorted(arg_node.kwargs.items()):
|
|
539
|
+
info_data[key] = None
|
|
540
|
+
if isinstance(val, ElementaryNode):
|
|
541
|
+
info_data[key] = val.value
|
|
542
|
+
elif isinstance(val, ArrayNode):
|
|
543
|
+
data_list = []
|
|
544
|
+
for i in val.args.arguments:
|
|
545
|
+
element = None
|
|
546
|
+
if isinstance(i, ElementaryNode):
|
|
547
|
+
element = i.value
|
|
548
|
+
data_list += [element]
|
|
549
|
+
info_data[key] = data_list
|
|
550
|
+
|
|
551
|
+
self.add_info('kwargs', '{}#{}'.format(cmd['function'], cmd['id']), info_data)
|
|
552
|
+
return # Nothing else to do
|
|
553
|
+
|
|
554
|
+
# Modify the kwargs
|
|
555
|
+
num_changed = 0
|
|
556
|
+
for key, val in sorted(cmd['kwargs'].items()):
|
|
557
|
+
if key not in kwargs_def:
|
|
558
|
+
mlog.error('Cannot modify unknown kwarg', mlog.bold(key), *self.on_error())
|
|
559
|
+
self.handle_error()
|
|
560
|
+
continue
|
|
561
|
+
|
|
562
|
+
if cmd['operation'] == 'delete':
|
|
563
|
+
# Remove the key from the kwargs
|
|
564
|
+
if key not in arg_node.kwargs:
|
|
565
|
+
mlog.log(' -- Key', mlog.bold(key), 'is already deleted')
|
|
566
|
+
continue
|
|
567
|
+
mlog.log(' -- Deleting', mlog.bold(key), 'from the kwargs')
|
|
568
|
+
del arg_node.kwargs[key]
|
|
569
|
+
elif cmd['operation'] == 'set':
|
|
570
|
+
# Replace the key from the kwargs
|
|
571
|
+
mlog.log(' -- Setting', mlog.bold(key), 'to', mlog.yellow(str(val)))
|
|
572
|
+
arg_node.kwargs[key] = kwargs_def[key].new_node(val)
|
|
573
|
+
else:
|
|
574
|
+
# Modify the value from the kwargs
|
|
575
|
+
|
|
576
|
+
if key not in arg_node.kwargs:
|
|
577
|
+
arg_node.kwargs[key] = None
|
|
578
|
+
modifier = kwargs_def[key](arg_node.kwargs[key])
|
|
579
|
+
if not modifier.can_modify():
|
|
580
|
+
mlog.log(' -- Skipping', mlog.bold(key), 'because it is too complex to modify')
|
|
581
|
+
continue
|
|
582
|
+
|
|
583
|
+
# Apply the operation
|
|
584
|
+
val_str = str(val)
|
|
585
|
+
if cmd['operation'] == 'add':
|
|
586
|
+
mlog.log(' -- Adding', mlog.yellow(val_str), 'to', mlog.bold(key))
|
|
587
|
+
modifier.add_value(val)
|
|
588
|
+
elif cmd['operation'] == 'remove':
|
|
589
|
+
mlog.log(' -- Removing', mlog.yellow(val_str), 'from', mlog.bold(key))
|
|
590
|
+
modifier.remove_value(val)
|
|
591
|
+
elif cmd['operation'] == 'remove_regex':
|
|
592
|
+
mlog.log(' -- Removing all values matching', mlog.yellow(val_str), 'from', mlog.bold(key))
|
|
593
|
+
modifier.remove_regex(val)
|
|
594
|
+
|
|
595
|
+
# Write back the result
|
|
596
|
+
arg_node.kwargs[key] = modifier.get_node()
|
|
597
|
+
|
|
598
|
+
num_changed += 1
|
|
599
|
+
|
|
600
|
+
# Convert the keys back to IdNode's
|
|
601
|
+
arg_node.kwargs = {IdNode(Token('', '', 0, 0, 0, None, k)): v for k, v in arg_node.kwargs.items()}
|
|
602
|
+
for k, v in arg_node.kwargs.items():
|
|
603
|
+
k.level = v.level
|
|
604
|
+
if num_changed > 0 and node not in self.modified_nodes:
|
|
605
|
+
self.modified_nodes += [node]
|
|
606
|
+
|
|
607
|
+
def find_assignment_node(self, node: BaseNode) -> AssignmentNode:
|
|
608
|
+
if node.ast_id and node.ast_id in self.interpreter.reverse_assignment:
|
|
609
|
+
return self.interpreter.reverse_assignment[node.ast_id]
|
|
610
|
+
return None
|
|
611
|
+
|
|
612
|
+
@RequiredKeys(rewriter_keys['target'])
|
|
613
|
+
def process_target(self, cmd):
|
|
614
|
+
mlog.log('Processing target', mlog.bold(cmd['target']), 'operation', mlog.cyan(cmd['operation']))
|
|
615
|
+
target = self.find_target(cmd['target'])
|
|
616
|
+
if target is None and cmd['operation'] != 'target_add':
|
|
617
|
+
mlog.error('Unknown target', mlog.bold(cmd['target']), *self.on_error())
|
|
618
|
+
return self.handle_error()
|
|
619
|
+
|
|
620
|
+
# Make source paths relative to the current subdir
|
|
621
|
+
def rel_source(src: str) -> str:
|
|
622
|
+
subdir = os.path.abspath(os.path.join(self.sourcedir, target['subdir']))
|
|
623
|
+
if os.path.isabs(src):
|
|
624
|
+
return os.path.relpath(src, subdir)
|
|
625
|
+
elif not os.path.exists(src):
|
|
626
|
+
return src # Trust the user when the source doesn't exist
|
|
627
|
+
# Make sure that the path is relative to the subdir
|
|
628
|
+
return os.path.relpath(os.path.abspath(src), subdir)
|
|
629
|
+
|
|
630
|
+
if target is not None:
|
|
631
|
+
cmd['sources'] = [rel_source(x) for x in cmd['sources']]
|
|
632
|
+
|
|
633
|
+
# Utility function to get a list of the sources from a node
|
|
634
|
+
def arg_list_from_node(n):
|
|
635
|
+
args = []
|
|
636
|
+
if isinstance(n, FunctionNode):
|
|
637
|
+
args = list(n.args.arguments)
|
|
638
|
+
if n.func_name.value in BUILD_TARGET_FUNCTIONS:
|
|
639
|
+
args.pop(0)
|
|
640
|
+
elif isinstance(n, ArrayNode):
|
|
641
|
+
args = n.args.arguments
|
|
642
|
+
elif isinstance(n, ArgumentNode):
|
|
643
|
+
args = n.arguments
|
|
644
|
+
return args
|
|
645
|
+
|
|
646
|
+
to_sort_nodes = []
|
|
647
|
+
|
|
648
|
+
if cmd['operation'] == 'src_add':
|
|
649
|
+
node = None
|
|
650
|
+
if target['sources']:
|
|
651
|
+
node = target['sources'][0]
|
|
652
|
+
else:
|
|
653
|
+
node = target['node']
|
|
654
|
+
assert node is not None
|
|
655
|
+
|
|
656
|
+
# Generate the current source list
|
|
657
|
+
src_list = []
|
|
658
|
+
for i in target['sources']:
|
|
659
|
+
for j in arg_list_from_node(i):
|
|
660
|
+
if isinstance(j, BaseStringNode):
|
|
661
|
+
src_list += [j.value]
|
|
662
|
+
|
|
663
|
+
# Generate the new String nodes
|
|
664
|
+
to_append = []
|
|
665
|
+
for i in sorted(set(cmd['sources'])):
|
|
666
|
+
if i in src_list:
|
|
667
|
+
mlog.log(' -- Source', mlog.green(i), 'is already defined for the target --> skipping')
|
|
668
|
+
continue
|
|
669
|
+
mlog.log(' -- Adding source', mlog.green(i), 'at',
|
|
670
|
+
mlog.yellow(f'{node.filename}:{node.lineno}'))
|
|
671
|
+
token = Token('string', node.filename, 0, 0, 0, None, i)
|
|
672
|
+
to_append += [StringNode(token)]
|
|
673
|
+
|
|
674
|
+
# Append to the AST at the right place
|
|
675
|
+
arg_node = None
|
|
676
|
+
if isinstance(node, (FunctionNode, ArrayNode)):
|
|
677
|
+
arg_node = node.args
|
|
678
|
+
elif isinstance(node, ArgumentNode):
|
|
679
|
+
arg_node = node
|
|
680
|
+
assert arg_node is not None
|
|
681
|
+
arg_node.arguments += to_append
|
|
682
|
+
|
|
683
|
+
# Mark the node as modified
|
|
684
|
+
if arg_node not in to_sort_nodes and not isinstance(node, FunctionNode):
|
|
685
|
+
to_sort_nodes += [arg_node]
|
|
686
|
+
if node not in self.modified_nodes:
|
|
687
|
+
self.modified_nodes += [node]
|
|
688
|
+
|
|
689
|
+
elif cmd['operation'] == 'src_rm':
|
|
690
|
+
# Helper to find the exact string node and its parent
|
|
691
|
+
def find_node(src):
|
|
692
|
+
for i in target['sources']:
|
|
693
|
+
for j in arg_list_from_node(i):
|
|
694
|
+
if isinstance(j, BaseStringNode):
|
|
695
|
+
if j.value == src:
|
|
696
|
+
return i, j
|
|
697
|
+
return None, None
|
|
698
|
+
|
|
699
|
+
for i in cmd['sources']:
|
|
700
|
+
# Try to find the node with the source string
|
|
701
|
+
root, string_node = find_node(i)
|
|
702
|
+
if root is None:
|
|
703
|
+
mlog.warning(' -- Unable to find source', mlog.green(i), 'in the target')
|
|
704
|
+
continue
|
|
705
|
+
|
|
706
|
+
# Remove the found string node from the argument list
|
|
707
|
+
arg_node = None
|
|
708
|
+
if isinstance(root, (FunctionNode, ArrayNode)):
|
|
709
|
+
arg_node = root.args
|
|
710
|
+
elif isinstance(root, ArgumentNode):
|
|
711
|
+
arg_node = root
|
|
712
|
+
assert arg_node is not None
|
|
713
|
+
mlog.log(' -- Removing source', mlog.green(i), 'from',
|
|
714
|
+
mlog.yellow(f'{string_node.filename}:{string_node.lineno}'))
|
|
715
|
+
arg_node.arguments.remove(string_node)
|
|
716
|
+
|
|
717
|
+
# Mark the node as modified
|
|
718
|
+
if arg_node not in to_sort_nodes and not isinstance(root, FunctionNode):
|
|
719
|
+
to_sort_nodes += [arg_node]
|
|
720
|
+
if root not in self.modified_nodes:
|
|
721
|
+
self.modified_nodes += [root]
|
|
722
|
+
|
|
723
|
+
elif cmd['operation'] == 'extra_files_add':
|
|
724
|
+
tgt_function: FunctionNode = target['node']
|
|
725
|
+
mark_array = True
|
|
726
|
+
try:
|
|
727
|
+
node = target['extra_files'][0]
|
|
728
|
+
except IndexError:
|
|
729
|
+
# Specifying `extra_files` with a list that flattens to empty gives an empty
|
|
730
|
+
# target['extra_files'] list, account for that.
|
|
731
|
+
try:
|
|
732
|
+
extra_files_key = next(k for k in tgt_function.args.kwargs.keys() if isinstance(k, IdNode) and k.value == 'extra_files')
|
|
733
|
+
node = tgt_function.args.kwargs[extra_files_key]
|
|
734
|
+
except StopIteration:
|
|
735
|
+
# Target has no extra_files kwarg, create one
|
|
736
|
+
node = ArrayNode(_symbol('['), ArgumentNode(Token('', tgt_function.filename, 0, 0, 0, None, '[]')), _symbol(']'))
|
|
737
|
+
tgt_function.args.kwargs[IdNode(Token('string', tgt_function.filename, 0, 0, 0, None, 'extra_files'))] = node
|
|
738
|
+
mark_array = False
|
|
739
|
+
if tgt_function not in self.modified_nodes:
|
|
740
|
+
self.modified_nodes += [tgt_function]
|
|
741
|
+
target['extra_files'] = [node]
|
|
742
|
+
if isinstance(node, IdNode):
|
|
743
|
+
node = self.interpreter.assignments[node.value]
|
|
744
|
+
target['extra_files'] = [node]
|
|
745
|
+
if not isinstance(node, ArrayNode):
|
|
746
|
+
mlog.error('Target', mlog.bold(cmd['target']), 'extra_files argument must be a list', *self.on_error())
|
|
747
|
+
return self.handle_error()
|
|
748
|
+
|
|
749
|
+
# Generate the current extra files list
|
|
750
|
+
extra_files_list = []
|
|
751
|
+
for i in target['extra_files']:
|
|
752
|
+
for j in arg_list_from_node(i):
|
|
753
|
+
if isinstance(j, BaseStringNode):
|
|
754
|
+
extra_files_list += [j.value]
|
|
755
|
+
|
|
756
|
+
# Generate the new String nodes
|
|
757
|
+
to_append = []
|
|
758
|
+
for i in sorted(set(cmd['sources'])):
|
|
759
|
+
if i in extra_files_list:
|
|
760
|
+
mlog.log(' -- Extra file', mlog.green(i), 'is already defined for the target --> skipping')
|
|
761
|
+
continue
|
|
762
|
+
mlog.log(' -- Adding extra file', mlog.green(i), 'at',
|
|
763
|
+
mlog.yellow(f'{node.filename}:{node.lineno}'))
|
|
764
|
+
token = Token('string', node.filename, 0, 0, 0, None, i)
|
|
765
|
+
to_append += [StringNode(token)]
|
|
766
|
+
|
|
767
|
+
# Append to the AST at the right place
|
|
768
|
+
arg_node = node.args
|
|
769
|
+
arg_node.arguments += to_append
|
|
770
|
+
|
|
771
|
+
# Mark the node as modified
|
|
772
|
+
if arg_node not in to_sort_nodes:
|
|
773
|
+
to_sort_nodes += [arg_node]
|
|
774
|
+
# If the extra_files array is newly created, don't mark it as its parent function node already is,
|
|
775
|
+
# otherwise this would cause double modification.
|
|
776
|
+
if mark_array and node not in self.modified_nodes:
|
|
777
|
+
self.modified_nodes += [node]
|
|
778
|
+
|
|
779
|
+
elif cmd['operation'] == 'extra_files_rm':
|
|
780
|
+
# Helper to find the exact string node and its parent
|
|
781
|
+
def find_node(src):
|
|
782
|
+
for i in target['extra_files']:
|
|
783
|
+
for j in arg_list_from_node(i):
|
|
784
|
+
if isinstance(j, BaseStringNode):
|
|
785
|
+
if j.value == src:
|
|
786
|
+
return i, j
|
|
787
|
+
return None, None
|
|
788
|
+
|
|
789
|
+
for i in cmd['sources']:
|
|
790
|
+
# Try to find the node with the source string
|
|
791
|
+
root, string_node = find_node(i)
|
|
792
|
+
if root is None:
|
|
793
|
+
mlog.warning(' -- Unable to find extra file', mlog.green(i), 'in the target')
|
|
794
|
+
continue
|
|
795
|
+
|
|
796
|
+
# Remove the found string node from the argument list
|
|
797
|
+
arg_node = root.args
|
|
798
|
+
mlog.log(' -- Removing extra file', mlog.green(i), 'from',
|
|
799
|
+
mlog.yellow(f'{string_node.filename}:{string_node.lineno}'))
|
|
800
|
+
arg_node.arguments.remove(string_node)
|
|
801
|
+
|
|
802
|
+
# Mark the node as modified
|
|
803
|
+
if arg_node not in to_sort_nodes and not isinstance(root, FunctionNode):
|
|
804
|
+
to_sort_nodes += [arg_node]
|
|
805
|
+
if root not in self.modified_nodes:
|
|
806
|
+
self.modified_nodes += [root]
|
|
807
|
+
|
|
808
|
+
elif cmd['operation'] == 'target_add':
|
|
809
|
+
if target is not None:
|
|
810
|
+
mlog.error('Can not add target', mlog.bold(cmd['target']), 'because it already exists', *self.on_error())
|
|
811
|
+
return self.handle_error()
|
|
812
|
+
|
|
813
|
+
id_base = re.sub(r'[- ]', '_', cmd['target'])
|
|
814
|
+
target_id = id_base + '_exe' if cmd['target_type'] == 'executable' else '_lib'
|
|
815
|
+
source_id = id_base + '_sources'
|
|
816
|
+
filename = os.path.join(cmd['subdir'], environment.build_filename)
|
|
817
|
+
|
|
818
|
+
# Build src list
|
|
819
|
+
src_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
|
|
820
|
+
src_arr_node = ArrayNode(_symbol('['), src_arg_node, _symbol(']'))
|
|
821
|
+
src_far_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
|
|
822
|
+
src_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), 'files')), _symbol('('), src_far_node, _symbol(')'))
|
|
823
|
+
src_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), source_id)), _symbol('='), src_fun_node)
|
|
824
|
+
src_arg_node.arguments = [StringNode(Token('string', filename, 0, 0, 0, None, x)) for x in cmd['sources']]
|
|
825
|
+
src_far_node.arguments = [src_arr_node]
|
|
826
|
+
|
|
827
|
+
# Build target
|
|
828
|
+
tgt_arg_node = ArgumentNode(Token('string', filename, 0, 0, 0, None, ''))
|
|
829
|
+
tgt_fun_node = FunctionNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), cmd['target_type'])), _symbol('('), tgt_arg_node, _symbol(')'))
|
|
830
|
+
tgt_ass_node = AssignmentNode(IdNode(Token('id', filename, 0, 0, 0, (0, 0), target_id)), _symbol('='), tgt_fun_node)
|
|
831
|
+
tgt_arg_node.arguments = [
|
|
832
|
+
StringNode(Token('string', filename, 0, 0, 0, None, cmd['target'])),
|
|
833
|
+
IdNode(Token('string', filename, 0, 0, 0, None, source_id))
|
|
834
|
+
]
|
|
835
|
+
|
|
836
|
+
src_ass_node.accept(AstIndentationGenerator())
|
|
837
|
+
tgt_ass_node.accept(AstIndentationGenerator())
|
|
838
|
+
self.to_add_nodes += [src_ass_node, tgt_ass_node]
|
|
839
|
+
|
|
840
|
+
elif cmd['operation'] == 'target_rm':
|
|
841
|
+
to_remove = self.find_assignment_node(target['node'])
|
|
842
|
+
if to_remove is None:
|
|
843
|
+
to_remove = target['node']
|
|
844
|
+
self.to_remove_nodes += [to_remove]
|
|
845
|
+
mlog.log(' -- Removing target', mlog.green(cmd['target']), 'at',
|
|
846
|
+
mlog.yellow(f'{to_remove.filename}:{to_remove.lineno}'))
|
|
847
|
+
|
|
848
|
+
elif cmd['operation'] == 'info':
|
|
849
|
+
# T.List all sources in the target
|
|
850
|
+
src_list = []
|
|
851
|
+
for i in target['sources']:
|
|
852
|
+
for j in arg_list_from_node(i):
|
|
853
|
+
if isinstance(j, BaseStringNode):
|
|
854
|
+
src_list += [j.value]
|
|
855
|
+
extra_files_list = []
|
|
856
|
+
for i in target['extra_files']:
|
|
857
|
+
for j in arg_list_from_node(i):
|
|
858
|
+
if isinstance(j, BaseStringNode):
|
|
859
|
+
extra_files_list += [j.value]
|
|
860
|
+
test_data = {
|
|
861
|
+
'name': target['name'],
|
|
862
|
+
'sources': src_list,
|
|
863
|
+
'extra_files': extra_files_list
|
|
864
|
+
}
|
|
865
|
+
self.add_info('target', target['id'], test_data)
|
|
866
|
+
|
|
867
|
+
# Sort files
|
|
868
|
+
for i in to_sort_nodes:
|
|
869
|
+
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
|
870
|
+
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
|
871
|
+
path_sorter = lambda key: ([(key.count('/') <= idx, alphanum_key(x)) for idx, x in enumerate(key.split('/'))])
|
|
872
|
+
|
|
873
|
+
unknown = [x for x in i.arguments if not isinstance(x, BaseStringNode)]
|
|
874
|
+
sources = [x for x in i.arguments if isinstance(x, BaseStringNode)]
|
|
875
|
+
sources = sorted(sources, key=lambda x: path_sorter(x.value))
|
|
876
|
+
i.arguments = unknown + sources
|
|
877
|
+
|
|
878
|
+
def process(self, cmd):
|
|
879
|
+
if 'type' not in cmd:
|
|
880
|
+
raise RewriterException('Command has no key "type"')
|
|
881
|
+
if cmd['type'] not in self.functions:
|
|
882
|
+
raise RewriterException('Unknown command "{}". Supported commands are: {}'
|
|
883
|
+
.format(cmd['type'], list(self.functions.keys())))
|
|
884
|
+
self.functions[cmd['type']](cmd)
|
|
885
|
+
|
|
886
|
+
def apply_changes(self):
|
|
887
|
+
assert all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.modified_nodes)
|
|
888
|
+
assert all(hasattr(x, 'lineno') and hasattr(x, 'colno') and hasattr(x, 'filename') for x in self.to_remove_nodes)
|
|
889
|
+
assert all(isinstance(x, (ArrayNode, FunctionNode)) for x in self.modified_nodes)
|
|
890
|
+
assert all(isinstance(x, (ArrayNode, AssignmentNode, FunctionNode)) for x in self.to_remove_nodes)
|
|
891
|
+
# Sort based on line and column in reversed order
|
|
892
|
+
work_nodes = [{'node': x, 'action': 'modify'} for x in self.modified_nodes]
|
|
893
|
+
work_nodes += [{'node': x, 'action': 'rm'} for x in self.to_remove_nodes]
|
|
894
|
+
work_nodes = sorted(work_nodes, key=lambda x: (x['node'].lineno, x['node'].colno), reverse=True)
|
|
895
|
+
work_nodes += [{'node': x, 'action': 'add'} for x in self.to_add_nodes]
|
|
896
|
+
|
|
897
|
+
# Generating the new replacement string
|
|
898
|
+
str_list = []
|
|
899
|
+
for i in work_nodes:
|
|
900
|
+
new_data = ''
|
|
901
|
+
if i['action'] == 'modify' or i['action'] == 'add':
|
|
902
|
+
printer = AstPrinter()
|
|
903
|
+
i['node'].accept(printer)
|
|
904
|
+
printer.post_process()
|
|
905
|
+
new_data = printer.result.strip()
|
|
906
|
+
data = {
|
|
907
|
+
'file': i['node'].filename,
|
|
908
|
+
'str': new_data,
|
|
909
|
+
'node': i['node'],
|
|
910
|
+
'action': i['action']
|
|
911
|
+
}
|
|
912
|
+
str_list += [data]
|
|
913
|
+
|
|
914
|
+
# Load build files
|
|
915
|
+
files = {}
|
|
916
|
+
for i in str_list:
|
|
917
|
+
if i['file'] in files:
|
|
918
|
+
continue
|
|
919
|
+
fpath = os.path.realpath(os.path.join(self.sourcedir, i['file']))
|
|
920
|
+
fdata = ''
|
|
921
|
+
# Create an empty file if it does not exist
|
|
922
|
+
if not os.path.exists(fpath):
|
|
923
|
+
with open(fpath, 'w', encoding='utf-8'):
|
|
924
|
+
pass
|
|
925
|
+
with open(fpath, encoding='utf-8') as fp:
|
|
926
|
+
fdata = fp.read()
|
|
927
|
+
|
|
928
|
+
# Generate line offsets numbers
|
|
929
|
+
m_lines = fdata.splitlines(True)
|
|
930
|
+
offset = 0
|
|
931
|
+
line_offsets = []
|
|
932
|
+
for j in m_lines:
|
|
933
|
+
line_offsets += [offset]
|
|
934
|
+
offset += len(j)
|
|
935
|
+
|
|
936
|
+
files[i['file']] = {
|
|
937
|
+
'path': fpath,
|
|
938
|
+
'raw': fdata,
|
|
939
|
+
'offsets': line_offsets
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
# Replace in source code
|
|
943
|
+
def remove_node(i):
|
|
944
|
+
offsets = files[i['file']]['offsets']
|
|
945
|
+
raw = files[i['file']]['raw']
|
|
946
|
+
node = i['node']
|
|
947
|
+
line = node.lineno - 1
|
|
948
|
+
col = node.colno
|
|
949
|
+
start = offsets[line] + col
|
|
950
|
+
end = start
|
|
951
|
+
if isinstance(node, (ArrayNode, FunctionNode)):
|
|
952
|
+
end = offsets[node.end_lineno - 1] + node.end_colno
|
|
953
|
+
|
|
954
|
+
# Only removal is supported for assignments
|
|
955
|
+
elif isinstance(node, AssignmentNode) and i['action'] == 'rm':
|
|
956
|
+
if isinstance(node.value, (ArrayNode, FunctionNode)):
|
|
957
|
+
remove_node({'file': i['file'], 'str': '', 'node': node.value, 'action': 'rm'})
|
|
958
|
+
raw = files[i['file']]['raw']
|
|
959
|
+
while raw[end] != '=':
|
|
960
|
+
end += 1
|
|
961
|
+
end += 1 # Handle the '='
|
|
962
|
+
while raw[end] in {' ', '\n', '\t'}:
|
|
963
|
+
end += 1
|
|
964
|
+
|
|
965
|
+
files[i['file']]['raw'] = raw[:start] + i['str'] + raw[end:]
|
|
966
|
+
|
|
967
|
+
for i in str_list:
|
|
968
|
+
if i['action'] in {'modify', 'rm'}:
|
|
969
|
+
remove_node(i)
|
|
970
|
+
elif i['action'] == 'add':
|
|
971
|
+
files[i['file']]['raw'] += i['str'] + '\n'
|
|
972
|
+
|
|
973
|
+
# Write the files back
|
|
974
|
+
for key, val in files.items():
|
|
975
|
+
mlog.log('Rewriting', mlog.yellow(key))
|
|
976
|
+
with open(val['path'], 'w', encoding='utf-8') as fp:
|
|
977
|
+
fp.write(val['raw'])
|
|
978
|
+
|
|
979
|
+
target_operation_map = {
|
|
980
|
+
'add': 'src_add',
|
|
981
|
+
'rm': 'src_rm',
|
|
982
|
+
'add_target': 'target_add',
|
|
983
|
+
'rm_target': 'target_rm',
|
|
984
|
+
'add_extra_files': 'extra_files_add',
|
|
985
|
+
'rm_extra_files': 'extra_files_rm',
|
|
986
|
+
'info': 'info',
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
def list_to_dict(in_list: T.List[str]) -> T.Dict[str, str]:
|
|
990
|
+
result = {}
|
|
991
|
+
it = iter(in_list)
|
|
992
|
+
try:
|
|
993
|
+
for i in it:
|
|
994
|
+
# calling next(it) is not a mistake, we're taking the next element from
|
|
995
|
+
# the iterator, avoiding the need to preprocess it into a sequence of
|
|
996
|
+
# key value pairs.
|
|
997
|
+
result[i] = next(it)
|
|
998
|
+
except StopIteration:
|
|
999
|
+
raise TypeError('in_list parameter of list_to_dict must have an even length.')
|
|
1000
|
+
return result
|
|
1001
|
+
|
|
1002
|
+
def generate_target(options) -> T.List[dict]:
|
|
1003
|
+
return [{
|
|
1004
|
+
'type': 'target',
|
|
1005
|
+
'target': options.target,
|
|
1006
|
+
'operation': target_operation_map[options.operation],
|
|
1007
|
+
'sources': options.sources,
|
|
1008
|
+
'subdir': options.subdir,
|
|
1009
|
+
'target_type': options.tgt_type,
|
|
1010
|
+
}]
|
|
1011
|
+
|
|
1012
|
+
def generate_kwargs(options) -> T.List[dict]:
|
|
1013
|
+
return [{
|
|
1014
|
+
'type': 'kwargs',
|
|
1015
|
+
'function': options.function,
|
|
1016
|
+
'id': options.id,
|
|
1017
|
+
'operation': options.operation,
|
|
1018
|
+
'kwargs': list_to_dict(options.kwargs),
|
|
1019
|
+
}]
|
|
1020
|
+
|
|
1021
|
+
def generate_def_opts(options) -> T.List[dict]:
|
|
1022
|
+
return [{
|
|
1023
|
+
'type': 'default_options',
|
|
1024
|
+
'operation': options.operation,
|
|
1025
|
+
'options': list_to_dict(options.options),
|
|
1026
|
+
}]
|
|
1027
|
+
|
|
1028
|
+
def generate_cmd(options) -> T.List[dict]:
|
|
1029
|
+
if os.path.exists(options.json):
|
|
1030
|
+
with open(options.json, encoding='utf-8') as fp:
|
|
1031
|
+
return json.load(fp)
|
|
1032
|
+
else:
|
|
1033
|
+
return json.loads(options.json)
|
|
1034
|
+
|
|
1035
|
+
# Map options.type to the actual type name
|
|
1036
|
+
cli_type_map = {
|
|
1037
|
+
'target': generate_target,
|
|
1038
|
+
'tgt': generate_target,
|
|
1039
|
+
'kwargs': generate_kwargs,
|
|
1040
|
+
'default-options': generate_def_opts,
|
|
1041
|
+
'def': generate_def_opts,
|
|
1042
|
+
'command': generate_cmd,
|
|
1043
|
+
'cmd': generate_cmd,
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
def run(options):
|
|
1047
|
+
if not options.verbose:
|
|
1048
|
+
mlog.set_quiet()
|
|
1049
|
+
|
|
1050
|
+
try:
|
|
1051
|
+
setup_vsenv()
|
|
1052
|
+
rewriter = Rewriter(options.sourcedir, skip_errors=options.skip)
|
|
1053
|
+
rewriter.analyze_meson()
|
|
1054
|
+
|
|
1055
|
+
if options.type is None:
|
|
1056
|
+
mlog.error('No command specified')
|
|
1057
|
+
return 1
|
|
1058
|
+
|
|
1059
|
+
commands = cli_type_map[options.type](options)
|
|
1060
|
+
|
|
1061
|
+
if not isinstance(commands, list):
|
|
1062
|
+
raise TypeError('Command is not a list')
|
|
1063
|
+
|
|
1064
|
+
for i in commands:
|
|
1065
|
+
if not isinstance(i, object):
|
|
1066
|
+
raise TypeError('Command is not an object')
|
|
1067
|
+
rewriter.process(i)
|
|
1068
|
+
|
|
1069
|
+
rewriter.apply_changes()
|
|
1070
|
+
rewriter.print_info()
|
|
1071
|
+
return 0
|
|
1072
|
+
except Exception as e:
|
|
1073
|
+
raise e
|
|
1074
|
+
finally:
|
|
1075
|
+
mlog.set_verbose()
|