mirror of
https://github.com/radareorg/r2env.git
synced 2026-11-08 08:49:34 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daeba4ebcf | ||
|
|
5578bee417 | ||
|
|
ab6cce7008 | ||
|
|
d501129500 | ||
|
|
51c1b2ca2c | ||
|
|
743812b653 | ||
|
|
ac3b695012 | ||
|
|
00a3db509c | ||
|
|
ccd7231065 | ||
|
|
3b8716ea1d | ||
|
|
d6b40cf4b8 | ||
|
|
a4d678511e | ||
|
|
658ede86d9 | ||
|
|
d8fc2f8b71 | ||
|
|
57398126f3 | ||
|
|
f7e211b014 | ||
|
|
3873eb48a7 | ||
|
|
c5ba226b21 | ||
|
|
88e68daef5 | ||
|
|
2468813a3c | ||
|
|
223af1e85d | ||
|
|
0ef5ff2d72 | ||
|
|
2f937f67f1 | ||
|
|
4380456e1d | ||
|
|
59c9445d10 | ||
|
|
713c18feb4 | ||
|
|
670de20b01 | ||
|
|
019e941dfa | ||
|
|
26925a29d6 | ||
|
|
1a1f3fcde5 | ||
|
|
0c838e7d08 | ||
|
|
b3852a92d3 | ||
|
|
6f81459f70 | ||
|
|
3f16036689 | ||
|
|
00782ae62f | ||
|
|
93bd2b0e1e | ||
|
|
100dc1a9d0 | ||
|
|
e5677a03ae | ||
|
|
35d769e73b | ||
|
|
587ce7ef96 | ||
|
|
edfe363401 | ||
|
|
9d521d7f0e | ||
|
|
2c0f8d48c9 | ||
|
|
d8a948c61b | ||
|
|
374e93bf2b | ||
|
|
9459ab1f72 | ||
|
|
61b9bafdcb | ||
|
|
e7d1a24683 | ||
|
|
ac6a072246 | ||
|
|
ffa0f87d9c | ||
|
|
bf35b36959 | ||
|
|
e6bcd7c4d4 | ||
|
|
25d26bb0f9 | ||
|
|
db54437130 | ||
|
|
4ffe814c42 | ||
|
|
89272008ca | ||
|
|
a1b6363f26 | ||
|
|
47eeb599b6 | ||
|
|
c89615d0fb | ||
|
|
e449e41971 | ||
|
|
56426fd1f2 | ||
|
|
e27ce149b3 | ||
|
|
5cb3f75f35 | ||
|
|
2200ddcb50 | ||
|
|
50f444dab0 | ||
|
|
db4e174ecf | ||
|
|
9ada5d4322 | ||
|
|
47c5b9feab | ||
|
|
e94f9c07af | ||
|
|
ef703be9fe | ||
|
|
b0c2e38ece | ||
|
|
aa4a5170cd | ||
|
|
01e2b5efaa | ||
|
|
d58b97085c | ||
|
|
e15c4249a3 | ||
|
|
2a7f1893f1 | ||
|
|
378adc688a | ||
|
|
092eda37ea | ||
|
|
068f103a89 | ||
|
|
6c0c26aa0b | ||
|
|
29fa15b555 | ||
|
|
fdd5602970 | ||
|
|
684d6d5211 | ||
|
|
bf6ff7d2db | ||
|
|
30e319f3fb | ||
|
|
7c948fab24 | ||
|
|
b9089e9b2d | ||
|
|
0fa2cf4a87 | ||
|
|
35f1c4152e | ||
|
|
7ece62f905 | ||
|
|
4323295829 | ||
|
|
444974cf0a | ||
|
|
9b60d72a55 | ||
|
|
c9e7123fad | ||
|
|
48ca2997e9 | ||
|
|
57db2d1f7a | ||
|
|
4d03c87bf1 | ||
|
|
eb7dfa643a | ||
|
|
f8fbc50505 | ||
|
|
8606f42ceb | ||
|
|
a37787570a | ||
|
|
58a2e071ab |
No files matched your search
+38
-11
@@ -2,8 +2,7 @@ name: CI
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
types: [published]
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -18,6 +17,7 @@ jobs:
|
||||
pylint:
|
||||
name: codecheck-pylint
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -28,6 +28,7 @@ jobs:
|
||||
flake8:
|
||||
name: codecheck-flake8
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -35,6 +36,17 @@ jobs:
|
||||
run: pip install -r requirements/test.txt
|
||||
- name: Run
|
||||
run: tox -e py38-codecheck-flake8
|
||||
unit-tests:
|
||||
name: linux-unit-tests
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements/test.txt
|
||||
- name: Run
|
||||
run: tox -e py38-tests
|
||||
integration-tests:
|
||||
name: linux-integration-tests
|
||||
runs-on: ubuntu-20.04
|
||||
@@ -43,23 +55,38 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
- name: Install
|
||||
run: sudo pip install . --force-reinstall
|
||||
- name: Initializing
|
||||
run: r2env init
|
||||
- name: Execute r2env
|
||||
run: r2env list
|
||||
- name: Install r2 using r2env
|
||||
run: |
|
||||
r2env init
|
||||
r2env install radare2@latest
|
||||
- name: Execute latest r2 version
|
||||
[ "`r2env | wc -l`" -gt 10 ] # measure help message
|
||||
[ "`r2env -l | wc -l`" -gt 6 ] # measure pkgs
|
||||
r2env install radare2@git
|
||||
- name: Execute git version of r2
|
||||
run: |
|
||||
r2env use radare2@latest
|
||||
r2env use radare2@git
|
||||
$HOME/.r2env/bin/r2 -v
|
||||
r2env shell "r2 -v"
|
||||
- name: Uninstalling
|
||||
run: sudo pip uninstall -y r2env && rm -rf $HOME/.r2env
|
||||
release-job:
|
||||
name: Publish to pypi
|
||||
name: Publish package
|
||||
runs-on: ubuntu-20.04
|
||||
needs: [integration-tests, flake8, pylint]
|
||||
if: github.event_name == 'release' && github.event.action == 'created'
|
||||
needs: [integration-tests, unit-tests, flake8, pylint]
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
steps:
|
||||
- name: Release
|
||||
run: make pub
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements/dist.txt
|
||||
- name: Build
|
||||
run: python setup.py sdist
|
||||
- name: Publish
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.TWINE_PASSWORD }}
|
||||
@@ -0,0 +1,70 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '34 6 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -0,0 +1,23 @@
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/semgrep.yml
|
||||
schedule:
|
||||
# random HH:MM to avoid a load spike on GitHub Actions at 00:00
|
||||
- cron: 34 10 * * *
|
||||
name: Semgrep
|
||||
jobs:
|
||||
semgrep:
|
||||
name: Scan
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: semgrep ci
|
||||
@@ -1,3 +1,4 @@
|
||||
.coverage
|
||||
.idea
|
||||
**/__pycache__/
|
||||
venv
|
||||
|
||||
@@ -4,6 +4,8 @@ disable=
|
||||
C0116, # Missing function or method docstring (missing-function-docstring)
|
||||
C0115, # Missing class docstring (missing-class-docstring)
|
||||
R0913, # Too many arguments (7/5) (too-many-arguments)
|
||||
W0511, # TODO (fixme)
|
||||
C0103, # invalid-name
|
||||
|
||||
[FORMAT]
|
||||
max-line-length=120
|
||||
@@ -1,17 +1,20 @@
|
||||
PYTHON?=python3
|
||||
PIP?=pip3
|
||||
|
||||
all:
|
||||
pip install .
|
||||
$(PIP) install .
|
||||
|
||||
pub:
|
||||
rm -rf dist
|
||||
$(PYTHON) setup.py sdist
|
||||
twine upload --repository=pypi --verbose dist/*
|
||||
twine check dist/*
|
||||
twine upload -u __token__ --repository-url https://upload.pypi.org/legacy/ --verbose dist/*
|
||||
#twine upload --repository=pypi --verbose dist/*
|
||||
|
||||
install:
|
||||
pip install .
|
||||
$(PIP) install .
|
||||
|
||||
uninstall:
|
||||
pip uninstall r2env
|
||||
$(PIP) uninstall r2env
|
||||
|
||||
.PHONY: all clean pub install uninstall
|
||||
@@ -1,53 +1,29 @@
|
||||
r2env
|
||||
=====
|
||||
# r2env
|
||||
|
||||
[](https://github.com/radareorg/r2env/actions/workflows/ci.yml)
|
||||
|
||||
This repository contains the tool available via pip to install
|
||||
and manage multiple versions of radare2 and its plugins.
|
||||
Create self-contained environments with multiple versions of radare2
|
||||
and plugins, make it easy to switch between them.
|
||||
|
||||
r2-tools doesn't conflict with r2pm in the sense that it's not
|
||||
going to support all the packages and plugins and it's
|
||||
* Build from source or install the system package if available.
|
||||
|
||||
r2env supports source and binary packages.
|
||||
## Installation
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
r2env is available via PIP.
|
||||
|
||||
* r2env should be self contained
|
||||
* `pip install -U -f r2env`
|
||||
|
||||
Some tools may be used if installed in the system, making some
|
||||
packages available, but we may try to use python-version if
|
||||
possible, so it don't depend on system packages.
|
||||
If you want to try it directly from source.
|
||||
|
||||
Package description
|
||||
-------------------
|
||||
INI, JSON or python class, loaded at runtime, but it is k=v stuff
|
||||
* `pip install .`
|
||||
|
||||
* name: iaito
|
||||
* platform: windows
|
||||
* version: 5.2.1
|
||||
* source: https://path/to/zip
|
||||
## Usage
|
||||
|
||||
Actions
|
||||
-------
|
||||
* install / uninstall
|
||||
* link / unlink
|
||||
* update - pip install -U r2env
|
||||
* upgrade - upgrade r2 and all the deps in sync
|
||||
First we need to initialize the working directory:
|
||||
|
||||
|
||||
How to install
|
||||
--------------
|
||||
|
||||
r2env is available via PIP. (`pip install r2env`)
|
||||
|
||||
To build + install from source just run: `make`
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
First of all you may want to initialize the `.r2env` directory somewhere with `cd .. ; r2env init`.
|
||||
```
|
||||
r2env init
|
||||
```
|
||||
|
||||
Listing available packages is done via `r2env list`.
|
||||
|
||||
@@ -56,18 +32,57 @@ Source packages are managed with the `add`, `rm`, `use` and `unused`.
|
||||
For example: Installing radare2 (assumes @git version)
|
||||
|
||||
```
|
||||
cd /tmp
|
||||
r2env init
|
||||
r2env add radare2
|
||||
r2env use radare2@git
|
||||
r2env shell r2 -v
|
||||
r2env shell "r2 -v"
|
||||
```
|
||||
|
||||
r2pm vs r2env
|
||||
-------------
|
||||
## Help
|
||||
|
||||
```
|
||||
Usage: r2env [-flags] [action] [args...]
|
||||
|
||||
Flags:
|
||||
|
||||
-h, --help - show this help
|
||||
-v, --version - display r2env version
|
||||
-m, --meson - use meson instead of acr
|
||||
-p, --package - install the dist package instead of building
|
||||
-l, --list - list available and installed packages
|
||||
|
||||
Actions:
|
||||
|
||||
init - create ~/.r2env directory
|
||||
config - display current .r2env settings
|
||||
add [pkg] - build and install given package. See -p and -m
|
||||
use [pkg] - use r2 package defined. pkg should be a release version or git.
|
||||
rm [pkg] - remove package from ~/.r2env
|
||||
path - show path of current r2 in use
|
||||
version - show version of r2env
|
||||
versions - list installed packages
|
||||
list - list all packages available to r2env
|
||||
shell - enter a new shell with PATH env var set
|
||||
purge - remove ~/.r2env
|
||||
update - update list of available profiles
|
||||
|
||||
Environment
|
||||
|
||||
R2ENV_PATH - specify different path other than ~/.r2env
|
||||
|
||||
```
|
||||
|
||||
## r2pm vs r2env
|
||||
|
||||
r2env aims to provide a packaging for r2 with support for binary packages and for all major platforms.
|
||||
|
||||
r2pm focus on providing more packages, it's written in shellscript, so it doesnt run on windows and requires r2 to work.
|
||||
|
||||
Therefor r2env is kind of `nvm` from nodejs or `pyenv` from python. A way to run multiple different versions of r2 in the system.
|
||||
|
||||
This repository contains the tool available via pip to install
|
||||
and manage multiple versions of radare2 and its plugins.
|
||||
|
||||
r2-tools doesn't conflict with r2pm in the sense that it's not
|
||||
going to support all the packages and plugins and it's
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from r2env.repl import main
|
||||
|
||||
main()
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"radare0": {
|
||||
"source": "https://github.com/radareorg/r0",
|
||||
"versions": [
|
||||
{
|
||||
"id": "latest",
|
||||
"packages:": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"radare2": {
|
||||
"source": "https://github.com/radareorg/radare2",
|
||||
"versions": [
|
||||
{
|
||||
"id": "5.3.0",
|
||||
"packages:": {
|
||||
"w64": "radare2-5.3.0-w64.zip",
|
||||
"deb_x64": "radare2_5.3.0_amd64.deb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "5.3.1",
|
||||
"packages:": {
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "latest",
|
||||
"packages:": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+91
-49
@@ -1,14 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from dploy import stow, unstow
|
||||
|
||||
from r2env.exceptions import R2EnvException
|
||||
from r2env.package_manager import PackageManager
|
||||
from r2env.tools import print_console, load_json_file, WARNING, ERROR
|
||||
from r2env.tools import print_console, load_json_file, WARNING, ERROR, host_platform
|
||||
|
||||
|
||||
class R2Env:
|
||||
@@ -23,114 +26,153 @@ class R2Env:
|
||||
|
||||
def init(self):
|
||||
if os.path.isdir(self._r2env_path):
|
||||
print_console("[x] r2env already initialized. Path {} already exists.".format(self._r2env_path), ERROR)
|
||||
print_console(f"[x] r2env already initialized. Path {self._r2env_path} already exists.", ERROR)
|
||||
return
|
||||
os.mkdir(self._r2env_path)
|
||||
print_console("[*] r2env initialized at {}".format(self._r2env_path))
|
||||
print_console(f"[*] r2env initialized at {self._r2env_path}")
|
||||
|
||||
def get_r2_path(self):
|
||||
self.exit_if_r2env_not_initialized()
|
||||
self.check_if_r2env_initialized()
|
||||
r2_version = self._get_current_version()
|
||||
r2_path = self._package_manager.get_package_path(r2_version) if r2_version else "Radare package not configured"
|
||||
print_console(" [*] {0} ({1})".format(r2_version, r2_path))
|
||||
print_console(f" [*] {r2_version} ({r2_path})")
|
||||
|
||||
def show_config(self):
|
||||
print_console("[*] Current r2env config:")
|
||||
print_console(json.dumps(self._config))
|
||||
|
||||
def list_packages(self):
|
||||
self.list_available_packages()
|
||||
self.list_installed_packages()
|
||||
|
||||
def list_available_packages(self):
|
||||
print_console("[*] List of available Radare packages")
|
||||
print_console("- Available")
|
||||
packages = self._package_manager.list_available_packages()
|
||||
for profile in packages:
|
||||
print_console(" - {} packages:".format(profile), WARNING)
|
||||
print_console(f" - {profile}:", WARNING)
|
||||
for version in packages[profile]['versions']:
|
||||
print_console(" {}@{}".format(profile, version['id']), formatter=1)
|
||||
dists = ", ".join(version['packages'].keys())
|
||||
print_console(f" - {profile}@{version['id']} - {dists}", formatter=1)
|
||||
|
||||
def list_installed_packages(self):
|
||||
self.exit_if_r2env_not_initialized()
|
||||
print_console("[*] Installed Radare packages")
|
||||
self.check_if_r2env_initialized()
|
||||
print_console("- Installed")
|
||||
for pkg in self._package_manager.list_installed_packages():
|
||||
if pkg == self._get_current_version():
|
||||
print_console(" [*] {}".format(pkg))
|
||||
print_console(f" - {pkg} (in use)")
|
||||
else:
|
||||
print_console(" - {}".format(pkg))
|
||||
print_console(f" - {pkg}")
|
||||
|
||||
def install(self, package, use_meson=False):
|
||||
self.exit_if_r2env_not_initialized()
|
||||
def install(self, package, **kwargs):
|
||||
self.check_if_r2env_initialized()
|
||||
use_meson = kwargs["use_meson"] if "use_meson" in kwargs else False
|
||||
use_dist = kwargs["use_dist"] if "use_dist" in kwargs else False
|
||||
if "@" not in package:
|
||||
package = f"{package}@git"
|
||||
if not self._check_package_format(package):
|
||||
print_console("[x] Invalid Package format.", level=ERROR)
|
||||
return
|
||||
profile, version = package.split('@')
|
||||
self._package_manager.install_package(profile, version, use_meson=use_meson)
|
||||
print_console("[*] Magic Done! Remember to add the $HOME/.r2env/bin folder to your PATH.")
|
||||
raise R2EnvException("[x] Invalid package format.")
|
||||
try:
|
||||
profile, version = package.split('@')
|
||||
except ValueError:
|
||||
profile = package
|
||||
version = "git"
|
||||
self._package_manager.install_package(profile, version, use_meson=use_meson, use_dist=use_dist)
|
||||
print_console("[*] Add $HOME/.r2env/bin to your PATH or use 'r2env shell'.")
|
||||
|
||||
def uninstall(self, package):
|
||||
self.exit_if_r2env_not_initialized()
|
||||
def uninstall(self, package, **kwargs):
|
||||
self.check_if_r2env_initialized()
|
||||
use_dist = kwargs["use_dist"] if "use_dist" in kwargs else False
|
||||
if not self._check_package_format(package):
|
||||
print_console("[x] Invalid Package format.", level=ERROR)
|
||||
return
|
||||
self._package_manager.uninstall_package(package)
|
||||
raise R2EnvException("[x] Invalid package format.")
|
||||
self._package_manager.uninstall_package(package, use_dist)
|
||||
|
||||
def use(self, package=None):
|
||||
self.exit_if_r2env_not_initialized()
|
||||
def purge(self):
|
||||
print_console(f"[*] Removing {self._r2env_path}")
|
||||
shutil.rmtree(self._r2env_path)
|
||||
|
||||
def use(self, package=None, **_kwargs):
|
||||
self.check_if_r2env_initialized()
|
||||
if not package:
|
||||
print_console("[x] Package not defined. Please use 'r2env use' with one installed package. ", ERROR)
|
||||
self.list_installed_packages()
|
||||
return
|
||||
raise R2EnvException("Package not defined.")
|
||||
if package not in self._package_manager.list_installed_packages():
|
||||
raise R2EnvException(f"Package {package} not installed.")
|
||||
cur_ver = self._get_current_version()
|
||||
new_dst_dir = self._package_manager.get_package_path(package)
|
||||
if cur_ver:
|
||||
unstow([self._package_manager.get_package_path(cur_ver)], self._r2env_path)
|
||||
stow([new_dst_dir], self._r2env_path)
|
||||
self._set_current_version(package)
|
||||
print_console("[*] Using {} package".format(package))
|
||||
print_console(f"[*] Using {package} package")
|
||||
|
||||
@staticmethod
|
||||
def version():
|
||||
thispath = os.path.dirname(os.path.realpath(__file__))
|
||||
with open(thispath + "/version.txt", "r") as version:
|
||||
return version.read()
|
||||
with open(f"{thispath}/version.txt", "r", encoding="utf-8") as version:
|
||||
print_console(version.read())
|
||||
|
||||
def shell(self, cmd=""):
|
||||
line = "export PS1=\"r2env\\$ \";export PATH=\"" + self._r2env_path + "/bin:$PATH\"; $SHELL -f"
|
||||
if os.path.isfile("/default.prop"): # hack for pre-dtag builds of r2
|
||||
line = "export LD_LIBRARY_PATH=\"" + self._r2env_path + "/lib\";" + line
|
||||
if cmd.strip() == "":
|
||||
return os.system(line)
|
||||
print(os.system(line + " -c '" + cmd + "'"))
|
||||
return os.system(line + " -c '" + cmd + "'")
|
||||
def shell(self, cmd=None, **_kwargs):
|
||||
bin_path = os.path.join(self._r2env_path, "bin")
|
||||
if host_platform() == "windows":
|
||||
os.system(f"set PATH={bin_path};%PATH% && cmd")
|
||||
return True
|
||||
pkgconfig_path = os.path.join(self._r2env_path, "lib", "pkgconfig")
|
||||
bin_path = os.path.join(self._r2env_path, "bin")
|
||||
export_ps1 = f"export PS1=\"r2env ({self._get_current_version()})\\$ \";"
|
||||
export_pkg_config = f"export PKG_CONFIG_PATH=\"{pkgconfig_path}\";"
|
||||
export_path = f"export PATH=\"{bin_path}:$PATH\";"
|
||||
cmd_shell = "$SHELL -f"
|
||||
full_cmd = export_ps1 + export_pkg_config + export_path + cmd_shell
|
||||
if host_platform() == "android": # hack for pre-dtag builds of r2
|
||||
library_path = os.path.join(self._r2env_path, "lib")
|
||||
full_cmd = f"export LD_LIBRARY_PATH=\"{library_path}\";" + full_cmd
|
||||
if host_platform() == "osx":
|
||||
library_path = os.path.join(self._r2env_path, "lib")
|
||||
# XXX this doesnt work on sip-enabled macs, that's why we use install_name_tool after install
|
||||
full_cmd = f"export DYLD_LIBRARY_PATH=\"{library_path}\";" + full_cmd
|
||||
if cmd is None:
|
||||
return os.system(full_cmd) == 0
|
||||
return os.system(f"{full_cmd} -c '{cmd}'") == 0
|
||||
|
||||
@staticmethod
|
||||
def _load_config():
|
||||
filename = os.path.join(os.path.dirname(__file__), 'config', 'config.json')
|
||||
config = load_json_file(filename)
|
||||
environment_path = os.getenv("R2ENV_PATH")
|
||||
if environment_path is not None:
|
||||
config["r2env_path"] = environment_path
|
||||
if not config:
|
||||
sys.exit(-1)
|
||||
config = {}
|
||||
return config
|
||||
|
||||
@staticmethod
|
||||
def _get_default_path():
|
||||
# TODO: try to find an .r2env starting in current directory
|
||||
return os.path.join(Path.home(), ".r2env")
|
||||
|
||||
@staticmethod
|
||||
def _check_package_format(package):
|
||||
regexp = re.compile(r"\w+\d@(?:\d\.\d\.\d|latest)")
|
||||
return regexp.match(package)
|
||||
regexp = r"[a-z0-9]+@(\d\.\d\.\d|git)"
|
||||
if not package:
|
||||
return False
|
||||
return re.search(regexp, package) is not None
|
||||
|
||||
def _get_current_version(self):
|
||||
version_file = os.path.join(self._r2env_path, self.VERSION_FILE)
|
||||
if not os.path.isfile(version_file):
|
||||
return ''
|
||||
with open(version_file, 'r') as file_desc:
|
||||
with open(version_file, 'r', encoding="utf-8") as file_desc:
|
||||
version = file_desc.read()
|
||||
return version
|
||||
|
||||
def _set_current_version(self, package):
|
||||
version_file = os.path.join(self._r2env_path, self.VERSION_FILE)
|
||||
with open(version_file, 'w') as file_desc:
|
||||
with open(version_file, 'w', encoding="utf-8") as file_desc:
|
||||
file_desc.write(package)
|
||||
|
||||
def exit_if_r2env_not_initialized(self):
|
||||
def update_version_profiles(self):
|
||||
PackageManager.update_radare2_profiles(self._r2env_path)
|
||||
|
||||
def check_if_r2env_initialized(self):
|
||||
if not os.path.isdir(self._r2env_path):
|
||||
print_console("Not r2env initialized. Execute 'r2env init' first.", ERROR)
|
||||
sys.exit(-1)
|
||||
raise R2EnvException("Not r2env initialized. Execute 'r2env init' first.")
|
||||
@@ -0,0 +1,10 @@
|
||||
class R2EnvException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ActionException(R2EnvException):
|
||||
pass
|
||||
|
||||
|
||||
class PackageManagerException(R2EnvException):
|
||||
pass
|
||||
+261
-48
@@ -2,20 +2,26 @@
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
from urllib.error import URLError
|
||||
import zipfile
|
||||
import json
|
||||
|
||||
from r2env.tools import load_json_file, git_fetch, git_clean, print_console, ERROR, exit_if_not_exists
|
||||
import wget
|
||||
import requests
|
||||
|
||||
from r2env.exceptions import PackageManagerException
|
||||
from r2env.tools import load_json_file, git_fetch, git_clean, print_console, ERROR, exit_if_not_exists, host_distname
|
||||
|
||||
|
||||
class PackageManager:
|
||||
|
||||
LOG_DIR = "log"
|
||||
PACKAGES_DIR = "versions"
|
||||
SOURCE_DIR = "src"
|
||||
DOWNLOAD_URL = "https://github.com/radareorg/radare2/releases/download/"
|
||||
|
||||
def __init__(self, r2env_path):
|
||||
self._packages = self._load_profiles()
|
||||
self._packages = self._load_profiles(r2env_path)
|
||||
self._r2env_path = r2env_path
|
||||
|
||||
def get_package_path(self, package_name):
|
||||
@@ -34,90 +40,297 @@ class PackageManager:
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def _load_profiles():
|
||||
filename = os.path.join(os.path.dirname(__file__), 'config', 'profiles.json')
|
||||
def _load_profiles(r2env_path):
|
||||
filename = os.path.join(r2env_path, 'profiles.json')
|
||||
# if profiles.json doesn't exist, generate it now
|
||||
if not os.path.exists(filename):
|
||||
print_console(f"NOTE: {filename} does not exist. Generating it now.")
|
||||
PackageManager.update_radare2_profiles(r2env_path)
|
||||
profiles = load_json_file(filename)
|
||||
if not profiles:
|
||||
sys.exit(-1)
|
||||
raise PackageManagerException("No profiles configured.")
|
||||
return profiles
|
||||
|
||||
def install_package(self, profile, version, use_meson):
|
||||
@staticmethod
|
||||
def update_radare2_profiles(r2env_path):
|
||||
gh_release_info_req = requests.get(
|
||||
"https://api.github.com/repos/radareorg/radare2/releases",
|
||||
{"headers": ["X-GitHub-Api-Version: 2022-11-28", "Accept: application/vnd.github+json"]},
|
||||
timeout=10 # 10-second timeout for API request
|
||||
)
|
||||
gh_release_info_req.raise_for_status() # raise an error if the request got a bad return code
|
||||
gh_release_info = gh_release_info_req.json()
|
||||
radare2_versions = [{'id': 'git', 'packages': {}}] # include the git version by default
|
||||
for release in gh_release_info:
|
||||
version = {'id': release['tag_name'], 'packages': {}}
|
||||
# generate a list of downloadable assets for this release that r2env can use
|
||||
for asset in release['assets']:
|
||||
# note: you're about to see 100 lines of hackery to deal with inconsistent naming schemes
|
||||
# the goal is to include as many valid assets as is reasonable without including any that are not valid
|
||||
# separate file extension
|
||||
asset_name, asset_ext = os.path.splitext(asset['name'])
|
||||
|
||||
# normalize 'seperators' before splitting into components
|
||||
asset_ref = asset_name.replace('_', '-').split('-')
|
||||
|
||||
# filter out things like r2ios_sdk and r2blob
|
||||
if asset_ref[0] != 'radare2':
|
||||
continue
|
||||
|
||||
# Some assets don't have the version number in the name, which breaks the following processing.
|
||||
# None of them are of interest anyway, so just skip them.
|
||||
if release['tag_name'] not in asset_ref:
|
||||
continue
|
||||
|
||||
# remove the beginning 'radare2'
|
||||
asset_ref.remove('radare2')
|
||||
|
||||
# we don't need to care about the release id when checking, so remove it
|
||||
asset_ref.remove(release['tag_name'])
|
||||
|
||||
# once "radare2" and the version number have been removed from asset_ref,
|
||||
# if all that's left matches a filter, save it.
|
||||
_VERSION_FILTERS = {
|
||||
'.zip': { # used for Windows builds among other things
|
||||
'w32': [['w32']],
|
||||
'w64': [['w64']]
|
||||
},
|
||||
'.deb': {
|
||||
'deb_i386': [['i386']],
|
||||
'deb_x64': [['amd64']]
|
||||
},
|
||||
'.pkg': { # macOS bundle
|
||||
'mac_arm64': [['m1']],
|
||||
'mac_x64': [[], ['amd64'], ['x64'], ['macos']]
|
||||
}
|
||||
}
|
||||
|
||||
if asset_ext in _VERSION_FILTERS:
|
||||
for platform, refs in _VERSION_FILTERS[asset_ext].items():
|
||||
if asset_ref in refs:
|
||||
version['packages'][platform] = asset['name']
|
||||
break
|
||||
|
||||
radare2_versions.append(version)
|
||||
|
||||
profiles = {
|
||||
'r2frida': {
|
||||
'source': 'https://github.com/nowsecure/r2frida',
|
||||
'versions': [{'id': 'git', 'packages': {}}]
|
||||
},
|
||||
'r2dec': {
|
||||
'source': 'https://github.com/wargio/r2dec-js',
|
||||
'versions': [{'id': 'git', 'packages': {}}]
|
||||
},
|
||||
'r2yara': {
|
||||
'source': 'https://github.com/radareorg/r2yara',
|
||||
'versions': [{'id': 'git', 'packages': {}}]
|
||||
},
|
||||
'r2ghidra': {
|
||||
'source': 'https://github.com/radareorg/r2ghidra',
|
||||
'versions': [{'id': 'git', 'packages': {}}]
|
||||
},
|
||||
'r0': {
|
||||
'source': 'https://github.com/radareorg/r0',
|
||||
'versions': [{'id': 'git', 'packages': {}}]
|
||||
},
|
||||
'radare2': {
|
||||
'source': 'https://github.com/radareorg/radare2',
|
||||
'versions': radare2_versions[::-1]
|
||||
}
|
||||
}
|
||||
if not os.path.isdir(r2env_path):
|
||||
os.makedirs(r2env_path)
|
||||
with open(os.path.join(r2env_path, 'profiles.json'), 'w', encoding='utf-8') as f:
|
||||
json.dump(profiles, f)
|
||||
|
||||
def install_package(self, profile, version, use_meson, use_dist):
|
||||
log_path = os.path.join(self._r2env_path, self.LOG_DIR)
|
||||
logfile = os.path.join(log_path, "{}_{}_{}_build.txt".format(profile, version, round(time.monotonic() * 1000)))
|
||||
timestamp = round(time.monotonic() * 1000)
|
||||
logfile = os.path.join(log_path, f"{profile}_{version}_{timestamp}_build.txt")
|
||||
source_path = os.path.join(os.path.join(self._r2env_path, self.SOURCE_DIR, profile))
|
||||
dst_dir = os.path.join(os.path.join(self._r2env_path, self.PACKAGES_DIR), "{}@{}".format(profile, version))
|
||||
dst_dir = os.path.join(os.path.join(self._r2env_path, self.PACKAGES_DIR), f"{profile}@{version}")
|
||||
if not os.path.isdir(log_path):
|
||||
os.makedirs(log_path)
|
||||
if not os.path.isdir(source_path):
|
||||
os.makedirs(source_path)
|
||||
if not os.path.isdir(dst_dir):
|
||||
os.makedirs(dst_dir)
|
||||
self._exit_if_package_not_available(profile, version)
|
||||
if self._build_from_source(profile, version, source_path, dst_dir, logfile, use_meson=use_meson):
|
||||
print_console("[*] Package {}@{} installed successfully".format(profile, version))
|
||||
else:
|
||||
print_console("[x] Something wrong happened during the build process. Check {} for more information.".format
|
||||
(logfile), level=ERROR)
|
||||
if self._if_package_not_available(profile, version):
|
||||
if os.path.isdir(dst_dir):
|
||||
shutil.rmtree(dst_dir)
|
||||
raise PackageManagerException(
|
||||
f"{profile}@{version} package not available. Use 'list' command to see available packages.")
|
||||
if use_dist:
|
||||
if self._install_from_dist(profile, version):
|
||||
print_console(f"[*] Binary package {profile}@{version} installed successfully")
|
||||
else:
|
||||
if os.path.isdir(dst_dir):
|
||||
shutil.rmtree(dst_dir)
|
||||
raise PackageManagerException(f"[x] Failed to install {profile}@{version}.")
|
||||
else:
|
||||
if self._build_from_source(profile, version, source_path, dst_dir, logfile, use_meson=use_meson):
|
||||
print_console(f"[*] Package {profile}@{version} installed successfully")
|
||||
else:
|
||||
if os.path.isdir(dst_dir):
|
||||
shutil.rmtree(dst_dir)
|
||||
raise PackageManagerException(f"[x] Failed to build {profile}@{version}. "
|
||||
f"Check {logfile} for more information.")
|
||||
|
||||
def uninstall_package(self, package_name):
|
||||
def uninstall_package(self, package_name, use_dist):
|
||||
pkg_found = False
|
||||
for package in self.list_installed_packages():
|
||||
if package_name == package:
|
||||
pkg_found = True
|
||||
pkg_dir = os.path.join(os.path.join(self._r2env_path, self.PACKAGES_DIR), package_name)
|
||||
try:
|
||||
shutil.rmtree(pkg_dir)
|
||||
print_console("Removed package {}".format(package_name))
|
||||
except OSError as err:
|
||||
print_console("[x] Unable to remove package {0}. Error: {1}".format(package_name, err), ERROR)
|
||||
if use_dist:
|
||||
profile, version = package.split("@")
|
||||
self._uninstall_from_dist(profile, version)
|
||||
else:
|
||||
pkg_dir = os.path.join(self._r2env_path, self.PACKAGES_DIR, package)
|
||||
try:
|
||||
shutil.rmtree(pkg_dir)
|
||||
print_console(f"[-] Removed package {package_name}")
|
||||
except OSError as err:
|
||||
raise PackageManagerException(f"[x] Unable to remove package {package_name}. Error: {err}") \
|
||||
from err
|
||||
break
|
||||
if not pkg_found:
|
||||
print_console("[x] Unable to find installed package {0}".format(package_name), ERROR)
|
||||
raise PackageManagerException(f"[x] Unable to find installed package {package_name}")
|
||||
|
||||
def _build_from_package(self):
|
||||
pass
|
||||
def _get_pkgname(self, profile, version, cos):
|
||||
if profile in self._packages:
|
||||
for pkgv in self._packages[profile]["versions"]:
|
||||
if pkgv["id"] == version:
|
||||
for pkgd in pkgv["packages"].keys():
|
||||
if pkgd == cos:
|
||||
return pkgv["packages"][pkgd]
|
||||
return None
|
||||
|
||||
def _get_disturl(self, profile, version, cos):
|
||||
pkgname = self._get_pkgname(profile, version, cos)
|
||||
if pkgname is not None:
|
||||
return "/".join([self.DOWNLOAD_URL, version, pkgname])
|
||||
return None
|
||||
|
||||
def _install_from_dist(self, profile, version):
|
||||
print_console(f"[*] Installing {profile}@{version} package from binary dist")
|
||||
dist_name = host_distname()
|
||||
disturl = self._get_disturl(profile, version, dist_name)
|
||||
pkgname = self._get_pkgname(profile, version, dist_name)
|
||||
pkgfile = "/".join([self._r2env_path, "src", pkgname])
|
||||
try:
|
||||
wget.download(disturl, pkgfile)
|
||||
except (URLError, ConnectionResetError) as err:
|
||||
raise PackageManagerException(f"Failed to download {profile} package. Error: {err}") from err
|
||||
# TODO: check package checksum
|
||||
if dist_name in ("mac_x64", "mac_arm64"):
|
||||
return os.system(f"sudo installer -pkg {pkgfile} -target /") == 0
|
||||
if dist_name in "w64":
|
||||
return self._install_windows_package(pkgfile)
|
||||
if dist_name in ("deb_x64", "deb_i386"):
|
||||
return os.system(f"sudo dpkg -i {pkgfile}") == 0
|
||||
if dist_name in "android": # termux
|
||||
return os.system("apt install radare2") == 0
|
||||
raise PackageManagerException(f"Operative System not supported: {os.uname()}")
|
||||
|
||||
def _install_windows_package(self, pkgfile):
|
||||
try:
|
||||
with zipfile.ZipFile(pkgfile, 'r') as zip_file:
|
||||
zip_file.extractall()
|
||||
dst_folder = os.path.sep.join([self._r2env_path, "bin"])
|
||||
if not os.path.isdir(dst_folder):
|
||||
os.makedirs(dst_folder, 493) # 0755)
|
||||
for file_path in zip_file.namelist():
|
||||
if file_path.endswith(".exe") or file_path.endswith(".dll") and file_path.find("bin") != -1:
|
||||
file_name = os.path.basename(file_path)
|
||||
dst_filepath = os.path.sep.join([dst_folder, file_name])
|
||||
shutil.copyfile(file_path, dst_filepath)
|
||||
print_console(f"[-] Copying {file_path}")
|
||||
radare2_bin_file_path = os.path.sep.join([self._r2env_path, "bin", "radare2.exe"])
|
||||
r2_bin_file_path = os.path.sep.join([self._r2env_path, "bin", "r2.exe"])
|
||||
shutil.copyfile(radare2_bin_file_path, r2_bin_file_path)
|
||||
return True
|
||||
except (FileNotFoundError, IOError) as err:
|
||||
print_console(f"[x] An error occurred when installing {pkgfile}. Error: {err}", level=ERROR)
|
||||
self._uninstall_from_dist("radare2", "latest")
|
||||
raise PackageManagerException(f"Unable to install Windows package {pkgfile}.") from err
|
||||
|
||||
def _uninstall_from_dist(self, profile, version):
|
||||
print_console(f"[*] Cleaning {profile}@{version} package from binary dist")
|
||||
dist_name = host_distname()
|
||||
if dist_name in "w64":
|
||||
dst = os.path.sep.join([self._r2env_path, "bin"])
|
||||
print_console(f"[*] Removing {dst}")
|
||||
try:
|
||||
shutil.rmtree(dst)
|
||||
return True
|
||||
except OSError as err:
|
||||
raise PackageManagerException(f"An issue occurred while removing {dst}. Error: {err}") from err
|
||||
if dist_name in ("mac_x64", "mac_arm64"):
|
||||
result_code = 0
|
||||
pkgname = "org.radare.radare2"
|
||||
result_code += os.system("pkgutil --pkg-info " + pkgname)
|
||||
result_code += os.system(f"cd / && pkgutil --only-files --files {pkgname} | "
|
||||
f"tr '\\n' '\\0' | xargs -n 1 -0 sudo rm -f")
|
||||
result_code += os.system(f"cd / && pkgutil --only-dirs --files {pkgname} | "
|
||||
f"tail -r | tr '\\n' '\\0' | xargs -n 1 -0 sudo rmdir 2>/dev/null")
|
||||
result_code += os.system(f"sudo pkgutil --forget {pkgname}")
|
||||
return result_code == 0
|
||||
if dist_name in ("deb_x64", "deb_i386"):
|
||||
return os.system("sudo dpkg -r " + profile) == 0
|
||||
if dist_name in "android": # termux
|
||||
return os.system("sudo dpkg -r radare2") == 0
|
||||
raise PackageManagerException(f"Operative System not supported: {os.uname()}")
|
||||
|
||||
def _build_from_source(self, profile, version, source_path, dst_path, logfile, use_meson=False):
|
||||
exit_if_not_exists(['git'])
|
||||
print_console("[*] Installing {}@{} package from source".format(profile, version))
|
||||
print_console("[-] Cloning {} version".format(version))
|
||||
print_console(f"[*] Installing {profile}@{version} package from source")
|
||||
print_console(f"[-] Cloning {version} version")
|
||||
git_fetch(self._packages[profile]["source"], version, source_path)
|
||||
print_console("[-] Cleaning Repo")
|
||||
git_clean(source_path)
|
||||
if use_meson:
|
||||
return self._build_using_meson(source_path, dst_path, logfile)
|
||||
return self._build_using_acr(source_path, dst_path, logfile)
|
||||
return self._build_using_meson(source_path, dst_path, logfile, self._r2env_path)
|
||||
return self._build_using_acr(source_path, dst_path, logfile, self._r2env_path)
|
||||
|
||||
@staticmethod
|
||||
def _build_using_acr(source_path, dst_path, logfile):
|
||||
def _build_using_acr(source_path, dst_path, logfile, r2env_path):
|
||||
"""Only works in Unix systems"""
|
||||
if host_distname() is not None and host_distname() in "w64":
|
||||
raise PackageManagerException("acr is not supported on Windows platform. Use meson instead.")
|
||||
exit_if_not_exists(['make'])
|
||||
print_console("[-] Building package using acr for Termux...")
|
||||
print_console("[-] Building package using acr...")
|
||||
extra_flags = ""
|
||||
if os.path.isfile("/default.prop"):
|
||||
extra_flags = " --with-compiler=termux"
|
||||
cmd = "(cd {0} && rm -rf shlr/capstone && ./configure {1}" \
|
||||
" --with-rpath --prefix={2} 2>&1 && make -j4 2>&1" \
|
||||
"&& make install) > {3}".format(source_path, extra_flags, dst_path, logfile)
|
||||
config_path = r2env_path + "/lib/pkgconfig"
|
||||
cmd = f"(export PKG_CONFIG_PATH=\"{config_path}\";" \
|
||||
f"cd {source_path} && " \
|
||||
f"rm -rf shlr/capstone && " \
|
||||
f"./configure {extra_flags} --with-rpath --prefix={dst_path} 2>&1 && " \
|
||||
f"make -j4 2>&1 && " \
|
||||
f"make install) > {logfile}"
|
||||
print_console(f"Executing {cmd}")
|
||||
return os.system(cmd) == 0
|
||||
|
||||
@staticmethod
|
||||
def _build_using_meson(source_path, dst_path, logfile):
|
||||
def _build_using_meson(source_path, dst_path, logfile, r2env_path):
|
||||
exit_if_not_exists(['meson', 'ninja'])
|
||||
print_console("[-] Building package using meson ...")
|
||||
cmd = "(cd {0} && rm -rf build && meson . build --buildtype=release --prefix={1} -Dlocal=true 2>&1" \
|
||||
"&& ninja -C build && ninja -C build install) > {2}".format(source_path, dst_path, logfile)
|
||||
config_path = r2env_path + "/lib/pkgconfig"
|
||||
# TODO: ensure source_path logfile or dst_path have no spaces
|
||||
cmd = f"(export PKG_CONFIG_PATH=\"{config_path}\";" \
|
||||
f"cd \"{source_path}\" && rm -rf build && " \
|
||||
f"meson build --buildtype=release --prefix={dst_path} -Dlocal=true 2>&1 && " \
|
||||
f"ninja -C build && " \
|
||||
f"ninja -C build install) > {logfile} && " \
|
||||
f"for a in {dst_path}/bin/* ; do install_name_tool -add_rpath {dst_path}/lib $a ; done"
|
||||
print_console(f"Executing {cmd}")
|
||||
return os.system(cmd) == 0
|
||||
|
||||
def _exit_if_package_not_available(self, profile, version):
|
||||
pkg_found = False
|
||||
for available_version in self._packages[profile]["versions"]:
|
||||
if available_version['id'] == version:
|
||||
pkg_found = True
|
||||
break
|
||||
if not pkg_found:
|
||||
print_console("{}@{} package not available. Use 'list' command to see available packages."
|
||||
.format(profile, version), level=ERROR)
|
||||
sys.exit(-1)
|
||||
def _if_package_not_available(self, profile, version):
|
||||
if profile in self._packages:
|
||||
for available_version in self._packages[profile]["versions"]:
|
||||
if available_version['id'] == version:
|
||||
return False
|
||||
return True
|
||||
+100
-67
@@ -3,93 +3,126 @@
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from r2env.exceptions import ActionException, R2EnvException, PackageManagerException
|
||||
from r2env.tools import print_console, ERROR
|
||||
from r2env.core import R2Env
|
||||
|
||||
|
||||
HELP_MESSAGE = """
|
||||
Usage: r2env [action] [args...]
|
||||
Actions:
|
||||
class REPL:
|
||||
HELP_MESSAGE = """
|
||||
Usage: r2env [-flags] [action] [args...]
|
||||
|
||||
init - create .r2env in current directory
|
||||
config - display current .r2env settings
|
||||
install [pkg] - build and install given package. Use --meson to use it as the build system.
|
||||
uninstall [pkg] - remove selected package
|
||||
use [pkg] - use r2 package defined. pkg should be a release version or latest.
|
||||
path - show path of current r2 in use
|
||||
version - show version of r2env
|
||||
versions - List all Radare versions installed
|
||||
list - list all Radare packages available to r2env
|
||||
shell - open a new shell with PATH env var set
|
||||
Flags:
|
||||
|
||||
"""
|
||||
-h, --help - show this help.
|
||||
-v, --version - display r2env version.
|
||||
-m, --meson - use meson instead of acr.
|
||||
-p, --package - install the dist package instead of building
|
||||
-l, --list - list available and installed packages
|
||||
|
||||
Actions:
|
||||
|
||||
def show_help():
|
||||
print_console(HELP_MESSAGE)
|
||||
init - create ~/.r2env directory.
|
||||
config - display current .r2env settings.
|
||||
add [pkg] - build and install given package. See -p and -m
|
||||
use [pkg] - stow a specific version to be the default.
|
||||
rm [pkg] - remove package from ~/.r2env
|
||||
path - show path of current r2 in use.
|
||||
list - list all packages available to r2env.
|
||||
shell - enter a new shell with PATH env var set.
|
||||
purge - remove ~/.r2env
|
||||
update - update list of available profiles
|
||||
|
||||
Environment
|
||||
|
||||
def show_version():
|
||||
print_console(R2Env().version())
|
||||
R2ENV_PATH - specify different path other than ~/.r2env
|
||||
|
||||
"""
|
||||
|
||||
actions_with_argument = ["install", "uninstall", "use"]
|
||||
actions_with_arguments = ["shell"]
|
||||
actions = {
|
||||
"init": R2Env().init,
|
||||
"version": show_version,
|
||||
"path": R2Env().get_r2_path,
|
||||
"config": R2Env().show_config,
|
||||
"list": R2Env().list_available_packages,
|
||||
"install": R2Env().install,
|
||||
"shell": R2Env().shell,
|
||||
"uninstall": R2Env().uninstall,
|
||||
"use": R2Env().use,
|
||||
"versions": R2Env().list_installed_packages,
|
||||
"help": show_help
|
||||
}
|
||||
def __init__(self):
|
||||
self.actions_with_arguments = ["add", "install", "rm", "uninstall", "use"]
|
||||
self._core = R2Env()
|
||||
self.actions = {
|
||||
"init": self._core.init,
|
||||
"v": self._core.version,
|
||||
"version": self._core.version,
|
||||
"path": self._core.get_r2_path,
|
||||
"sh": self._core.shell,
|
||||
"shell": self._core.shell,
|
||||
"config": self._core.show_config,
|
||||
"ls": self._core.list_packages,
|
||||
"list": self._core.list_packages,
|
||||
"add": self._core.install,
|
||||
"install": self._core.install,
|
||||
"installed": self._core.list_installed_packages,
|
||||
"uninstall": self._core.uninstall,
|
||||
"update": self._core.update_version_profiles,
|
||||
"rm": self._core.uninstall,
|
||||
"use": self._core.use,
|
||||
"purge": self._core.purge,
|
||||
"h": self.show_help,
|
||||
"help": self.show_help
|
||||
}
|
||||
|
||||
def show_help(self):
|
||||
print_console(self.HELP_MESSAGE)
|
||||
|
||||
def run_action(action, args, use_meson):
|
||||
if action == "":
|
||||
show_help()
|
||||
elif action not in actions:
|
||||
print_console("[X] Action not found", ERROR)
|
||||
elif action in actions_with_arguments:
|
||||
actions[action](" ".join(args))
|
||||
elif action in actions_with_argument:
|
||||
exit_if_not_argument_is_set(args, action)
|
||||
if action == "install":
|
||||
actions[action](args[0], use_meson=use_meson)
|
||||
def run_action(self, action_args): # noqa: C901
|
||||
args = []
|
||||
if not action_args:
|
||||
self.show_help()
|
||||
raise ActionException("No action selected")
|
||||
if action_args.version:
|
||||
self.actions["version"]()
|
||||
return
|
||||
if action_args.list:
|
||||
list_method = self.actions["list"]
|
||||
list_method()
|
||||
if len(action_args.args) == 0:
|
||||
self.show_help()
|
||||
raise ActionException("No action selected")
|
||||
if len(action_args.args) > 1:
|
||||
args = action_args.args[1:]
|
||||
action = action_args.args[0]
|
||||
if action not in self.actions:
|
||||
raise ActionException("Invalid action selected")
|
||||
if len(args) < 1 and action in self.actions_with_arguments:
|
||||
if action in ["add", "install"]:
|
||||
self._core.list_packages()
|
||||
if action in ["use", "rm", "uninstall"]:
|
||||
self._core.list_installed_packages()
|
||||
raise ActionException(f"Action {action} requires a package as an argument.")
|
||||
if action in self.actions_with_arguments:
|
||||
self.actions[action](args[0], use_meson=action_args.meson, use_dist=action_args.package)
|
||||
elif action in "shell" and len(args) > 0:
|
||||
self.actions[action](args[0])
|
||||
else:
|
||||
actions[action](args[0])
|
||||
else:
|
||||
actions[action]()
|
||||
|
||||
|
||||
def exit_if_not_argument_is_set(args, action):
|
||||
if len(args) < 1:
|
||||
if action == "use":
|
||||
print_console("[x] Package not defined. Please use 'r2env use' with one installed package. ", ERROR)
|
||||
actions["versions"]()
|
||||
else:
|
||||
print_console("[x] Missing package argument. ( as for example: radare2@latest)", ERROR)
|
||||
print_console("[x] Missing package argument. ( as for example: radare2@latest)", ERROR)
|
||||
sys.exit(-1)
|
||||
self.actions[action]()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("action", help="run specified action. (Run r2env help for more information)",
|
||||
action="store", default=["help"])
|
||||
parser.add_argument('args', metavar='args', nargs='*', type=str, help='Specified arguments')
|
||||
parser.add_argument("args", help="run specified action. (Run r2env help for more information)",
|
||||
action="store", nargs="*", default=[])
|
||||
# parser.add_argument('args', metavar='args', nargs='+', type=str, help='Specified arguments')
|
||||
parser.add_argument("-v", "--version", dest="version", help="Show r2env version", action="store_true")
|
||||
parser.add_argument("-m", "--meson", dest="meson", help="Use meson as your build system.", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if args.version:
|
||||
print_console(R2Env().version())
|
||||
return
|
||||
run_action(args.action, args.args, args.meson)
|
||||
parser.add_argument("-m", "--meson", dest="meson", help="Use meson instead of acr to compile", action="store_true")
|
||||
parser.add_argument("-p", "--package", dest="package", help="Use binary package for target system if available",
|
||||
action="store_true")
|
||||
parser.add_argument("-l", "--list", dest="list", help="List available and installed packages", action="store_true")
|
||||
parser.print_help = REPL().show_help
|
||||
action_args = parser.parse_args()
|
||||
try:
|
||||
REPL().run_action(action_args)
|
||||
except ActionException as err:
|
||||
print_console(f"[x] Parameter error. Details: {err}", level=ERROR)
|
||||
sys.exit(-1)
|
||||
except PackageManagerException as err:
|
||||
print_console(f"[x] Package Error: {err}", level=ERROR)
|
||||
sys.exit(-1)
|
||||
except R2EnvException as err:
|
||||
print_console(f"[x] r2Env Error: {err}", level=ERROR)
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
from doublex import assert_that
|
||||
from hamcrest import equal_to
|
||||
from mock import patch
|
||||
import unittest
|
||||
|
||||
from r2env.core import R2Env
|
||||
from r2env.exceptions import R2EnvException
|
||||
|
||||
|
||||
class TestCore(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.packages_dir = ["5.3.0"]
|
||||
|
||||
self.profiles = {
|
||||
"radare2": {
|
||||
"source": "https://github.com/radareorg/radare2",
|
||||
"versions": [
|
||||
{
|
||||
"id": "5.3.0",
|
||||
"packages": {
|
||||
"w64": "radare2-5.3.0-w64.zip",
|
||||
"deb_x64": "radare2_5.3.0_amd64.deb"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
patch.stopall()
|
||||
|
||||
@patch("r2env.core.R2Env._get_default_path")
|
||||
def test_default_config(self, mock_default_path):
|
||||
_ = R2Env()
|
||||
mock_default_path.assert_called()
|
||||
|
||||
@patch("r2env.core.load_json_file")
|
||||
def test_custom_config_using_json_file(self, mock_load_json_file):
|
||||
custom_r2_path = "custom_r2_path"
|
||||
mock_load_json_file.return_value = {"r2env_path": "custom_r2_path"}
|
||||
r2env = R2Env()
|
||||
assert_that(r2env._r2env_path, equal_to(custom_r2_path))
|
||||
|
||||
@patch("os.getenv")
|
||||
def test_custom_config_using_envvar(self, mock_getenv):
|
||||
custom_r2_path = "custom_r2_path"
|
||||
mock_getenv.return_value = custom_r2_path
|
||||
r2env = R2Env()
|
||||
assert_that(r2env._r2env_path, equal_to(custom_r2_path))
|
||||
|
||||
@patch("os.mkdir")
|
||||
@patch("os.path.isdir")
|
||||
def test_init_failed(self, mock_isdir, mock_mkdir):
|
||||
mock_isdir.return_value = True
|
||||
R2Env().init()
|
||||
mock_mkdir.assert_not_called()
|
||||
|
||||
@patch("os.mkdir")
|
||||
@patch("os.path.isdir")
|
||||
def test_init_successfully(self, mock_isdir, mock_mkdir):
|
||||
mock_isdir.return_value = False
|
||||
r2env= R2Env()
|
||||
r2env.init()
|
||||
mock_mkdir.assert_called_with(r2env._r2env_path)
|
||||
|
||||
@patch("os.path.isdir")
|
||||
def test_check_if_r2env_not_initialized(self, mock_isdir):
|
||||
mock_isdir.return_value = False
|
||||
with self.assertRaises(R2EnvException):
|
||||
R2Env().check_if_r2env_initialized()
|
||||
|
||||
@patch("r2env.core.print_console")
|
||||
@patch("r2env.core.PackageManager.list_available_packages")
|
||||
def test_list_available_pkg_successfully(self, mock_list_pkg, mock_print_console):
|
||||
mock_list_pkg.return_value = self.profiles
|
||||
R2Env().list_available_packages()
|
||||
mock_print_console.assert_called_with(" - [email protected] - w64, deb_x64", formatter=1)
|
||||
|
||||
@patch("r2env.core.R2Env._get_current_version")
|
||||
@patch("r2env.core.print_console")
|
||||
@patch("os.path.isdir")
|
||||
@patch("r2env.core.PackageManager.list_installed_packages")
|
||||
def test_list_installed_pkg_successfully(self, mock_list_pkg, mock_isdir, mock_print, mock_current):
|
||||
mock_list_pkg.return_value = self.packages_dir
|
||||
mock_isdir.return_value = True
|
||||
R2Env().list_installed_packages()
|
||||
mock_print.assert_called_with(" - 5.3.0")
|
||||
mock_current.return_value = "5.3.0"
|
||||
R2Env().list_installed_packages()
|
||||
mock_print.assert_called_with(" - 5.3.0 (in use)")
|
||||
|
||||
def test_check_package_format(self):
|
||||
r2env = R2Env()
|
||||
assert_that(r2env._check_package_format("radare2@git"), equal_to(True))
|
||||
assert_that(r2env._check_package_format("[email protected]"), equal_to(True))
|
||||
assert_that(r2env._check_package_format("[email protected]"), equal_to(False))
|
||||
assert_that(r2env._check_package_format("[email protected]"), equal_to(False))
|
||||
assert_that(r2env._check_package_format("radare2git"), equal_to(False))
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.install_package")
|
||||
def test_install_successfully_default(self, mock_pkg_install, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "radare2"
|
||||
version = "5.3.0"
|
||||
R2Env().install(f"{package}@{version}")
|
||||
mock_pkg_install.assert_called_with(package, version, use_meson=False, use_dist=False)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.install_package")
|
||||
def test_install_successfully_meson(self, mock_pkg_install, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "radare2"
|
||||
version = "5.3.0"
|
||||
R2Env().install(f"{package}@{version}", use_meson=True)
|
||||
mock_pkg_install.assert_called_with(package, version, use_meson=True, use_dist=False)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.install_package")
|
||||
def test_install_successfully_dist(self, mock_pkg_install, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "radare2"
|
||||
version = "5.3.0"
|
||||
R2Env().install(f"{package}@{version}", use_dist=True)
|
||||
mock_pkg_install.assert_called_with(package, version, use_meson=False, use_dist=True)
|
||||
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_install_successfully_failed(self, mock_initialized):
|
||||
mock_initialized.return_value = True
|
||||
package = "radare2@"
|
||||
version = ""
|
||||
with self.assertRaises(R2EnvException):
|
||||
R2Env().install(f"{package}{version}", use_dist=True)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.install_package")
|
||||
def test_install_successfully_failed_with_default(self, mock_pkg_install, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "radare2"
|
||||
R2Env().install(package)
|
||||
mock_pkg_install.assert_called_with(package, "git", use_meson=False, use_dist=False)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.uninstall_package")
|
||||
def test_uninstall_successfully_default(self, mock_pkg_uninstall, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "[email protected]"
|
||||
R2Env().uninstall(package)
|
||||
mock_pkg_uninstall.assert_called_with(package, False)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
@patch("r2env.core.PackageManager.uninstall_package")
|
||||
def test_uninstall_successfully_dist(self, mock_pkg_uninstall, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = True
|
||||
package = "[email protected]"
|
||||
R2Env().uninstall(package, use_dist=True)
|
||||
mock_pkg_uninstall.assert_called_with(package, True)
|
||||
|
||||
@patch("r2env.core.R2Env._check_package_format")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_uninstall_failed(self, mock_initialized, mock_valid_format):
|
||||
mock_initialized.return_value = True
|
||||
mock_valid_format.return_value = False
|
||||
package = "[email protected]"
|
||||
with self.assertRaises(R2EnvException):
|
||||
R2Env().uninstall(package, use_dist=True)
|
||||
|
||||
@patch("shutil.rmtree")
|
||||
def test_purge(self, mock_rmtree):
|
||||
r2env = R2Env()
|
||||
r2env.purge()
|
||||
mock_rmtree.assert_called_with(r2env._r2env_path)
|
||||
|
||||
|
||||
@patch("r2env.core.PackageManager.list_installed_packages")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_use_package_not_installed(self, mock_initialized, mock_list_pkg):
|
||||
package = "radare2@not_existing"
|
||||
mock_list_pkg.return_value = ["[email protected]"]
|
||||
mock_initialized.return_value = True
|
||||
r2env = R2Env()
|
||||
with self.assertRaises(R2EnvException):
|
||||
r2env.use(package)
|
||||
|
||||
@patch("r2env.core.PackageManager.list_installed_packages")
|
||||
@patch("r2env.core.PackageManager.get_package_path")
|
||||
@patch("r2env.core.unstow")
|
||||
@patch("r2env.core.stow")
|
||||
@patch("r2env.core.R2Env._set_current_version")
|
||||
@patch("r2env.core.R2Env._get_current_version")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_use_successfully(self, mock_initialized, mock_get_cur_ver, mock_set_cur_ver, mock_stow, mock_unstow,
|
||||
mock_pkg_path, mock_list_pkg):
|
||||
package = "[email protected]"
|
||||
mock_initialized.return_value = True
|
||||
mock_get_cur_ver.return_value = "5.3.0"
|
||||
mock_list_pkg.return_value = ["[email protected]"]
|
||||
new_path = f"new_path/{package}"
|
||||
curr_path = f"new_path/old_package"
|
||||
mock_pkg_path.side_effect = [new_path, curr_path]
|
||||
r2env = R2Env()
|
||||
r2env.use(package)
|
||||
mock_set_cur_ver.assert_called_once_with(package)
|
||||
mock_stow.assert_called_once_with([new_path], r2env._r2env_path)
|
||||
mock_unstow.assert_called_once_with([curr_path], r2env._r2env_path)
|
||||
|
||||
@patch("r2env.core.PackageManager.list_installed_packages")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_use_with_no_none_package(self, mock_initialized, mock_list_pkg):
|
||||
mock_initialized.return_value = True
|
||||
r2env = R2Env()
|
||||
with self.assertRaises(R2EnvException):
|
||||
r2env.use(None)
|
||||
mock_list_pkg.assert_called_once()
|
||||
|
||||
@patch("r2env.core.PackageManager.list_installed_packages")
|
||||
@patch("r2env.core.R2Env.check_if_r2env_initialized")
|
||||
def test_use_with_no_package(self, mock_initialized, mock_list_pkg):
|
||||
mock_initialized.return_value = True
|
||||
r2env = R2Env()
|
||||
with self.assertRaises(R2EnvException):
|
||||
r2env.use()
|
||||
mock_list_pkg.assert_called_once()
|
||||
|
||||
|
||||
@patch("r2env.core.PackageManager")
|
||||
@patch("r2env.core.os.path.join")
|
||||
@patch("r2env.core.host_platform")
|
||||
@patch("r2env.core.os.system")
|
||||
@patch("r2env.core.load_json_file")
|
||||
def test_shell_windows(self, mock_load_json_file, mock_system, mock_host_platform, mock_join, _):
|
||||
def side_effect(path1, path2, *args):
|
||||
return f"{path1}\\{path2}"
|
||||
r2env_path = "c:\\windows\\temp\\r2env\\"
|
||||
mock_join.side_effect = side_effect
|
||||
mock_host_platform.return_value = "windows"
|
||||
mock_load_json_file.return_value = {"r2env_path": r2env_path}
|
||||
cmd = "r2 -v"
|
||||
R2Env().shell(cmd)
|
||||
mock_system.assert_called_with(f"set PATH={r2env_path}\\bin;%PATH% && cmd")
|
||||
|
||||
@patch("r2env.core.host_platform")
|
||||
@patch("r2env.core.os.system")
|
||||
@patch("r2env.core.load_json_file")
|
||||
def test_shell_android(self, mock_load_json_file, mock_system, mock_host_platform):
|
||||
mock_host_platform.return_value = "android"
|
||||
r2env_path = "/tmp/r2env"
|
||||
mock_load_json_file.return_value = {"r2env_path": r2env_path}
|
||||
cmd = "r2 -v"
|
||||
R2Env().shell(cmd)
|
||||
mock_system.assert_called_with(f"export LD_LIBRARY_PATH=\"{r2env_path}/lib\";"
|
||||
f"export PS1=\"r2env ()\\$ \";"
|
||||
f"export PKG_CONFIG_PATH=\"{r2env_path}/lib/pkgconfig\";"
|
||||
f"export PATH=\"{r2env_path}/bin:$PATH\";"
|
||||
f"$SHELL -f -c \'{cmd}\'")
|
||||
|
||||
@patch("r2env.core.host_platform")
|
||||
@patch("r2env.core.os.system")
|
||||
@patch("r2env.core.load_json_file")
|
||||
def test_shell_osx(self, mock_load_json_file, mock_system, mock_host_platform):
|
||||
mock_host_platform.return_value = "osx"
|
||||
r2env_path = "/tmp/r2env"
|
||||
mock_load_json_file.return_value = {"r2env_path": r2env_path}
|
||||
cmd = "r2 -v"
|
||||
R2Env().shell(cmd)
|
||||
mock_system.assert_called_with(f"export DYLD_LIBRARY_PATH=\"{r2env_path}/lib\";"
|
||||
f"export PS1=\"r2env ()\\$ \";"
|
||||
f"export PKG_CONFIG_PATH=\"{r2env_path}/lib/pkgconfig\";"
|
||||
f"export PATH=\"{r2env_path}/bin:$PATH\";"
|
||||
f"$SHELL -f -c \'{cmd}\'")
|
||||
|
||||
@patch("r2env.core.host_platform")
|
||||
@patch("r2env.core.os.system")
|
||||
@patch("r2env.core.load_json_file")
|
||||
def test_shell_linux(self, mock_load_json_file, mock_system, mock_host_platform):
|
||||
mock_host_platform.return_value = "linux"
|
||||
r2env_path = "/tmp/r2env"
|
||||
mock_load_json_file.return_value = {"r2env_path": r2env_path}
|
||||
cmd = "r2 -v"
|
||||
R2Env().shell(cmd)
|
||||
mock_system.assert_called_with(f"export PS1=\"r2env ()\\$ \";"
|
||||
f"export PKG_CONFIG_PATH=\"{r2env_path}/lib/pkgconfig\";"
|
||||
f"export PATH=\"{r2env_path}/bin:$PATH\";"
|
||||
f"$SHELL -f -c \'{cmd}\'")
|
||||
Whitespace-only changes.
@@ -0,0 +1,403 @@
|
||||
import os
|
||||
from unittest.mock import MagicMock
|
||||
from urllib.error import URLError
|
||||
|
||||
from doublex import assert_that
|
||||
from hamcrest import equal_to
|
||||
from mock import patch
|
||||
import unittest
|
||||
|
||||
from r2env.exceptions import PackageManagerException
|
||||
from r2env.package_manager import PackageManager
|
||||
|
||||
|
||||
class TestPackageManager(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.profile = "radare2"
|
||||
self.version = "5.3.0"
|
||||
self.profiles = {
|
||||
self.profile: {
|
||||
"source": "https://github.com/radareorg/radare2",
|
||||
"versions": [
|
||||
{
|
||||
"id": self.version,
|
||||
"packages": {
|
||||
"w64": "radare2-5.3.0-w64.zip",
|
||||
"deb_x64": "radare2_5.3.0_amd64.deb"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
self.load_json_mock = patch("r2env.package_manager.load_json_file").start()
|
||||
self.load_json_mock.return_value = self.profiles
|
||||
self.default_r2env_path = "/tmp/r2env"
|
||||
self.package_manager = PackageManager(self.default_r2env_path)
|
||||
|
||||
def tearDown(self):
|
||||
patch.stopall()
|
||||
|
||||
def test_constructor(self):
|
||||
assert_that(self.package_manager._packages, equal_to(self.profiles))
|
||||
assert_that(self.package_manager._r2env_path, equal_to(self.default_r2env_path))
|
||||
|
||||
def test_constructor_with_no_profiles(self):
|
||||
self.load_json_mock.return_value = []
|
||||
with self.assertRaises(PackageManagerException):
|
||||
PackageManager(self.default_r2env_path)
|
||||
|
||||
def test_get_package_path(self):
|
||||
package_name = "test"
|
||||
package_path = self.package_manager.get_package_path(package_name)
|
||||
assert_that(package_path, equal_to(os.path.join(self.default_r2env_path, "versions", package_name)))
|
||||
|
||||
def test_list_available_packages(self):
|
||||
assert_that(self.package_manager.list_available_packages(), equal_to(self.profiles))
|
||||
|
||||
@patch("r2env.package_manager.os")
|
||||
def test_list_installed_packages(self, os_mock):
|
||||
packages = ["PKG1", "PKG2", "PKG3"]
|
||||
os_mock.path.isdir.return_value = True
|
||||
os_mock.listdir.return_value = packages
|
||||
assert_that(self.package_manager.list_installed_packages(), equal_to(packages))
|
||||
|
||||
@patch("r2env.package_manager.os.makedirs")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_with_no_log_path(self, mock_isdir, mock_makedirs):
|
||||
patch("r2env.package_manager.PackageManager._build_from_source").start()
|
||||
patch("r2env.package_manager.PackageManager._install_from_dist").start()
|
||||
mock_isdir.side_effect = [False, True, True]
|
||||
self.package_manager.install_package(self.profile, self.version, True, True)
|
||||
mock_makedirs.assert_called_once()
|
||||
|
||||
@patch("r2env.package_manager.os.makedirs")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_with_no_source_path(self, mock_isdir, mock_makedirs):
|
||||
patch("r2env.package_manager.PackageManager._build_from_source").start()
|
||||
patch("r2env.package_manager.PackageManager._install_from_dist").start()
|
||||
mock_isdir.side_effect = [True, False, True]
|
||||
self.package_manager.install_package(self.profile, self.version, True, True)
|
||||
source_path = os.path.join(os.path.join(self.package_manager._r2env_path,
|
||||
self.package_manager.SOURCE_DIR, self.profile))
|
||||
mock_makedirs.assert_called_once_with(source_path)
|
||||
|
||||
@patch("r2env.package_manager.os.makedirs")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_with_no_dstdir(self, mock_isdir, mock_makedirs):
|
||||
patch("r2env.package_manager.PackageManager._build_from_source").start()
|
||||
patch("r2env.package_manager.PackageManager._install_from_dist").start()
|
||||
mock_isdir.side_effect = [True, True, False]
|
||||
self.package_manager.install_package(self.profile, self.version, True, True)
|
||||
dst_dir = os.path.join(self.package_manager._r2env_path,
|
||||
self.package_manager.PACKAGES_DIR,
|
||||
f"{self.profile}@{self.version}")
|
||||
mock_makedirs.assert_called_once_with(dst_dir)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._install_from_dist")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_from_dist_success(self, mock_isdir,
|
||||
mock_dist):
|
||||
mock_isdir.return_value = True
|
||||
mock_dist.return_value = True
|
||||
self.package_manager.install_package(self.profile, self.version, True, True)
|
||||
mock_dist.assert_called_once_with(self.profile, self.version)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._install_from_dist")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_from_dist_failed(self, mock_isdir,
|
||||
mock_dist):
|
||||
mock_isdir.return_value = True
|
||||
mock_dist.return_value = False
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager.install_package(self.profile, self.version, True, True)
|
||||
mock_dist.assert_called_once_with(self.profile, self.version)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._build_from_source")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_from_build_success(self, mock_isdir,
|
||||
mock_build):
|
||||
mock_isdir.return_value = True
|
||||
mock_build.return_value = True
|
||||
self.package_manager.install_package(self.profile, self.version, True, False)
|
||||
mock_build.assert_called_once()
|
||||
|
||||
@patch("r2env.package_manager.shutil.rmtree")
|
||||
@patch("r2env.package_manager.PackageManager._build_from_source")
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_package_from_build_failed(self, mock_isdir,
|
||||
mock_build, mock_rmtree):
|
||||
mock_isdir.return_value = True
|
||||
mock_build.return_value = False
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager.install_package(self.profile, self.version, True, False)
|
||||
mock_build.assert_called_once()
|
||||
mock_rmtree.assert_called_once()
|
||||
|
||||
@patch("r2env.package_manager.PackageManager.list_installed_packages")
|
||||
@patch("r2env.package_manager.PackageManager._uninstall_from_dist")
|
||||
def test_uninstall_package_from_dist_successfully(self, mock_uninstall, mock_list_pkg):
|
||||
mock_list_pkg.return_value = ["[email protected]", "[email protected]"]
|
||||
profile = "radare2"
|
||||
version = "2.0.0"
|
||||
package = f"{profile}@{version}"
|
||||
self.package_manager.uninstall_package(package, True)
|
||||
mock_uninstall.assert_called_once_with(profile, version)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager.list_installed_packages")
|
||||
@patch("r2env.package_manager.shutil.rmtree")
|
||||
def test_uninstall_package_from_build_successfully(self, mock_rmtree, mock_list_pkg):
|
||||
mock_list_pkg.return_value = ["[email protected]", "[email protected]"]
|
||||
package = "[email protected]"
|
||||
self.package_manager.uninstall_package(package, False)
|
||||
pkg_dir = os.path.join(self.package_manager._r2env_path,
|
||||
self.package_manager.PACKAGES_DIR,
|
||||
package)
|
||||
mock_rmtree.assert_called_once_with(pkg_dir)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager.list_installed_packages")
|
||||
@patch("r2env.package_manager.shutil.rmtree")
|
||||
def test_uninstall_package_from_build_failed(self, mock_rmtree, mock_list_pkg):
|
||||
mock_list_pkg.return_value = ["[email protected]", "[email protected]"]
|
||||
package = "[email protected]"
|
||||
mock_rmtree.side_effect = OSError("fail")
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager.uninstall_package(package, False)
|
||||
|
||||
@patch("r2env.package_manager.PackageManager.list_installed_packages")
|
||||
def test_uninstall_package_not_found(self, mock_list_pkg):
|
||||
mock_list_pkg.return_value = ["[email protected]"]
|
||||
package = "[email protected]"
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager.uninstall_package(package, False)
|
||||
|
||||
def test_get_pkgname_success(self):
|
||||
target_pkg = "radare2-5.3.1-w64.zip"
|
||||
target_os = "w64"
|
||||
target_version = "5.3.1"
|
||||
packages_mock = {"radare2": {
|
||||
"versions": [
|
||||
{
|
||||
"id": "5.3.0",
|
||||
"packages": {
|
||||
"w64": "radare2-5.3.0-w64.zip",
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": target_version,
|
||||
"packages": {
|
||||
target_os: target_pkg,
|
||||
"mac_x64": "radare2-5.3.1.pkg",
|
||||
}
|
||||
}]
|
||||
}}
|
||||
self.package_manager._packages = packages_mock
|
||||
assert_that(self.package_manager._get_pkgname("radare2", target_version, target_os), equal_to(target_pkg))
|
||||
|
||||
def test_get_pkgname_failed(self):
|
||||
target_os = "w64"
|
||||
target_version = "5.3.1"
|
||||
packages_mock = {"radare2": {
|
||||
"versions": [
|
||||
{
|
||||
"id": "5.3.0",
|
||||
"packages": {
|
||||
"w64": "radare2-5.3.0-w64.zip",
|
||||
}
|
||||
},
|
||||
]
|
||||
}}
|
||||
self.package_manager._packages = packages_mock
|
||||
assert_that(self.package_manager._get_pkgname("radare2", target_version, target_os), equal_to(None))
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
def test_get_disturl_success(self, mock_getpkg):
|
||||
target_pkg = "radare2-5.3.1-w64.zip"
|
||||
version = "5.2.0"
|
||||
mock_getpkg.return_value = target_pkg
|
||||
dist_url = self.package_manager._get_disturl("mock_profile", version, "mock_cos")
|
||||
expected_url = "/".join([self.package_manager.DOWNLOAD_URL, version, target_pkg])
|
||||
assert_that(dist_url, equal_to(expected_url))
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
def test_get_disturl_failed(self, mock_getpkg):
|
||||
target_pkg = None
|
||||
mock_getpkg.return_value = target_pkg
|
||||
dist_url = self.package_manager._get_disturl("mock_profile", "mock_version", "mock_cos")
|
||||
assert_that(dist_url, equal_to(None))
|
||||
|
||||
@patch("r2env.package_manager.wget")
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
@patch("r2env.package_manager.PackageManager._get_disturl")
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_install_from_dist_wget_is_called(self, mock_host_distname,
|
||||
mock__get_disturl,
|
||||
mock__get_pkgname,
|
||||
mock_wget):
|
||||
patch("r2env.package_manager.os.system").start()
|
||||
pkgname = "radare2-5.3.1-w64.zip"
|
||||
disturl = "http://example.org"
|
||||
pkgfile = "/".join([self.package_manager._r2env_path, "src", pkgname])
|
||||
mock__get_pkgname.return_value = pkgname
|
||||
mock__get_disturl.return_value = disturl
|
||||
mock_host_distname.return_value = "mac_arm64"
|
||||
profile = "radare2"
|
||||
version = "5.6.0"
|
||||
self.package_manager._install_from_dist(profile, version)
|
||||
mock_wget.download.assert_called_once_with(disturl, pkgfile)
|
||||
|
||||
@patch("r2env.package_manager.wget")
|
||||
def test_install_from_dist_wget_error_url(self, mock_wget):
|
||||
pkgname_mock = patch("r2env.package_manager.PackageManager._get_pkgname").start()
|
||||
get_disturl_mock = patch("r2env.package_manager.PackageManager._get_disturl").start()
|
||||
pkgname_mock.return_value = "radare2-5.3.1-w64.zip"
|
||||
get_disturl_mock.return_value = "http://example.org"
|
||||
mock_wget.download.side_effect = URLError("error")
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._install_from_dist("profile", "version")
|
||||
|
||||
@patch("r2env.package_manager.wget")
|
||||
def test_install_from_dist_wget_error_connection(self, mock_wget):
|
||||
pkgname_mock = patch("r2env.package_manager.PackageManager._get_pkgname").start()
|
||||
get_disturl_mock = patch("r2env.package_manager.PackageManager._get_disturl").start()
|
||||
pkgname_mock.return_value = "radare2-5.3.1-w64.zip"
|
||||
get_disturl_mock.return_value = "http://example.org"
|
||||
mock_wget.download.side_effect = ConnectionResetError("error")
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._install_from_dist("profile", "version")
|
||||
|
||||
@patch("r2env.package_manager.wget")
|
||||
def test_install_from_dist_wget_error_connection(self, mock_wget):
|
||||
pkgname_mock = patch("r2env.package_manager.PackageManager._get_pkgname").start()
|
||||
get_disturl_mock = patch("r2env.package_manager.PackageManager._get_disturl").start()
|
||||
pkgname_mock.return_value = "radare2-5.3.1-w64.zip"
|
||||
get_disturl_mock.return_value = "http://example.org"
|
||||
mock_wget.download.side_effect = ConnectionResetError("error")
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._install_from_dist("profile", "version")
|
||||
|
||||
@patch("r2env.package_manager.os.system")
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
@patch("r2env.package_manager.PackageManager._get_disturl")
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_install_from_dist_mac(self, mock_host_distname,
|
||||
mock__get_disturl,
|
||||
mock__get_pkgname,
|
||||
mock_system):
|
||||
pkgname = "radare2-5.3.1-mac.pkg"
|
||||
pkgfile = "/".join([self.package_manager._r2env_path, "src", pkgname])
|
||||
mock__get_pkgname.return_value = pkgname
|
||||
mock__get_disturl.return_value = "http://example.org"
|
||||
mock_host_distname.return_value = "mac_arm64"
|
||||
profile = "radare2"
|
||||
version = "5.6.0"
|
||||
patch("r2env.package_manager.wget.download").start()
|
||||
mock_system.return_value = 0
|
||||
assert_that(self.package_manager._install_from_dist(profile, version), equal_to(True))
|
||||
mock_system.assert_called_once_with(f"sudo installer -pkg {pkgfile} -target /")
|
||||
|
||||
@patch("r2env.package_manager.os.system")
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
@patch("r2env.package_manager.PackageManager._get_disturl")
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_install_from_dist_linux_deb(self, mock_host_distname,
|
||||
mock__get_disturl,
|
||||
mock__get_pkgname,
|
||||
mock_system):
|
||||
pkgname = "radare2-5.3.1-linux.deb"
|
||||
pkgfile = "/".join([self.package_manager._r2env_path, "src", pkgname])
|
||||
mock__get_pkgname.return_value = pkgname
|
||||
mock__get_disturl.return_value = "http://example.org"
|
||||
mock_host_distname.return_value = "deb_x64"
|
||||
profile = "radare2"
|
||||
version = "5.6.0"
|
||||
patch("r2env.package_manager.wget.download").start()
|
||||
mock_system.return_value = 0
|
||||
assert_that(self.package_manager._install_from_dist(profile, version), equal_to(True))
|
||||
mock_system.assert_called_once_with(f"sudo dpkg -i {pkgfile}")
|
||||
|
||||
@patch("r2env.package_manager.os.system")
|
||||
@patch("r2env.package_manager.PackageManager._get_pkgname")
|
||||
@patch("r2env.package_manager.PackageManager._get_disturl")
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_install_from_dist_mac_os_not_supported(self, mock_host_distname,
|
||||
mock__get_disturl,
|
||||
mock__get_pkgname,
|
||||
mock_system):
|
||||
mock__get_pkgname.return_value = "radare2-5.3.1-mac.zip"
|
||||
mock__get_disturl.return_value = "http://example.org"
|
||||
mock_host_distname.return_value = "not_existing_so"
|
||||
patch("r2env.package_manager.wget.download").start()
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._install_from_dist("radare2", "5.6.0")
|
||||
mock_system.assert_not_called()
|
||||
|
||||
@patch("r2env.package_manager.PackageManager._uninstall_from_dist")
|
||||
@patch("r2env.package_manager.zipfile.ZipFile")
|
||||
def test_install_windows_package_file_not_found(self, zipfile_mock, uninstall_mock):
|
||||
zipfile_mock.extractall.side_effect = FileNotFoundError()
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._install_windows_package("radare2")
|
||||
uninstall_mock.assert_called_once()
|
||||
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
@patch("r2env.package_manager.os.makedirs")
|
||||
def test_install_windows_package_create_dst_folder(self, makedirs_mock, isdir_mock):
|
||||
patch("r2env.package_manager.shutil.copyfile").start()
|
||||
patch("r2env.package_manager.zipfile").start()
|
||||
isdir_mock.return_value = False
|
||||
patch("r2env.package_manager.shutil.copyfile").start()
|
||||
self.package_manager._install_windows_package("radare2")
|
||||
makedirs_mock.assert_called_once_with(os.path.join(self.package_manager._r2env_path, "bin"), 493)
|
||||
|
||||
@patch("r2env.package_manager.os.path.isdir")
|
||||
def test_install_windows_package_successfully(self, isdir_mock):
|
||||
with patch("r2env.package_manager.zipfile.ZipFile") as mock_ZipFile:
|
||||
mock_zip = MagicMock()
|
||||
mock_zip.return_value = ["1", "2", "3"]
|
||||
mock_ZipFile.return_value = mock_zip
|
||||
mock_copy = patch("r2env.package_manager.shutil.copyfile").start()
|
||||
isdir_mock.return_value = True
|
||||
assert_that(self.package_manager._install_windows_package("radare2"), equal_to(True))
|
||||
mock_copy.assert_called_once()
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_uninstall_from_dist_windows(self, mock_distname):
|
||||
mock_distname.return_value = "w64"
|
||||
mock_rmtree = patch("r2env.package_manager.shutil.rmtree").start()
|
||||
dst_folder = os.path.join(self.package_manager._r2env_path, "bin")
|
||||
assert_that(self.package_manager._uninstall_from_dist("radare2", "1.0.0"), equal_to(True))
|
||||
mock_rmtree.assert_called_once_with(dst_folder)
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_uninstall_from_dist_mac(self, mock_distname):
|
||||
mock_distname.return_value = "mac_arm64"
|
||||
mock_system = patch("r2env.package_manager.os.system").start()
|
||||
mock_system.side_effect = [0,0,0,0]
|
||||
assert_that(self.package_manager._uninstall_from_dist("radare2", "1.0.0"), equal_to(True))
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_uninstall_from_dist_mac_failed(self, mock_distname):
|
||||
mock_distname.return_value = "mac_arm64"
|
||||
mock_system = patch("r2env.package_manager.os.system").start()
|
||||
mock_system.side_effect = [0,1,0,0]
|
||||
assert_that(self.package_manager._uninstall_from_dist("radare2", "1.0.0"), equal_to(False))
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_uninstall_from_dist_linux(self, mock_distname):
|
||||
mock_distname.return_value = "deb_x64"
|
||||
mock_system = patch("r2env.package_manager.os.system").start()
|
||||
mock_system.return_value = 0
|
||||
assert_that(self.package_manager._uninstall_from_dist("radare2", "1.0.0"), equal_to(True))
|
||||
mock_system.assert_called_once_with("sudo dpkg -r radare2")
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_uninstall_from_dist_os_not_supported(self, mock_distname):
|
||||
mock_distname.return_value = "non_existent"
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._uninstall_from_dist("radare2", "1.0.0")
|
||||
|
||||
@patch("r2env.package_manager.host_distname")
|
||||
def test_acr_not_supported_on_windows(self, mock_distname):
|
||||
mock_distname.return_value = "w64"
|
||||
with self.assertRaises(PackageManagerException):
|
||||
self.package_manager._build_using_acr("source", "dest", "logfile", "r2env")
|
||||
Whitespace-only changes.
@@ -0,0 +1,55 @@
|
||||
from mock import patch
|
||||
import unittest
|
||||
|
||||
from r2env.repl import REPL
|
||||
from r2env.exceptions import ActionException
|
||||
|
||||
|
||||
class MockActions:
|
||||
def __init__(self):
|
||||
self.args = []
|
||||
self.version = False
|
||||
self.list = False
|
||||
|
||||
|
||||
class TestRepl(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.repl = REPL()
|
||||
|
||||
def tearDown(self):
|
||||
patch.stopall()
|
||||
|
||||
def test_invalid_run_with_no_action(self):
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(None)
|
||||
no_action = MockActions()
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(no_action)
|
||||
|
||||
@patch("r2env.repl.R2Env.list_packages")
|
||||
@patch("r2env.repl.R2Env.list_installed_packages")
|
||||
def test_invalid_run_action_with_no_arguments(self,mock_list_installed_packages, mock_list_packages):
|
||||
use_action = MockActions()
|
||||
use_action.args.append("use")
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(use_action)
|
||||
mock_list_installed_packages.assert_called()
|
||||
install_action = MockActions()
|
||||
install_action.args.append("install")
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(install_action)
|
||||
mock_list_packages.assert_called()
|
||||
|
||||
@patch("r2env.repl.REPL.show_help")
|
||||
def test_print_help(self, mock_help):
|
||||
help_action = MockActions()
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(help_action)
|
||||
mock_help.assert_called()
|
||||
|
||||
def test_invalid_action(self):
|
||||
invalid_action = MockActions()
|
||||
invalid_action.args.append("invalid_action")
|
||||
with self.assertRaises(ActionException):
|
||||
self.repl.run_action(invalid_action)
|
||||
|
||||
+62
-14
@@ -2,14 +2,16 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
from shutil import which
|
||||
|
||||
import git
|
||||
from colorama import Fore, Style
|
||||
from git import Repo
|
||||
|
||||
|
||||
# Global Vars
|
||||
from r2env.exceptions import PackageManagerException
|
||||
|
||||
INFO = 0
|
||||
WARNING = 1
|
||||
ERROR = 2
|
||||
@@ -19,6 +21,9 @@ def print_console(msg, level=INFO, formatter=0):
|
||||
tabs, color = ["", ""]
|
||||
for _ in range(formatter):
|
||||
tabs += " "
|
||||
if os.name == 'nt':
|
||||
print(tabs + msg)
|
||||
return
|
||||
if level == ERROR:
|
||||
color = Fore.RED
|
||||
elif level == WARNING:
|
||||
@@ -28,20 +33,64 @@ def print_console(msg, level=INFO, formatter=0):
|
||||
|
||||
def host_platform():
|
||||
if os.name == "nt":
|
||||
return "w64"
|
||||
return "windows"
|
||||
if os.path.isfile("/default.prop"):
|
||||
return "android"
|
||||
if os.uname().sysname == "Darwin":
|
||||
return "osx"
|
||||
return "unix"
|
||||
|
||||
|
||||
# TODO :improve to support all archs
|
||||
def host_distname(): # noqa: C901
|
||||
dist_name = None
|
||||
try:
|
||||
sysname = os.uname().sysname
|
||||
machine = os.uname().machine
|
||||
except AttributeError:
|
||||
sysname = "Windows"
|
||||
machine = "amd64"
|
||||
if sysname in "Windows" and os.name in "nt":
|
||||
dist_name = "w64"
|
||||
elif sysname in "Darwin":
|
||||
if machine in "x86_64":
|
||||
dist_name = "mac_x64"
|
||||
if machine in "arm64":
|
||||
dist_name = "mac_arm64"
|
||||
elif sysname == "Linux":
|
||||
if os.path.exists("/usr/bin/dpkg"):
|
||||
if machine == "x86_64":
|
||||
dist_name = "deb_x64"
|
||||
else:
|
||||
dist_name = "deb_i386"
|
||||
if os.path.isfile("/default.prop"):
|
||||
dist_name = "android"
|
||||
return dist_name
|
||||
|
||||
|
||||
def git_fetch(url, version, source_path):
|
||||
if os.path.isdir(os.path.join(source_path, ".git")):
|
||||
repo = Repo(source_path)
|
||||
repo.remotes.origin.pull("master")
|
||||
else:
|
||||
repo = Repo.clone_from(url, source_path)
|
||||
if version != "latest":
|
||||
repo.git.checkout(version)
|
||||
try:
|
||||
if os.path.isdir(os.path.join(source_path, ".git")):
|
||||
repo = Repo(source_path)
|
||||
repo.git.checkout("master")
|
||||
repo.remotes.origin.pull("master")
|
||||
else:
|
||||
repo = Repo.clone_from(url, source_path)
|
||||
except git.GitCommandError as err:
|
||||
raise PackageManagerException("An error occured clonning the repo. "
|
||||
f"Verify the source path is not dirty. Error: {err}") \
|
||||
from err
|
||||
if version != "git":
|
||||
try:
|
||||
repo.git.checkout(version)
|
||||
except git.GitCommandError:
|
||||
# try again after pulling new tags from origin
|
||||
repo.git.fetch("origin", "--tags")
|
||||
repo.git.checkout(version)
|
||||
sms = repo.submodules
|
||||
for sm in sms:
|
||||
if not sm.module_exists():
|
||||
sm.update()
|
||||
|
||||
|
||||
def git_clean(source_path):
|
||||
@@ -56,14 +105,13 @@ def exists(tool):
|
||||
def exit_if_not_exists(tools):
|
||||
for tool in tools:
|
||||
if not exists(tool):
|
||||
print_console("[x] {} is required. Please install it first", level=ERROR)
|
||||
sys.exit(-1)
|
||||
raise PackageManagerException(f"[x] {tool} is required. Please install it first")
|
||||
|
||||
|
||||
def load_json_file(filepath):
|
||||
try:
|
||||
with open(filepath) as json_file:
|
||||
with open(filepath, encoding="utf-8") as json_file:
|
||||
return json.load(json_file)
|
||||
except OSError as err:
|
||||
print_console("File {} not found. Msg: {}".format(filepath, err), ERROR)
|
||||
print_console(f"File {filepath} not found. Msg: {err}", ERROR)
|
||||
return None
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.3.0
|
||||
0.5.9
|
||||
@@ -1,3 +1,5 @@
|
||||
dploy>=0.1.2
|
||||
colorama>=0.4.4
|
||||
wget
|
||||
requests
|
||||
GitPython
|
||||
@@ -7,4 +7,4 @@ mock
|
||||
pytest
|
||||
coverage
|
||||
doublex
|
||||
tox
|
||||
tox
|
||||
Regular → Executable
+1
-1
@@ -6,7 +6,7 @@ readlink=$(which greadlink 2>/dev/null) || readlink=$(which readlink)
|
||||
base_dir=$(cd $(dirname $(${readlink} -f "$0")); pwd)
|
||||
|
||||
echo "Cleaning *.pyc files ..."
|
||||
find $base_dir -name \*.pyc | xargs rm 2>/dev/null
|
||||
find . -name \*.pyc | xargs rm 2>/dev/null
|
||||
|
||||
python -m coverage run -m pytest -v -rsx -k "test_" --ignore=bin/
|
||||
ecode=$?
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
[metadata]
|
||||
license_file = LICENSE
|
||||
version = 0.3.1
|
||||
name = r2env
|
||||
author = pancake
|
||||
# author_email = '[email protected], [email protected]'
|
||||
@@ -36,6 +35,7 @@ install_requires=
|
||||
dploy >= 0.1.2
|
||||
colorama >= 0.4.4
|
||||
GitPython
|
||||
requests
|
||||
setup_requires =
|
||||
setuptools_scm >= 1.15
|
||||
include_package_data = True
|
||||
|
||||
@@ -5,5 +5,8 @@ from setuptools import setup
|
||||
setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True,
|
||||
package_files=[('config', ['r2env/config/config.json', 'r2env/config/profiles.json'])]
|
||||
package_files=[
|
||||
('config', ['r2env/config/config.json']),
|
||||
('', ['version.txt'])
|
||||
]
|
||||
)
|
||||
@@ -1,15 +1,16 @@
|
||||
[tox]
|
||||
envlist = py{38,39}-{tests},{py38,py39}-codecheck-{pylint,flake8,bandit}
|
||||
envlist = py{38,39,310}-{tests},{py38,py39,310}-codecheck-{pylint,flake8,bandit}
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
allowlist_externals = bash
|
||||
deps = -r {toxinidir}/requirements/test.txt
|
||||
passenv = *
|
||||
commands =
|
||||
py{38,39}-tests: {toxinidir}/run_tests.sh unit
|
||||
py{38,39}-codecheck-pylint: pylint r2env
|
||||
py{38,39}-codecheck-flake8: flake8 r2env
|
||||
py{38,39}-codecheck-bandit: bandit -c .bandit.yml -r r2env
|
||||
py{38,39,310}-tests: bash {toxinidir}/run_tests.sh unit
|
||||
py{38,39,310}-codecheck-pylint: pylint r2env
|
||||
py{38,39,310}-codecheck-flake8: flake8 r2env
|
||||
py{38,39,310}-codecheck-bandit: bandit -c .bandit.yml -r r2env
|
||||
|
||||
[flake8]
|
||||
# to ignore complete files, add to the file: # flake8: noqa
|
||||
|
||||
Reference in new issue
Block a user