mirror of
https://github.com/revanced/revanced-cli.git
synced 2025-04-30 14:44:34 +02:00
Compare commits
No commits in common. "main" and "v4.0.0-dev.4" have entirely different histories.
main
...
v4.0.0-dev
@ -1,3 +0,0 @@
|
|||||||
[*.{kt,kts}]
|
|
||||||
ktlint_code_style = intellij_idea
|
|
||||||
ktlint_standard_no-wildcard-imports = disabled
|
|
49
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
49
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: 🐞 Bug report
|
||||||
|
description: Report a bug or an issue.
|
||||||
|
title: 'bug: '
|
||||||
|
labels: ['Bug report']
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# ReVanced CLI bug report
|
||||||
|
|
||||||
|
Please check for existing bug reports
|
||||||
|
[here](https://github.com/ReVanced/revanced-cli/labels/Bug%20report)
|
||||||
|
before creating a new one.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Bug description
|
||||||
|
description: |
|
||||||
|
- Describe your bug in detail
|
||||||
|
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
|
||||||
|
- Add images and videos if possible
|
||||||
|
- List used patches if applicable
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Error logs
|
||||||
|
description: Exceptions can be captured by running `logcat | grep AndroidRuntime` in a shell.
|
||||||
|
render: shell
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Solution
|
||||||
|
description: If applicable, add a possible solution to the bug.
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional context
|
||||||
|
description: Add additional context here.
|
||||||
|
- type: checkboxes
|
||||||
|
id: acknowledgements
|
||||||
|
attributes:
|
||||||
|
label: Acknowledgements
|
||||||
|
description: Your issue will be closed if you don't follow the checklist below.
|
||||||
|
options:
|
||||||
|
- label: This request is not a duplicate of an existing issue.
|
||||||
|
required: true
|
||||||
|
- label: I have chosen an appropriate title.
|
||||||
|
required: true
|
||||||
|
- label: All requested information has been provided properly.
|
||||||
|
required: true
|
110
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
110
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,110 +0,0 @@
|
|||||||
name: 🐞 Bug report
|
|
||||||
description: Report a bug or an issue.
|
|
||||||
title: 'bug: '
|
|
||||||
labels: ['Bug report']
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
<p align="center">
|
|
||||||
<picture>
|
|
||||||
<source
|
|
||||||
width="256px"
|
|
||||||
media="(prefers-color-scheme: dark)"
|
|
||||||
srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
width="256px"
|
|
||||||
src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
|
||||||
>
|
|
||||||
</picture>
|
|
||||||
<br>
|
|
||||||
<a href="https://revanced.app/">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/ReVanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
|
||||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="http://revanced.app/discord">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://reddit.com/r/revancedapp">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://t.me/app_revanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://x.com/revancedapp">
|
|
||||||
<picture>
|
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.youtube.com/@ReVanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
Continuing the legacy of Vanced
|
|
||||||
</p>
|
|
||||||
|
|
||||||
# ReVanced CLI bug report
|
|
||||||
|
|
||||||
Before creating a new bug report, please keep the following in mind:
|
|
||||||
|
|
||||||
- **Do not submit a duplicate bug report**: Search for existing bug reports [here](https://github.com/ReVanced/revanced-cli/issues?q=label%3A%22Bug+report%22).
|
|
||||||
- **Review the contribution guidelines**: Make sure your bug report adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-cli/blob/main/CONTRIBUTING.md).
|
|
||||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Bug description
|
|
||||||
description: |
|
|
||||||
- Describe your bug in detail
|
|
||||||
- Add steps to reproduce the bug if possible (Step 1. ... Step 2. ...)
|
|
||||||
- Add images and videos if possible
|
|
||||||
- List used patches if applicable
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Error logs
|
|
||||||
description: Exceptions can be captured by running `logcat | grep AndroidRuntime` in a shell.
|
|
||||||
render: shell
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Solution
|
|
||||||
description: If applicable, add a possible solution to the bug.
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context
|
|
||||||
description: Add additional context here.
|
|
||||||
- type: checkboxes
|
|
||||||
id: acknowledgements
|
|
||||||
attributes:
|
|
||||||
label: Acknowledgements
|
|
||||||
description: Your bug report will be closed if you don't follow the checklist below.
|
|
||||||
options:
|
|
||||||
- label: I have checked all open and closed bug reports and this is not a duplicate.
|
|
||||||
required: true
|
|
||||||
- label: I have chosen an appropriate title.
|
|
||||||
required: true
|
|
||||||
- label: All requested information has been provided properly.
|
|
||||||
required: true
|
|
45
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
45
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: ⭐ Feature request
|
||||||
|
description: Create a detailed request for a new feature.
|
||||||
|
title: 'feat: '
|
||||||
|
labels: ['Feature request']
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
# ReVanced CLI feature request
|
||||||
|
|
||||||
|
Please check for existing feature requests
|
||||||
|
[here](https://github.com/ReVanced/revanced-cli/labels/Feature%20request)
|
||||||
|
before creating a new one.
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Feature description
|
||||||
|
description: |
|
||||||
|
- Describe your feature in detail
|
||||||
|
- Add images, videos, links, examples, references, etc. if possible
|
||||||
|
- Add the target application name in case you request a new patch
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Motivation
|
||||||
|
description: |
|
||||||
|
A strong motivation is necessary for a feature request to be considered.
|
||||||
|
|
||||||
|
- Why should this feature be implemented?
|
||||||
|
- What is the explicit use case?
|
||||||
|
- What are the benefits?
|
||||||
|
- What makes this feature important?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: checkboxes
|
||||||
|
id: acknowledgements
|
||||||
|
attributes:
|
||||||
|
label: Acknowledgements
|
||||||
|
description: Your issue will be closed if you don't follow the checklist below.
|
||||||
|
options:
|
||||||
|
- label: This request is not a duplicate of an existing issue.
|
||||||
|
required: true
|
||||||
|
- label: I have chosen an appropriate title.
|
||||||
|
required: true
|
||||||
|
- label: All requested information has been provided properly.
|
||||||
|
required: true
|
106
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
106
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,106 +0,0 @@
|
|||||||
name: ⭐ Feature request
|
|
||||||
description: Create a detailed request for a new feature.
|
|
||||||
title: 'feat: '
|
|
||||||
labels: ['Feature request']
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
<p align="center">
|
|
||||||
<picture>
|
|
||||||
<source
|
|
||||||
width="256px"
|
|
||||||
media="(prefers-color-scheme: dark)"
|
|
||||||
srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
width="256px"
|
|
||||||
src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-headline/revanced-headline-vertical-light.svg"
|
|
||||||
>
|
|
||||||
</picture>
|
|
||||||
<br>
|
|
||||||
<a href="https://revanced.app/">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
<img height="24px" src="https://raw.githubusercontent.com/revanced/revanced-cli/main/assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://github.com/ReVanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
|
||||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="http://revanced.app/discord">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://reddit.com/r/revancedapp">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://t.me/app_revanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://x.com/revancedapp">
|
|
||||||
<picture>
|
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<a href="https://www.youtube.com/@ReVanced">
|
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
Continuing the legacy of Vanced
|
|
||||||
</p>
|
|
||||||
|
|
||||||
# ReVanced CLI feature request
|
|
||||||
|
|
||||||
Before creating a new feature request, please keep the following in mind:
|
|
||||||
|
|
||||||
- **Do not submit a duplicate feature request**: Search for existing feature requests [here](https://github.com/ReVanced/revanced-cli/issues?q=label%3A%22Feature+request%22).
|
|
||||||
- **Review the contribution guidelines**: Make sure your feature request adheres to it. You can find the guidelines [here](https://github.com/ReVanced/revanced-cli//blob/main/CONTRIBUTING.md).
|
|
||||||
- **Do not use the issue page for support**: If you need help or have questions, check out other platforms on [revanced.app](https://revanced.app).
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Feature description
|
|
||||||
description: |
|
|
||||||
- Describe your feature in detail
|
|
||||||
- Add images, videos, links, examples, references, etc. if possible
|
|
||||||
- Add the target application name in case you request a new patch
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Motivation
|
|
||||||
description: |
|
|
||||||
A strong motivation is necessary for a feature request to be considered.
|
|
||||||
|
|
||||||
- Why should this feature be implemented?
|
|
||||||
- What is the explicit use case?
|
|
||||||
- What are the benefits?
|
|
||||||
- What makes this feature important?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: checkboxes
|
|
||||||
id: acknowledgements
|
|
||||||
attributes:
|
|
||||||
label: Acknowledgements
|
|
||||||
description: Your feature request will be closed if you don't follow the checklist below.
|
|
||||||
options:
|
|
||||||
- label: I have checked all open and closed feature requests and this is not a duplicate.
|
|
||||||
required: true
|
|
||||||
- label: I have chosen an appropriate title.
|
|
||||||
required: true
|
|
||||||
- label: All requested information has been provided properly.
|
|
||||||
required: true
|
|
2
.github/config.yml
vendored
2
.github/config.yml
vendored
@ -1,2 +1,2 @@
|
|||||||
firstPRMergeComment: >
|
firstPRMergeComment: >
|
||||||
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) to receive a role for your contribution.
|
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.
|
||||||
|
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: github-actions
|
|
||||||
labels: []
|
|
||||||
directory: /
|
|
||||||
target-branch: dev
|
|
||||||
schedule:
|
|
||||||
interval: monthly
|
|
||||||
|
|
||||||
- package-ecosystem: npm
|
|
||||||
labels: []
|
|
||||||
directory: /
|
|
||||||
target-branch: dev
|
|
||||||
schedule:
|
|
||||||
interval: monthly
|
|
||||||
|
|
||||||
- package-ecosystem: gradle
|
|
||||||
labels: []
|
|
||||||
directory: /
|
|
||||||
target-branch: dev
|
|
||||||
schedule:
|
|
||||||
interval: monthly
|
|
25
.github/workflows/build_pull_request.yml
vendored
25
.github/workflows/build_pull_request.yml
vendored
@ -1,25 +0,0 @@
|
|||||||
name: Build pull request
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Cache Gradle
|
|
||||||
uses: burrunan/gradle-cache-action@v1
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: ./gradlew build --no-daemon
|
|
@ -16,7 +16,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Open pull request
|
- name: Open pull request
|
||||||
uses: repo-sync/pull-request@v2
|
uses: repo-sync/pull-request@v2
|
||||||
with:
|
with:
|
42
.github/workflows/release.yml
vendored
42
.github/workflows/release.yml
vendored
@ -6,12 +6,14 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- dev
|
- dev
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@ -21,32 +23,24 @@ jobs:
|
|||||||
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Cache
|
||||||
- name: Cache Gradle
|
uses: actions/cache@v3
|
||||||
uses: burrunan/gradle-cache-action@v1
|
with:
|
||||||
|
path: |
|
||||||
|
${{ runner.home }}/.gradle/caches
|
||||||
|
${{ runner.home }}/.gradle/wrapper
|
||||||
|
.gradle
|
||||||
|
build
|
||||||
|
node_modules
|
||||||
|
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: ./gradlew build clean
|
# Cleaning is necessary to avoid uploading two identical artifacts with different versions
|
||||||
|
run: ./gradlew clean --no-daemon
|
||||||
- name: Setup Node.js
|
- name: Setup semantic-release
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: "lts/*"
|
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install
|
run: npm install
|
||||||
|
|
||||||
- name: Import GPG key
|
|
||||||
uses: crazy-max/ghaction-import-gpg@v6
|
|
||||||
with:
|
|
||||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
||||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
|
||||||
fingerprint: ${{ vars.GPG_FINGERPRINT }}
|
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
|
||||||
run: npm exec semantic-release
|
run: npm exec semantic-release
|
||||||
|
@ -11,7 +11,7 @@ jobs:
|
|||||||
name: Dispatch event to documentation repository
|
name: Dispatch event to documentation repository
|
||||||
if: github.ref == 'refs/heads/main'
|
if: github.ref == 'refs/heads/main'
|
||||||
steps:
|
steps:
|
||||||
- uses: peter-evans/repository-dispatch@v3
|
- uses: peter-evans/repository-dispatch@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
|
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
|
||||||
repository: revanced/revanced-documentation
|
repository: revanced/revanced-documentation
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -120,6 +120,3 @@ node_modules/
|
|||||||
# ReVanced CLI
|
# ReVanced CLI
|
||||||
revanced-cache/
|
revanced-cache/
|
||||||
options.toml
|
options.toml
|
||||||
|
|
||||||
# Generated by Android projects
|
|
||||||
local.properties
|
|
@ -23,8 +23,7 @@
|
|||||||
"assets": [
|
"assets": [
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
"gradle.properties"
|
"gradle.properties"
|
||||||
],
|
]
|
||||||
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -32,7 +31,7 @@
|
|||||||
{
|
{
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
"path": "build/libs/*-all*"
|
"path": "build/libs/*all.jar"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
successComment: false
|
successComment: false
|
||||||
|
411
CHANGELOG.md
411
CHANGELOG.md
@ -1,414 +1,3 @@
|
|||||||
## [5.0.1](https://github.com/ReVanced/revanced-cli/compare/v5.0.0...v5.0.1) (2025-04-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Make mounting work again by bumping dependencies ([#359](https://github.com/ReVanced/revanced-cli/issues/359)) ([68a4872](https://github.com/ReVanced/revanced-cli/commit/68a48724ebf01a0c8f8adc0fec63037bff672dc9))
|
|
||||||
|
|
||||||
## [5.0.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v5.0.0...v5.0.1-dev.1) (2025-02-26)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Make mounting work again by bumping dependencies ([#359](https://github.com/ReVanced/revanced-cli/issues/359)) ([68a4872](https://github.com/ReVanced/revanced-cli/commit/68a48724ebf01a0c8f8adc0fec63037bff672dc9))
|
|
||||||
|
|
||||||
# [5.0.0](https://github.com/ReVanced/revanced-cli/compare/v4.6.0...v5.0.0) (2024-11-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Check for null when no device serial was specified ([1da8ae9](https://github.com/ReVanced/revanced-cli/commit/1da8ae9e46000dd3c4eecd793c559e75012cf535))
|
|
||||||
* List if patch option is required ([#346](https://github.com/ReVanced/revanced-cli/issues/346)) ([98ff0c3](https://github.com/ReVanced/revanced-cli/commit/98ff0c34fa71c3b3ecd96157d45a30ee2b8979c6))
|
|
||||||
* Make CLI ArgGroup non-exclusive to be able to disable and enable patches at the same time ([1bb0d13](https://github.com/ReVanced/revanced-cli/commit/1bb0d13726fd5790c59cb6d28df3618c7606710d))
|
|
||||||
* Make patches selectable by using a mutable collection for the selection option ([751fa1d](https://github.com/ReVanced/revanced-cli/commit/751fa1d889f40c51b291116029fd84f2b051f2f0))
|
|
||||||
* Make the patch command work without specifying any selection ([ba159a3](https://github.com/ReVanced/revanced-cli/commit/ba159a35a9a99d18a4c1e04128b08ae336a49b3e))
|
|
||||||
* Print in new line correctly ([c2dc9d7](https://github.com/ReVanced/revanced-cli/commit/c2dc9d76be33c98284741e23c406500483c47753))
|
|
||||||
* Use the first connected device when no ADB device is specified ([5f952f3](https://github.com/ReVanced/revanced-cli/commit/5f952f35f5cb388b6509b2b4d905b8143ebc7996))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Set patch options via CLI ([#336](https://github.com/ReVanced/revanced-cli/issues/336)) ([2300243](https://github.com/ReVanced/revanced-cli/commit/23002434b2d51c2a3b30b33dd0526261432d90ce))
|
|
||||||
* Show error about no installation device found at the beginning ([3300e6b](https://github.com/ReVanced/revanced-cli/commit/3300e6b4333ed1c4e6785cb82eca9016fc6d4a20))
|
|
||||||
* Simplify command and option names and descriptions ([#338](https://github.com/ReVanced/revanced-cli/issues/338)) ([6e7797a](https://github.com/ReVanced/revanced-cli/commit/6e7797a3f0525a8f48af7182157da0d045600ac2))
|
|
||||||
* Simplify option descriptions ([45c998b](https://github.com/ReVanced/revanced-cli/commit/45c998b335b65ac233fece8b804dc7410142691c))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* Options have been renamed.
|
|
||||||
* This commit changes various CLI options and removes the `options.json` file. Instead, patch options can now be passed via CLI options
|
|
||||||
|
|
||||||
# [5.0.0-dev.11](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.10...v5.0.0-dev.11) (2024-11-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* List if patch option is required ([#346](https://github.com/ReVanced/revanced-cli/issues/346)) ([98ff0c3](https://github.com/ReVanced/revanced-cli/commit/98ff0c34fa71c3b3ecd96157d45a30ee2b8979c6))
|
|
||||||
|
|
||||||
# [5.0.0-dev.10](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.9...v5.0.0-dev.10) (2024-11-05)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Make CLI ArgGroup non-exclusive to be able to disable and enable patches at the same time ([1bb0d13](https://github.com/ReVanced/revanced-cli/commit/1bb0d13726fd5790c59cb6d28df3618c7606710d))
|
|
||||||
|
|
||||||
# [5.0.0-dev.9](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.8...v5.0.0-dev.9) (2024-11-05)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Print in new line correctly ([c2dc9d7](https://github.com/ReVanced/revanced-cli/commit/c2dc9d76be33c98284741e23c406500483c47753))
|
|
||||||
|
|
||||||
# [5.0.0-dev.8](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.7...v5.0.0-dev.8) (2024-10-17)
|
|
||||||
|
|
||||||
# [5.0.0-dev.7](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.6...v5.0.0-dev.7) (2024-10-16)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Check for null when no device serial was specified ([1da8ae9](https://github.com/ReVanced/revanced-cli/commit/1da8ae9e46000dd3c4eecd793c559e75012cf535))
|
|
||||||
|
|
||||||
# [5.0.0-dev.6](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.5...v5.0.0-dev.6) (2024-10-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Use the first connected device when no ADB device is specified ([5f952f3](https://github.com/ReVanced/revanced-cli/commit/5f952f35f5cb388b6509b2b4d905b8143ebc7996))
|
|
||||||
|
|
||||||
# [5.0.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.4...v5.0.0-dev.5) (2024-09-30)
|
|
||||||
|
|
||||||
# [5.0.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.3...v5.0.0-dev.4) (2024-09-17)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Make patches selectable by using a mutable collection for the selection option ([751fa1d](https://github.com/ReVanced/revanced-cli/commit/751fa1d889f40c51b291116029fd84f2b051f2f0))
|
|
||||||
* Make the patch command work without specifying any selection ([ba159a3](https://github.com/ReVanced/revanced-cli/commit/ba159a35a9a99d18a4c1e04128b08ae336a49b3e))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Show error about no installation device found at the beginning ([3300e6b](https://github.com/ReVanced/revanced-cli/commit/3300e6b4333ed1c4e6785cb82eca9016fc6d4a20))
|
|
||||||
|
|
||||||
# [5.0.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.2...v5.0.0-dev.3) (2024-08-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Simplify option descriptions ([45c998b](https://github.com/ReVanced/revanced-cli/commit/45c998b335b65ac233fece8b804dc7410142691c))
|
|
||||||
|
|
||||||
# [5.0.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v5.0.0-dev.1...v5.0.0-dev.2) (2024-08-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Simplify command and option names and descriptions ([#338](https://github.com/ReVanced/revanced-cli/issues/338)) ([6e7797a](https://github.com/ReVanced/revanced-cli/commit/6e7797a3f0525a8f48af7182157da0d045600ac2))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* Options have been renamed.
|
|
||||||
|
|
||||||
# [5.0.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.6.0...v5.0.0-dev.1) (2024-08-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Set patch options via CLI ([#336](https://github.com/ReVanced/revanced-cli/issues/336)) ([2300243](https://github.com/ReVanced/revanced-cli/commit/23002434b2d51c2a3b30b33dd0526261432d90ce))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* This commit changes various CLI options and removes the `options.json` file. Instead, patch options can now be passed via CLI options
|
|
||||||
|
|
||||||
# [4.6.0](https://github.com/ReVanced/revanced-cli/compare/v4.5.0...v4.6.0) (2024-04-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Copy APK to output path when it is not being signed ([366f400](https://github.com/ReVanced/revanced-cli/commit/366f400c5a46491f3f262c7ff4b0df1ae3721f74))
|
|
||||||
* Use correct option description ([45a2ffa](https://github.com/ReVanced/revanced-cli/commit/45a2ffa2dd95ee8ac3c4d466463c9a5b869b8da1))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Use more consistent option name ([223629c](https://github.com/ReVanced/revanced-cli/commit/223629c663dcd94d237110e09e4e152aa03867f9))
|
|
||||||
|
|
||||||
# [4.6.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.5.1-dev.1...v4.6.0-dev.1) (2024-03-14)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Use correct option description ([45a2ffa](https://github.com/ReVanced/revanced-cli/commit/45a2ffa2dd95ee8ac3c4d466463c9a5b869b8da1))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Use more consistent option name ([223629c](https://github.com/ReVanced/revanced-cli/commit/223629c663dcd94d237110e09e4e152aa03867f9))
|
|
||||||
|
|
||||||
## [4.5.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.5.0...v4.5.1-dev.1) (2024-03-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Copy APK to output path when it is not being signed ([366f400](https://github.com/ReVanced/revanced-cli/commit/366f400c5a46491f3f262c7ff4b0df1ae3721f74))
|
|
||||||
|
|
||||||
# [4.5.0](https://github.com/ReVanced/revanced-cli/compare/v4.4.2...v4.5.0) (2024-03-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Show path for missing files instead of just the name ([f0f3e56](https://github.com/ReVanced/revanced-cli/commit/f0f3e5614b99b34391e0492177706f9c09781cad))
|
|
||||||
* Sign APKs correctly ([5ff105c](https://github.com/ReVanced/revanced-cli/commit/5ff105cf6b3fac9cd12478efd10caf90d1ecf589))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Remove deprecated CLI options ([48a1a39](https://github.com/ReVanced/revanced-cli/commit/48a1a39b94dd9121c400d28e3e93dec3fc13e3be))
|
|
||||||
|
|
||||||
# [4.5.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.2...v4.5.0-dev.1) (2024-03-11)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Show path for missing files instead of just the name ([f0f3e56](https://github.com/ReVanced/revanced-cli/commit/f0f3e5614b99b34391e0492177706f9c09781cad))
|
|
||||||
* Sign APKs correctly ([5ff105c](https://github.com/ReVanced/revanced-cli/commit/5ff105cf6b3fac9cd12478efd10caf90d1ecf589))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Remove deprecated CLI options ([48a1a39](https://github.com/ReVanced/revanced-cli/commit/48a1a39b94dd9121c400d28e3e93dec3fc13e3be))
|
|
||||||
|
|
||||||
## [4.4.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2) (2024-03-10)
|
|
||||||
|
|
||||||
## [4.4.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.2-dev.1...v4.4.2-dev.2) (2024-03-10)
|
|
||||||
|
|
||||||
## [4.4.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.1...v4.4.2-dev.1) (2024-03-09)
|
|
||||||
|
|
||||||
## [4.4.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1) (2024-03-06)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Bump dependencies to support BCS keystore ([1c10a77](https://github.com/ReVanced/revanced-cli/commit/1c10a7760d76ea850260ca49b448be7ad121de44))
|
|
||||||
|
|
||||||
## [4.4.1-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.1-dev.1...v4.4.1-dev.2) (2024-03-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Bump dependencies to support BCS keystore ([1c10a77](https://github.com/ReVanced/revanced-cli/commit/1c10a7760d76ea850260ca49b448be7ad121de44))
|
|
||||||
|
|
||||||
## [4.4.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.4.0...v4.4.1-dev.1) (2024-02-21)
|
|
||||||
|
|
||||||
# [4.4.0](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0) (2023-12-28)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Add missing punctuation in command description ([8210351](https://github.com/ReVanced/revanced-cli/commit/821035107d7264580275f395e9e3fcef91394afd))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Log saved patched APK file path ([16109bd](https://github.com/ReVanced/revanced-cli/commit/16109bd8bc6236debf71cbc8db78fe452b2ed00d))
|
|
||||||
|
|
||||||
# [4.4.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.4.0-dev.1...v4.4.0-dev.2) (2023-12-18)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Add missing punctuation in command description ([8210351](https://github.com/ReVanced/revanced-cli/commit/821035107d7264580275f395e9e3fcef91394afd))
|
|
||||||
|
|
||||||
# [4.4.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.3.0...v4.4.0-dev.1) (2023-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Log saved patched APK file path ([16109bd](https://github.com/ReVanced/revanced-cli/commit/16109bd8bc6236debf71cbc8db78fe452b2ed00d))
|
|
||||||
|
|
||||||
# [4.3.0](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0) (2023-12-01)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Add `list-versions` command ([a974b8e](https://github.com/ReVanced/revanced-cli/commit/a974b8ea80acd85f8dc472a3f93b8fd7bea08007))
|
|
||||||
|
|
||||||
# [4.3.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.2.0...v4.3.0-dev.1) (2023-11-27)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Add `list-versions` command ([a974b8e](https://github.com/ReVanced/revanced-cli/commit/a974b8ea80acd85f8dc472a3f93b8fd7bea08007))
|
|
||||||
|
|
||||||
# [4.2.0](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.2.0) (2023-11-26)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](https://github.com/ReVanced/revanced-cli/commit/9d96bb7b4cc4538da416db50bd689af1a632fc45))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](https://github.com/ReVanced/revanced-cli/commit/e7c3d64bf15bf84f3853e7ef699511bf72c13767))
|
|
||||||
* Exit application with CLI exit code ([36c6a6a](https://github.com/ReVanced/revanced-cli/commit/36c6a6a5f75f2e770a7941b3f83f430f62de13de))
|
|
||||||
* Make `--out´ option optional ([3765957](https://github.com/ReVanced/revanced-cli/commit/3765957043989fe7a8932a0c548566a78d04fc41))
|
|
||||||
|
|
||||||
# [4.2.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.1-dev.1...v4.2.0-dev.1) (2023-11-26)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Allow selecting first Adb device, if none supplied automatically by updating dependencies ([e7c3d64](https://github.com/ReVanced/revanced-cli/commit/e7c3d64bf15bf84f3853e7ef699511bf72c13767))
|
|
||||||
* Exit application with CLI exit code ([36c6a6a](https://github.com/ReVanced/revanced-cli/commit/36c6a6a5f75f2e770a7941b3f83f430f62de13de))
|
|
||||||
* Make `--out´ option optional ([3765957](https://github.com/ReVanced/revanced-cli/commit/3765957043989fe7a8932a0c548566a78d04fc41))
|
|
||||||
|
|
||||||
## [4.1.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.1.0...v4.1.1-dev.1) (2023-11-25)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Fix typo ([#300](https://github.com/ReVanced/revanced-cli/issues/300)) ([9d96bb7](https://github.com/ReVanced/revanced-cli/commit/9d96bb7b4cc4538da416db50bd689af1a632fc45))
|
|
||||||
|
|
||||||
# [4.1.0](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.1.0) (2023-11-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
|
|
||||||
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
|
|
||||||
|
|
||||||
# [4.1.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.2...v4.1.0-dev.3) (2023-11-03)
|
|
||||||
|
|
||||||
# [4.1.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.1.0-dev.1...v4.1.0-dev.2) (2023-11-03)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Include or exclude patches by their index in relation to supplied patch bundles ([b2055ce](https://github.com/ReVanced/revanced-cli/commit/b2055ce07df3ab9a9f3f73ab17d8c2cf02f2ae62))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Use a `HashSet` to check for included and excluded patches ([616d14f](https://github.com/ReVanced/revanced-cli/commit/616d14f0097c1ee7ba6dc07be417590f6418e8e5))
|
|
||||||
|
|
||||||
# [4.1.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.2...v4.1.0-dev.1) (2023-11-03)
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* List patches which are compatible with any app ([#297](https://github.com/ReVanced/revanced-cli/issues/297)) ([0139dfe](https://github.com/ReVanced/revanced-cli/commit/0139dfe0bfa06a13f56dc03e7718aaf644029614))
|
|
||||||
|
|
||||||
## [4.0.3-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.3-dev.1...v4.0.3-dev.2) (2023-10-30)
|
|
||||||
|
|
||||||
## [4.0.3-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.2...v4.0.3-dev.1) (2023-10-23)
|
|
||||||
|
|
||||||
## [4.0.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2) (2023-10-12)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Move file to output even when mounting ([59dfc98](https://github.com/ReVanced/revanced-cli/commit/59dfc988e351374eb718923d19bd9bdd94e8d3c0))
|
|
||||||
* Use punctuation in option descriptions ([da4469f](https://github.com/ReVanced/revanced-cli/commit/da4469f402c26ad95898404236b0acf0202907e2))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Use multiple threads for writing dex files ([28648a1](https://github.com/ReVanced/revanced-cli/commit/28648a1c53520eef8c799504ff61a35947f878b8))
|
|
||||||
|
|
||||||
## [4.0.2-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.2...v4.0.2-dev.3) (2023-10-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Move file to output even when mounting ([59dfc98](https://github.com/ReVanced/revanced-cli/commit/59dfc988e351374eb718923d19bd9bdd94e8d3c0))
|
|
||||||
|
|
||||||
## [4.0.2-dev.2](https://github.com/ReVanced/revanced-cli/compare/v4.0.2-dev.1...v4.0.2-dev.2) (2023-10-10)
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Use multiple threads for writing dex files ([28648a1](https://github.com/ReVanced/revanced-cli/commit/28648a1c53520eef8c799504ff61a35947f878b8))
|
|
||||||
|
|
||||||
## [4.0.2-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.1...v4.0.2-dev.1) (2023-10-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Use punctuation in option descriptions ([da4469f](https://github.com/ReVanced/revanced-cli/commit/da4469f402c26ad95898404236b0acf0202907e2))
|
|
||||||
|
|
||||||
## [4.0.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.0...v4.0.1) (2023-10-08)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Correct warning message ([ba573f7](https://github.com/ReVanced/revanced-cli/commit/ba573f73d0e310fdeb8be2831fd40a7188473fff))
|
|
||||||
|
|
||||||
## [4.0.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v4.0.0...v4.0.1-dev.1) (2023-10-07)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Correct warning message ([e4e339d](https://github.com/ReVanced/revanced-cli/commit/e4e339dff40542d6265de59496545c859312cf11))
|
|
||||||
|
|
||||||
# [4.0.0](https://github.com/ReVanced/revanced-cli/compare/v3.1.1...v4.0.0) (2023-10-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Check, if mounting is possible ([3e13fb5](https://github.com/ReVanced/revanced-cli/commit/3e13fb5d56eb2a90c2a4a1ddfc05852b1f70add5))
|
|
||||||
* Delete temporal files if it exists ([a022feb](https://github.com/ReVanced/revanced-cli/commit/a022febd0c70807ddc3fa9948207a2a70d5191da))
|
|
||||||
* Do not sign if mounting ([578e16b](https://github.com/ReVanced/revanced-cli/commit/578e16b099fddfd2bb56accb225d04dfcd409b0c))
|
|
||||||
* Filter logs correctly ([43fc20d](https://github.com/ReVanced/revanced-cli/commit/43fc20d90e0a694b231b17bb7d9ecfa22bb5d9a0))
|
|
||||||
* Log correct options command ([#262](https://github.com/ReVanced/revanced-cli/issues/262)) ([96c196d](https://github.com/ReVanced/revanced-cli/commit/96c196dcb14e37ad91b751af61ee8382547c1ca3))
|
|
||||||
* Log logs with levels over warning to error output stream ([075f6ad](https://github.com/ReVanced/revanced-cli/commit/075f6ad56528a667dca1f0bed704cf7e5381026f))
|
|
||||||
* Only open files for reading and writing if writeable ([3846f72](https://github.com/ReVanced/revanced-cli/commit/3846f721ca015ab39a7e4b8d3f3d61163a6f1650))
|
|
||||||
* Only set options for filtered patches ([64d9127](https://github.com/ReVanced/revanced-cli/commit/64d9127291ea9a8abe21a0e82721721495094472))
|
|
||||||
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* Add function to get the most common compatible version ([77d9173](https://github.com/ReVanced/revanced-cli/commit/77d91735ffbbd6e733f08176f535bfd39ece0c29))
|
|
||||||
* Add option to filter patches to be listed by package name ([50c0f98](https://github.com/ReVanced/revanced-cli/commit/50c0f98ce5927e07839437a2e550aa85f5a7e62d))
|
|
||||||
* Add option to warn about patches not being found in supplied patch bundles ([e46d855](https://github.com/ReVanced/revanced-cli/commit/e46d85564320f46c6faa54b2d3fa7fca3fa60019))
|
|
||||||
* Add ReVanced Library subproject ([#265](https://github.com/ReVanced/revanced-cli/issues/265)) ([157278c](https://github.com/ReVanced/revanced-cli/commit/157278c9ba25f0f786c5fe58e3e23f6890107118))
|
|
||||||
* Do not format patch names ([80a8d88](https://github.com/ReVanced/revanced-cli/commit/80a8d88406b2b04d13dca4fb0d7d7d62e1910317))
|
|
||||||
* Extend signing API ([592dc1c](https://github.com/ReVanced/revanced-cli/commit/592dc1c64ae4078e73bb71eba11380b301c79dea))
|
|
||||||
* Improve option descriptions ([d5ea5a0](https://github.com/ReVanced/revanced-cli/commit/d5ea5a0ab1cc015730063e5be94ee18bd88cc906))
|
|
||||||
* Log stacktrace in new line ([c67e3c7](https://github.com/ReVanced/revanced-cli/commit/c67e3c70c7eaa514cde1bebe775a2216bc4a6074))
|
|
||||||
* Use ReVanced Library in ReVanced CLI ([7794327](https://github.com/ReVanced/revanced-cli/commit/7794327a11e8a0e0f28176cd45fad797b924c45f))
|
|
||||||
* Word log message better ([6942b22](https://github.com/ReVanced/revanced-cli/commit/6942b22a68de5e991987ea89882915917aec93a3))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Do not check, if the options file exists twice ([e3c5550](https://github.com/ReVanced/revanced-cli/commit/e3c55507cf52e697b9ce9d59decc1cbe4cfe5b43))
|
|
||||||
|
|
||||||
|
|
||||||
### BREAKING CHANGES
|
|
||||||
|
|
||||||
* This changes many signatures of existing APIs and adds new functions for signing
|
|
||||||
* This changes the log handler signature
|
|
||||||
|
|
||||||
# [4.0.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v4.0.0-dev.4...v4.0.0-dev.5) (2023-10-04)
|
|
||||||
|
|
||||||
|
|
||||||
### Bug Fixes
|
|
||||||
|
|
||||||
* Only set options for filtered patches ([64d9127](https://github.com/ReVanced/revanced-cli/commit/64d9127291ea9a8abe21a0e82721721495094472))
|
|
||||||
|
|
||||||
|
|
||||||
### Performance Improvements
|
|
||||||
|
|
||||||
* Do not check, if the options file exists twice ([e3c5550](https://github.com/ReVanced/revanced-cli/commit/e3c55507cf52e697b9ce9d59decc1cbe4cfe5b43))
|
|
||||||
|
|
||||||
# [4.0.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v4.0.0-dev.3...v4.0.0-dev.4) (2023-10-01)
|
# [4.0.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v4.0.0-dev.3...v4.0.0-dev.4) (2023-10-01)
|
||||||
|
|
||||||
# [4.0.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.0-dev.2...v4.0.0-dev.3) (2023-09-27)
|
# [4.0.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v4.0.0-dev.2...v4.0.0-dev.3) (2023-09-27)
|
||||||
|
@ -6,72 +6,53 @@
|
|||||||
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
width="256px"
|
|
||||||
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
|
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||||
>
|
>
|
||||||
</picture>
|
</picture>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://revanced.app/">
|
<a href="https://revanced.app/">
|
||||||
<picture>
|
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" />
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ReVanced">
|
<a href="https://github.com/revanced">
|
||||||
<picture>
|
<picture>
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
<a href="http://revanced.app/discord">
|
<a href="http://revanced.app/discord">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://reddit.com/r/revancedapp">
|
<a href="https://reddit.com/r/revancedapp">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://t.me/app_revanced">
|
<a href="https://t.me/app_revanced">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://x.com/revancedapp">
|
<a href="https://twitter.com/revancedapp">
|
||||||
<picture>
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" />
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.youtube.com/@ReVanced">
|
<a href="https://www.youtube.com/@ReVanced">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||||
</picture>
|
</a>
|
||||||
</a>
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
Continuing the legacy of Vanced
|
Continuing the legacy of Vanced
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# 👋 Contribution guidelines
|
# 📙 ReVanced CLI contribution guidelines
|
||||||
|
|
||||||
This document describes how to contribute to ReVanced CLI.
|
This document describes how to contribute to ReVanced CLI.
|
||||||
|
|
||||||
## 📖 Resources to help you get started
|
## 📖 Resources to help you get started
|
||||||
|
|
||||||
- The [documentation](/docs) explains how to use ReVanced CLI
|
* The [documentation](/docs) explains how to use ReVanced CLI
|
||||||
- [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
|
* [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
|
||||||
- [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests
|
* [Issues](https://github.com/ReVanced/revanced-cli/issues) are where we keep track of bugs and feature requests
|
||||||
|
|
||||||
## 🙏 Submitting a feature request
|
## 🙏 Submitting a feature request
|
||||||
|
|
||||||
Features can be requested by opening an issue using the
|
Features can be requested by opening an issue using the
|
||||||
[Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature_request.yml&title=feat%3A+).
|
[Feature request issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Feature+request&projects=&template=feature-request.yml&title=feat%3A+).
|
||||||
|
|
||||||
> **Note**
|
> **Note**
|
||||||
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced CLI.
|
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced CLI.
|
||||||
@ -80,7 +61,7 @@ Features can be requested by opening an issue using the
|
|||||||
## 🐞 Submitting a bug report
|
## 🐞 Submitting a bug report
|
||||||
|
|
||||||
If you encounter a bug while using ReVanced CLI, open an issue using the
|
If you encounter a bug while using ReVanced CLI, open an issue using the
|
||||||
[Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug_report.yml&title=bug%3A+).
|
[Bug report issue template](https://github.com/ReVanced/revanced-cli/issues/new?assignees=&labels=Bug+report&projects=&template=bug-report.yml&title=bug%3A+).
|
||||||
|
|
||||||
## 📝 How to contribute
|
## 📝 How to contribute
|
||||||
|
|
||||||
@ -88,7 +69,7 @@ If you encounter a bug while using ReVanced CLI, open an issue using the
|
|||||||
with the maintainers of ReVanced CLI. This will help you determine whether your change is acceptable
|
with the maintainers of ReVanced CLI. This will help you determine whether your change is acceptable
|
||||||
and whether it is worth your time to implement it
|
and whether it is worth your time to implement it
|
||||||
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
|
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
|
||||||
3. Commit your changes
|
3. Commit your changes.
|
||||||
4. Submit a pull request to the `dev` branch of the repository and reference issues
|
4. Submit a pull request to the `dev` branch of the repository and reference issues
|
||||||
that your pull request closes in the description of your pull request
|
that your pull request closes in the description of your pull request
|
||||||
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
|
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
|
||||||
|
60
README.md
60
README.md
@ -6,84 +6,56 @@
|
|||||||
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
width="256px"
|
|
||||||
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
|
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
|
||||||
>
|
>
|
||||||
</picture>
|
</picture>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://revanced.app/">
|
<a href="https://revanced.app/">
|
||||||
<picture>
|
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" />
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
<img height="24px" src="assets/revanced-logo/revanced-logo.svg" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/ReVanced">
|
<a href="https://github.com/revanced">
|
||||||
<picture>
|
<picture>
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
|
||||||
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
|
||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
<a href="http://revanced.app/discord">
|
<a href="http://revanced.app/discord">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://reddit.com/r/revancedapp">
|
<a href="https://reddit.com/r/revancedapp">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://t.me/app_revanced">
|
<a href="https://t.me/app_revanced">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://x.com/revancedapp">
|
<a href="https://twitter.com/revancedapp">
|
||||||
<picture>
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" />
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/93124920/270180600-7c1b38bf-889b-4d68-bd5e-b9d86f91421a.png">
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/93124920/270108715-d80743fa-b330-4809-b1e6-79fbdc60d09c.png" />
|
|
||||||
</picture>
|
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.youtube.com/@ReVanced">
|
<a href="https://www.youtube.com/@ReVanced">
|
||||||
<picture>
|
|
||||||
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
|
||||||
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
|
||||||
</picture>
|
</a>
|
||||||
</a>
|
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
Continuing the legacy of Vanced
|
Continuing the legacy of Vanced
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
# 💻 ReVanced CLI
|
# 💻 ReVanced CLI
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
Command-line application to use ReVanced.
|
Command line application to use ReVanced.
|
||||||
|
|
||||||
## ❓ About
|
## ❓ About
|
||||||
|
|
||||||
ReVanced CLI is a command-line application that uses [ReVanced Patcher](https://github.com/revanced/revanced-patcher) to patch Android apps.
|
ReVanced CLI is a command line application to patch apps using ReVanced.
|
||||||
|
ReVanced CLI also comes with commands to uninstall or install patched apps and list patches from supplied patch bundles.
|
||||||
|
|
||||||
## 💪 Features
|
## 🚀 Download
|
||||||
|
|
||||||
Some of the features ReVanced CLI provides are:
|
|
||||||
|
|
||||||
- 💉 **Patch apps**: Harness ReVanced Patcher to patch Android apps
|
|
||||||
- 💾 **Install and uninstall apps**: Install and uninstall Apps via ADB,
|
|
||||||
using the Android package manager or by mounting using root permissions
|
|
||||||
- 📃 **List patches from patch bundles**: List available patches, compatible packages, and versions
|
|
||||||
- 💪 **Flexibility and functionality**: Apply any combination of patches to any version of Android apps
|
|
||||||
|
|
||||||
## 🔽 Download
|
|
||||||
|
|
||||||
You can download the most recent version of ReVanced CLI from
|
You can download the most recent version of ReVanced CLI from
|
||||||
[here](https://github.com/ReVanced/revanced-cli/releases/latest).
|
[here](https://github.com/ReVanced/revanced-cli/releases/latest). Learn how to use ReVanced CLI by following the [documentation](/docs).
|
||||||
Learn how to use ReVanced CLI by following the [documentation](/docs).
|
|
||||||
|
|
||||||
## 📚 Everything else
|
## 📚 Everything else
|
||||||
|
|
||||||
@ -94,14 +66,10 @@ You can find the contribution guidelines [here](CONTRIBUTING.md).
|
|||||||
|
|
||||||
### 🛠️ Building
|
### 🛠️ Building
|
||||||
|
|
||||||
To build a ReVanced CLI, you can follow the [documentation](/docs).
|
In order to build ReVanced CLI, you can follow the [documentation](/docs).
|
||||||
|
|
||||||
### 📃 Documentation
|
|
||||||
|
|
||||||
You can find the documentation of ReVanced CLI [here](/docs).
|
|
||||||
|
|
||||||
## 📜 Licence
|
## 📜 Licence
|
||||||
|
|
||||||
ReVanced CLI is licensed under the GPLv3 license. Please see the [license file](LICENSE) for more information.
|
ReVanced CLI is licensed under the GPLv3 licence. Please see the [licence file](LICENSE) for more information.
|
||||||
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced CLI as long as you track changes/dates in source files.
|
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced CLI as long as you track changes/dates in source files.
|
||||||
Any modifications to ReVanced CLI must also be made available under the GPL, along with build & install instructions.
|
Any modifications to ReVanced CLI must also be made available under the GPL along with build & install instructions.
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 11 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 11 KiB |
@ -1 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 800 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="Logo"><g id="Ring"><circle id="Ring-Background" serif:id="Ring Background" cx="400" cy="400" r="400" style="fill:#1b1b1b;"/><path id="Ring1" serif:id="Ring" d="M400,0c220.766,0 400,179.234 400,400c-0,220.766 -179.234,400 -400,400c-220.766,-0 -400,-179.234 -400,-400c0,-220.766 179.234,-400 400,-400Zm-0,36c200.897,-0 364,163.103 364,364c0,200.897 -163.103,364 -364,364c-200.897,0 -364,-163.103 -364,-364c-0,-200.897 163.103,-364 364,-364Z" style="fill:url(#_Linear1);"/></g><g id="Shape"><path id="V-Shape" serif:id="V Shape" d="M538.74,269.872c1.481,-3.382 1.157,-7.283 -0.863,-10.373c-2.021,-3.091 -5.464,-4.954 -9.156,-4.954c-5.148,0 -10.435,0 -14.165,0c-3.1,0 -5.907,1.834 -7.153,4.672c-12.468,28.396 -78.273,178.273 -100.25,228.328c-1.246,2.838 -4.053,4.671 -7.154,4.671c-3.1,0 -5.907,-1.833 -7.153,-4.671c-21.977,-50.055 -87.782,-199.932 -100.25,-228.328c-1.246,-2.838 -4.053,-4.672 -7.153,-4.672c-3.73,0 -9.017,0 -14.164,0c-3.693,0 -7.135,1.863 -9.156,4.954c-2.02,3.09 -2.344,6.991 -0.863,10.373c23.557,53.766 101.872,232.519 117.871,269.034c1.743,3.979 5.674,6.549 10.018,6.549c6.293,-0 15.408,-0 21.701,-0c4.344,-0 8.275,-2.57 10.018,-6.549c15.999,-36.515 94.315,-215.268 117.872,-269.034Z" style="fill:#fff;"/><path id="Diamond" d="M408.119,395.312c-1.675,2.901 -4.77,4.688 -8.119,4.688c-3.349,-0 -6.444,-1.787 -8.119,-4.688c-16.997,-29.44 -56.156,-97.264 -73.153,-126.704c-1.675,-2.901 -1.675,-6.474 0,-9.375c1.675,-2.901 4.77,-4.688 8.119,-4.688c33.995,0 112.311,0 146.306,0c3.349,0 6.444,1.787 8.119,4.688c1.675,2.901 1.675,6.474 -0,9.375c-16.997,29.44 -56.156,97.264 -73.153,126.704Z" style="fill:url(#_Linear2);"/></g></g><defs><linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.89859e-14,800,-800,4.89859e-14,400.001,3.31681e-10)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient><linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.77155e-14,289.317,-282.535,1.73003e-14,400,254.545)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient></defs></svg>
|
|
Before Width: | Height: | Size: 2.8 KiB |
@ -1,32 +1,10 @@
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlin)
|
kotlin("jvm") version "1.9.0"
|
||||||
alias(libs.plugins.shadow)
|
alias(libs.plugins.shadow)
|
||||||
application
|
|
||||||
`maven-publish`
|
|
||||||
signing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "app.revanced"
|
group = "app.revanced"
|
||||||
|
|
||||||
application {
|
|
||||||
mainClass = "app.revanced.cli.command.MainCommandKt"
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
google()
|
|
||||||
maven {
|
|
||||||
// A repository must be specified for some reason. "registry" is a dummy.
|
|
||||||
url = uri("https://maven.pkg.github.com/revanced/registry")
|
|
||||||
credentials {
|
|
||||||
username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR")
|
|
||||||
password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.revanced.patcher)
|
implementation(libs.revanced.patcher)
|
||||||
implementation(libs.revanced.library)
|
implementation(libs.revanced.library)
|
||||||
@ -36,15 +14,7 @@ dependencies {
|
|||||||
testImplementation(libs.kotlin.test)
|
testImplementation(libs.kotlin.test)
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin { jvmToolchain(11) }
|
||||||
compilerOptions {
|
|
||||||
jvmTarget.set(JvmTarget.JVM_11)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
java {
|
|
||||||
targetCompatibility = JavaVersion.VERSION_11
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
test {
|
test {
|
||||||
@ -59,36 +29,35 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
exclude("/prebuilt/linux/aapt", "/prebuilt/windows/aapt.exe", "/prebuilt/*/aapt_*")
|
manifest {
|
||||||
|
attributes("Main-Class" to "app.revanced.cli.command.MainCommandKt")
|
||||||
|
}
|
||||||
minimize {
|
minimize {
|
||||||
|
exclude(dependency("org.jetbrains.kotlin:.*"))
|
||||||
exclude(dependency("org.bouncycastle:.*"))
|
exclude(dependency("org.bouncycastle:.*"))
|
||||||
exclude(dependency("app.revanced:revanced-patcher"))
|
exclude(dependency("app.revanced:.*"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publish {
|
build {
|
||||||
dependsOn(shadowJar)
|
dependsOn(shadowJar)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Needed by gradle-semantic-release-plugin.
|
/*
|
||||||
// Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
Dummy task to hack gradle-semantic-release-plugin to release this project.
|
||||||
|
|
||||||
// The maven-publish is also necessary to make the signing plugin work.
|
Explanation:
|
||||||
publishing {
|
SemVer is a standard for versioning libraries.
|
||||||
repositories {
|
For that reason the semantic-release plugin uses the "publish" task to publish libraries.
|
||||||
mavenLocal()
|
However, this subproject is not a library, and the "publish" task is not available for this subproject.
|
||||||
}
|
Because semantic-release is not designed to handle this case, we need to hack it.
|
||||||
|
|
||||||
publications {
|
RE: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
|
||||||
create<MavenPublication>("revanced-cli-publication") {
|
*/
|
||||||
from(components["java"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signing {
|
register<DefaultTask>("publish") {
|
||||||
useGpgCmd()
|
group = "publishing"
|
||||||
|
description = "Dummy task to hack gradle-semantic-release-plugin to release ReVanced CLI"
|
||||||
sign(publishing.publications["revanced-cli-publication"])
|
dependsOn(build)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
# 💼 Prerequisites
|
# 💼 Prerequisites
|
||||||
|
|
||||||
To use ReVanced CLI, you will need to fulfill specific requirements.
|
To use ReVanced CLI, you will need to fulfil specific requirements.
|
||||||
|
|
||||||
## 🤝 Requirements
|
## 🤝 Requirements
|
||||||
|
|
||||||
- Java Runtime Environment 11 ([Azul Zulu JRE](https://www.azul.com/downloads/?version=java-11-lts&package=jre#zulu) or [OpenJDK](https://jdk.java.net/archive/))
|
- Java SDK 11 (Azul Zulu JDK or OpenJDK)
|
||||||
- [Android Debug Bridge (ADB)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device
|
- [Android Debug Bridge (adb)](https://developer.android.com/studio/command-line/adb) if you want to install the patched APK file on your device
|
||||||
- x86 or x86-64 (For [other architectures](https://github.com/ReVanced/revanced-manager/tree/main/android/app/src/main/jniLibs) use the `--custom-aapt2-binary` option)
|
- An ABI other than ARMv7 such as x86 or x86-64 (or a custom AAPT binary that supports ARMv7)
|
||||||
|
- ReVanced Patches
|
||||||
|
- ReVanced Integrations, if the patches require it
|
||||||
|
|
||||||
## ⏭️ Whats next
|
## ⏭️ Whats next
|
||||||
|
|
||||||
|
230
docs/1_usage.md
230
docs/1_usage.md
@ -1,171 +1,111 @@
|
|||||||
# 🛠️ Using ReVanced CLI
|
# 🛠️ Using ReVanced CLI
|
||||||
|
|
||||||
Learn how to use ReVanced CLI.
|
Learn how to ReVanced CLI.
|
||||||
The following examples will show you how to perform basic operations.
|
|
||||||
You can list patches, patch an app, uninstall, and install an app.
|
|
||||||
|
|
||||||
## 🚀 Show all commands
|
## ⚡ Setup ADB
|
||||||
|
|
||||||
|
1. Ensure that ADB is working
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb shell exit
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally, you can install the patched APK file on your device by mounting it on top of the original APK file.
|
||||||
|
You will need root permissions for this. Check if you have root permissions by running the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb shell su -c exit
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Get your device's serial
|
||||||
|
|
||||||
|
```bash
|
||||||
|
adb devices
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔨 Using ReVanced CLI
|
||||||
|
|
||||||
|
- ### ⚙️ Show all available options for ReVanced CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar revanced-cli.jar -h
|
java -jar revanced-cli.jar -h
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📃 List patches
|
- ### 📃 List patches from supplied patch bundles
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar revanced-cli.jar list-patches --with-packages --with-versions --with-options patches.rvp
|
java -jar revanced-cli.jar list-patches \
|
||||||
|
--with-packages \
|
||||||
|
--with-versions \
|
||||||
|
--with-options \
|
||||||
|
revanced-patches.jar [<patch-bundle> ...]
|
||||||
```
|
```
|
||||||
|
|
||||||
## 💉 Patch an app
|
- ### ⚙️ Generate options from patches using ReVanced CLI
|
||||||
|
|
||||||
To patch an app using the default list of patches, use the `patch` command:
|
This will generate an `options.json` file for the patches from a list of supplied patch bundles.
|
||||||
|
The file can be supplied to ReVanced CLI later on.
|
||||||
|
|
||||||
|
- ```bash
|
||||||
|
java -jar revanced-cli.jar options \
|
||||||
|
--path options.json \
|
||||||
|
--overwrite \
|
||||||
|
revanced-patches.jar [<patch-bundle> ...]
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**: A default `options.json` file will be automatically generated, if it does not exist
|
||||||
|
without any need for intervention when using the `patch` command.
|
||||||
|
|
||||||
|
- ### 💉 Use ReVanced CLI to patch an APK file but install without root permissions
|
||||||
|
|
||||||
|
This will install the patched APK file regularly on your device.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp input.apk
|
java -jar revanced-cli.jar patch \
|
||||||
|
--patch-bundle revanced-patches.jar \
|
||||||
|
--out output.apk \
|
||||||
|
--device-serial <device-serial> \
|
||||||
|
input.apk
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use multiple RVP files:
|
- ### 👾 Use ReVanced CLI to patch an APK file but install with root permissions
|
||||||
|
|
||||||
|
This will install the patched APK file on your device by mounting it on top of the original APK file.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp -p another-patches.rvp input.apk
|
adb install input.apk
|
||||||
|
java -jar revanced-cli.jar patch \
|
||||||
|
--patch-bundle revanced-patches.jar \
|
||||||
|
--include some-other-patch \
|
||||||
|
--exclude some-patch \
|
||||||
|
--out patched-output.apk \
|
||||||
|
--device-serial <device-serial> \
|
||||||
|
--mount \
|
||||||
|
input.apk
|
||||||
```
|
```
|
||||||
|
|
||||||
To change the default set of enabled or disabled patches, use the option `-e` or `-d` to enable or disable specific patches.
|
> **Note**: Some patches may require integrations
|
||||||
You can use the `list-patches` command to see which patches are enabled by default.
|
such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations).
|
||||||
|
Supply them with the option `--merge`. If any patches accepted by ReVanced Patcher require ReVanced Integrations,
|
||||||
|
they will be merged into the APK file automatically.
|
||||||
|
|
||||||
To only enable specific patches, you can use the option `--exclusive` combined with `-e`.
|
- ### 🗑️ Uninstall a patched APK file
|
||||||
Remember that the options `-e` and `-d` match the patch's name exactly. Here is an example:
|
```bash
|
||||||
|
java -jar revanced-cli.jar utility uninstall \
|
||||||
|
--package-name <package-name> \
|
||||||
|
<device-serial>
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note**: You can unmount an APK file
|
||||||
|
with the option `--unmount`.
|
||||||
|
|
||||||
|
- ### ️ ⚙️ Manually install an APK file
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp --exclusive -e "Patch name" -e "Another patch name" input.apk
|
java -jar revanced-cli.jar utility install \
|
||||||
|
-a input.apk \
|
||||||
|
<device-serial>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also use the options `--ei` or `--di` to enable or disable patches by their index.
|
> **Note**: You can mount an APK file
|
||||||
This is useful, if two patches happen to have the same name, or if typing the names is too cumbersome.
|
by supplying the package name of the app to mount the supplied APK file to over the option `--mount`.
|
||||||
To know the indices of patches, use the command `list-patches`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar list-patches patches.rvp
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you can use the indices to enable or disable patches:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp --ei 123 --di 456 input.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
You can combine the option `-e`, `-d`, `--ei`, `--di` and `--exclusive`. Here is an example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp --exclusive -e "Patch name" --ei 123 input.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> You can use the option `-i` to automatically install the patched app after patching.
|
|
||||||
> Make sure ADB is working:
|
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> adb shell exit
|
|
||||||
> ```
|
|
||||||
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> You can use the option `--mount` to mount the patched app on top of the un-patched app.
|
|
||||||
> Make sure you have root permissions and the same app you are patching and mounting over is installed on your device:
|
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> adb shell su -c exit
|
|
||||||
> adb install input.apk
|
|
||||||
> ```
|
|
||||||
|
|
||||||
Patches can have options you can set using the option `-O` alongside the option to include the patch by name or index.
|
|
||||||
To know the options of a patch, use the option `--with-options` when listing patches:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar list-patches --with-options patches.rvp
|
|
||||||
```
|
|
||||||
|
|
||||||
Each patch can have multiple options. You can set them using the option `-O`.
|
|
||||||
For example, to set the options for the patch with the name `Patch name`
|
|
||||||
with the key `key1` and `key2` to `value1` and `value2` respectively, use the following command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp -e "Patch name" -Okey1=value1 -Okey2=value2 input.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
If you want to set the option value to `null`, you can omit the value:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar patch -p patches.rvp -i "Patch name" -Okey1 input.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!WARNING]
|
|
||||||
> Option values are usually typed. If you set a value with the wrong type, the patch can fail.
|
|
||||||
> The value types can be seen when listing patches with the option `--with-options`.
|
|
||||||
>
|
|
||||||
> Example option values:
|
|
||||||
>
|
|
||||||
> - String: `string`
|
|
||||||
> - Boolean: `true`, `false`
|
|
||||||
> - Integer: `123`
|
|
||||||
> - Double: `1.0`
|
|
||||||
> - Float: `1.0f`
|
|
||||||
> - Long: `1234567890`, `1L`
|
|
||||||
> - List: `[item1,item2,item3]`
|
|
||||||
> - List of type `Any`: `[item1,123,true,1.0]`
|
|
||||||
> - Empty list of type `Any`: `[]`
|
|
||||||
> - Typed empty list: `int[]`
|
|
||||||
> - Typed and nested empty list: `[int[]]`
|
|
||||||
> - List with null value and two empty strings: `[null,\'\',\"\"]`
|
|
||||||
>
|
|
||||||
> Quotes and commas escaped in strings (`\"`, `\'`, `\,`) are parsed as part of the string.
|
|
||||||
> List items are recursively parsed, so you can escape values in lists:
|
|
||||||
>
|
|
||||||
> - Escaped integer as a string: `[\'123\']`
|
|
||||||
> - Escaped boolean as a string: `[\'true\']`
|
|
||||||
> - Escaped list as a string: `[\'[item1,item2]\']`
|
|
||||||
> - Escaped null value as a string: `[\'null\']`
|
|
||||||
> - List with an integer, an integer as a string and a string with a comma, and an escaped list: [`123,\'123\',str\,ing`,`\'[]\'`]
|
|
||||||
>
|
|
||||||
> Example command with an escaped integer as a string:
|
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> java -jar revanced-cli.jar -p patches.rvp -e "Patch name" -OstringKey=\'1\' input.apk
|
|
||||||
> ```
|
|
||||||
## 📦 Install an app manually
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar utility install -a input.apk
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> You can use the option `--mount` to mount the patched app on top of the un-patched app.
|
|
||||||
> Make sure you have root permissions and the same app you are patching and mounting over is installed on your device:
|
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> adb shell su -c exit
|
|
||||||
> adb install input.apk
|
|
||||||
> ```
|
|
||||||
|
|
||||||
## 🗑️ Uninstall an app manually
|
|
||||||
|
|
||||||
Here `<package-name>` is the package name of the app you want to uninstall:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar utility uninstall --package-name <package-name>
|
|
||||||
```
|
|
||||||
|
|
||||||
If the app is mounted, you need to unmount it by using the option `--unmount`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
java -jar revanced-cli.jar utility uninstall --package-name <package-name> --unmount
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> By default, the app is installed or uninstalled to the first connected device.
|
|
||||||
> You can append one or more devices by their serial to install or uninstall an app on your selected choice of devices:
|
|
||||||
>
|
|
||||||
> ```bash
|
|
||||||
> java -jar revanced-cli.jar utility uninstall --package-name <package-name> [<device-serial> ...]
|
|
||||||
> ```
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
# 🔨️ Building
|
|
||||||
|
|
||||||
Build ReVanced CLI from source.
|
|
||||||
|
|
||||||
## 📝 Requirements
|
|
||||||
|
|
||||||
- Java Development Kit 11 (Azul Zulu JRE or OpenJDK)
|
|
||||||
|
|
||||||
## 🏗️ Building
|
|
||||||
|
|
||||||
To build ReVanced CLI, follow these steps:
|
|
||||||
|
|
||||||
1. Clone the repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone git@github.com:ReVanced/revanced-cli.git
|
|
||||||
cd revanced-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Build the project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./gradlew build
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> If the build fails due to authentication, you may need to authenticate to GitHub Packages.
|
|
||||||
> Create a PAT with the scope `read:packages` [here](https://github.com/settings/tokens/new?scopes=read:packages&description=ReVanced) and add your token to ~/.gradle/gradle.properties.
|
|
||||||
>
|
|
||||||
> Example `gradle.properties` file:
|
|
||||||
>
|
|
||||||
> ```properties
|
|
||||||
> gpr.user = user
|
|
||||||
> gpr.key = key
|
|
||||||
> ```
|
|
||||||
|
|
||||||
After the build succeeds, the built JAR file will be located at `build/libs/revanced-cli-<version>-all.jar`.
|
|
@ -1,9 +1,8 @@
|
|||||||
# 💻 Documentation and guides of ReVanced CLI
|
# 💻 Documentation and guides of ReVanced CLI
|
||||||
|
|
||||||
This documentation contains topics around [ReVanced CLI](https://github.com/revanced/revanced-cli).
|
This documentation explains how to use [ReVanced CLI](https://github.com/revanced/revanced-cli).
|
||||||
|
|
||||||
## 📖 Table of contents
|
## 📖 Table of contents
|
||||||
|
|
||||||
1. [💼 Prerequisites](0_prerequisites.md)
|
1. [💼 Prerequisites](0_prerequisites.md)
|
||||||
2. [🛠️ Using ReVanced CLI](1_usage.md)
|
2. [🛠️ Using ReVanced CLI](1_usage.md)
|
||||||
3. [🔨 Building ReVanced CLI](2_building.md)
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
org.gradle.parallel = true
|
org.gradle.parallel = true
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 5.0.1
|
version = 4.0.0-dev.4
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
[versions]
|
[versions]
|
||||||
shadow = "8.1.1"
|
shadow = "8.1.1"
|
||||||
kotlin = "2.0.20"
|
kotlin-test = "1.8.20-RC"
|
||||||
kotlinx = "1.8.1"
|
kotlinx-coroutines-core = "1.7.3"
|
||||||
picocli = "4.7.6"
|
picocli = "4.7.3"
|
||||||
revanced-patcher = "21.0.0"
|
revanced-patcher = "15.0.3"
|
||||||
revanced-library = "3.1.0"
|
revanced-library = "1.1.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin-test" }
|
||||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx" }
|
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines-core" }
|
||||||
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
|
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
|
||||||
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
|
||||||
revanced-library = { module = "app.revanced:revanced-library-jvm", version.ref = "revanced-library" }
|
revanced-library = { module = "app.revanced:revanced-library", version.ref = "revanced-library" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
|
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,7 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
17
gradlew
vendored
17
gradlew
vendored
@ -83,8 +83,7 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@ -145,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@ -153,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC2039,SC3045
|
# shellcheck disable=SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@ -202,11 +201,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command;
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
# and any embedded shellness will be escaped.
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
6891
package-lock.json
generated
6891
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
"@saithodev/semantic-release-backmerge": "^3.1.0",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.2",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"gradle-semantic-release-plugin": "^1.10.1",
|
"gradle-semantic-release-plugin": "^1.7.6",
|
||||||
"semantic-release": "^24.1.2"
|
"semantic-release": "^20.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,23 @@
|
|||||||
|
val githubUsername: String = providers.gradleProperty("gpr.user").orNull ?: System.getenv("GITHUB_ACTOR")
|
||||||
|
val githubPassword: String = providers.gradleProperty("gpr.key").orNull ?: System.getenv("GITHUB_TOKEN")
|
||||||
|
|
||||||
|
dependencyResolutionManagement {
|
||||||
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
|
google()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
|
listOf("revanced-patcher", "jadb").forEach { repo ->
|
||||||
|
maven {
|
||||||
|
url = uri("https://maven.pkg.github.com/revanced/$repo")
|
||||||
|
credentials {
|
||||||
|
username = githubUsername
|
||||||
|
password = githubPassword
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = "revanced-cli"
|
rootProject.name = "revanced-cli"
|
@ -1,105 +0,0 @@
|
|||||||
package app.revanced.cli.command
|
|
||||||
|
|
||||||
import picocli.CommandLine
|
|
||||||
|
|
||||||
class OptionKeyConverter : CommandLine.ITypeConverter<String> {
|
|
||||||
override fun convert(value: String): String = value
|
|
||||||
}
|
|
||||||
|
|
||||||
class OptionValueConverter : CommandLine.ITypeConverter<Any?> {
|
|
||||||
override fun convert(value: String?): Any? {
|
|
||||||
value ?: return null
|
|
||||||
|
|
||||||
return when {
|
|
||||||
value.startsWith("[") && value.endsWith("]") -> {
|
|
||||||
val innerValue = value.substring(1, value.length - 1)
|
|
||||||
|
|
||||||
buildList {
|
|
||||||
var nestLevel = 0
|
|
||||||
var insideQuote = false
|
|
||||||
var escaped = false
|
|
||||||
|
|
||||||
val item = buildString {
|
|
||||||
for (char in innerValue) {
|
|
||||||
when (char) {
|
|
||||||
'\\' -> {
|
|
||||||
if (escaped || nestLevel != 0) {
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
escaped = !escaped
|
|
||||||
}
|
|
||||||
|
|
||||||
'"', '\'' -> {
|
|
||||||
if (!escaped) {
|
|
||||||
insideQuote = !insideQuote
|
|
||||||
} else {
|
|
||||||
escaped = false
|
|
||||||
}
|
|
||||||
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
'[' -> {
|
|
||||||
if (!insideQuote) {
|
|
||||||
nestLevel++
|
|
||||||
}
|
|
||||||
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
']' -> {
|
|
||||||
if (!insideQuote) {
|
|
||||||
nestLevel--
|
|
||||||
|
|
||||||
if (nestLevel == -1) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
',' -> if (nestLevel == 0) {
|
|
||||||
if (insideQuote) {
|
|
||||||
append(char)
|
|
||||||
} else {
|
|
||||||
add(convert(toString()))
|
|
||||||
setLength(0)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
append(char)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> append(char)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.isNotEmpty()) {
|
|
||||||
add(convert(item))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value.startsWith("\"") && value.endsWith("\"") -> value.substring(1, value.length - 1)
|
|
||||||
value.startsWith("'") && value.endsWith("'") -> value.substring(1, value.length - 1)
|
|
||||||
value.endsWith("f") -> value.dropLast(1).toFloat()
|
|
||||||
value.endsWith("L") -> value.dropLast(1).toLong()
|
|
||||||
value.equals("true", ignoreCase = true) -> true
|
|
||||||
value.equals("false", ignoreCase = true) -> false
|
|
||||||
value.toIntOrNull() != null -> value.toInt()
|
|
||||||
value.toLongOrNull() != null -> value.toLong()
|
|
||||||
value.toDoubleOrNull() != null -> value.toDouble()
|
|
||||||
value.toFloatOrNull() != null -> value.toFloat()
|
|
||||||
value == "null" -> null
|
|
||||||
value == "int[]" -> emptyList<Int>()
|
|
||||||
value == "long[]" -> emptyList<Long>()
|
|
||||||
value == "double[]" -> emptyList<Double>()
|
|
||||||
value == "float[]" -> emptyList<Float>()
|
|
||||||
value == "boolean[]" -> emptyList<Boolean>()
|
|
||||||
value == "string[]" -> emptyList<String>()
|
|
||||||
else -> value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,66 +0,0 @@
|
|||||||
package app.revanced.cli.command
|
|
||||||
|
|
||||||
import app.revanced.library.PackageName
|
|
||||||
import app.revanced.library.VersionMap
|
|
||||||
import app.revanced.library.mostCommonCompatibleVersions
|
|
||||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
|
||||||
import picocli.CommandLine
|
|
||||||
import java.io.File
|
|
||||||
import java.util.logging.Logger
|
|
||||||
|
|
||||||
@CommandLine.Command(
|
|
||||||
name = "list-versions",
|
|
||||||
description = [
|
|
||||||
"List the most common compatible versions of apps that are compatible " +
|
|
||||||
"with the patches from RVP files.",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
internal class ListCompatibleVersions : Runnable {
|
|
||||||
private val logger = Logger.getLogger(this::class.java.name)
|
|
||||||
|
|
||||||
@CommandLine.Parameters(
|
|
||||||
description = ["Paths to RVP files."],
|
|
||||||
arity = "1..*",
|
|
||||||
)
|
|
||||||
private lateinit var patchesFiles: Set<File>
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["-f", "--filter-package-names"],
|
|
||||||
description = ["Filter patches by package name."],
|
|
||||||
)
|
|
||||||
private var packageNames: Set<String>? = null
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["-u", "--count-unused-patches"],
|
|
||||||
description = ["Count patches that are not used by default."],
|
|
||||||
showDefaultValue = CommandLine.Help.Visibility.ALWAYS,
|
|
||||||
)
|
|
||||||
private var countUnusedPatches: Boolean = false
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
fun VersionMap.buildVersionsString(): String {
|
|
||||||
if (isEmpty()) return "Any"
|
|
||||||
|
|
||||||
fun buildPatchesCountString(count: Int) = if (count == 1) "1 patch" else "$count patches"
|
|
||||||
|
|
||||||
return entries.joinToString("\n") { (version, count) ->
|
|
||||||
"$version (${buildPatchesCountString(count)})"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun buildString(entry: Map.Entry<PackageName, VersionMap>) =
|
|
||||||
buildString {
|
|
||||||
val (name, versions) = entry
|
|
||||||
appendLine("Package name: $name")
|
|
||||||
appendLine("Most common compatible versions:")
|
|
||||||
appendLine(versions.buildVersionsString().prependIndent("\t"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val patches = loadPatchesFromJar(patchesFiles)
|
|
||||||
|
|
||||||
patches.mostCommonCompatibleVersions(
|
|
||||||
packageNames,
|
|
||||||
countUnusedPatches,
|
|
||||||
).entries.joinToString("\n", transform = ::buildString).let(logger::info)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,147 +1,98 @@
|
|||||||
package app.revanced.cli.command
|
package app.revanced.cli.command
|
||||||
|
|
||||||
import app.revanced.patcher.patch.Package
|
import app.revanced.patcher.PatchBundleLoader
|
||||||
import app.revanced.patcher.patch.Patch
|
import app.revanced.patcher.patch.Patch
|
||||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
import app.revanced.patcher.patch.options.PatchOption
|
||||||
import picocli.CommandLine.*
|
import picocli.CommandLine.*
|
||||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
import app.revanced.patcher.patch.Option as PatchOption
|
|
||||||
|
|
||||||
@Command(
|
|
||||||
name = "list-patches",
|
@Command(name = "list-patches", description = ["List patches from supplied patch bundles"])
|
||||||
description = ["List patches from supplied RVP files."],
|
|
||||||
)
|
|
||||||
internal object ListPatchesCommand : Runnable {
|
internal object ListPatchesCommand : Runnable {
|
||||||
private val logger = Logger.getLogger(this::class.java.name)
|
private val logger = Logger.getLogger(ListPatchesCommand::class.java.name)
|
||||||
|
|
||||||
@Parameters(
|
@Parameters(
|
||||||
description = ["Paths to RVP files."],
|
description = ["Paths to patch bundles"], arity = "1..*"
|
||||||
arity = "1..*",
|
|
||||||
)
|
)
|
||||||
private lateinit var patchesFiles: Set<File>
|
private lateinit var patchBundles: Array<File>
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-d", "--with-descriptions"],
|
names = ["-d", "--with-descriptions"], description = ["List their descriptions"], showDefaultValue = ALWAYS
|
||||||
description = ["List their descriptions."],
|
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
)
|
||||||
private var withDescriptions: Boolean = true
|
private var withDescriptions: Boolean = true
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-p", "--with-packages"],
|
names = ["-p", "--with-packages"],
|
||||||
description = ["List the packages the patches are compatible with."],
|
description = ["List the packages the patches are compatible with"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var withPackages: Boolean = false
|
private var withPackages: Boolean = false
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-v", "--with-versions"],
|
names = ["-v", "--with-versions"],
|
||||||
description = ["List the versions of the apps the patches are compatible with."],
|
description = ["List the versions of the apps the patches are compatible with"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var withVersions: Boolean = false
|
private var withVersions: Boolean = false
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-o", "--with-options"],
|
names = ["-o", "--with-options"], description = ["List the options of the patches"], showDefaultValue = ALWAYS
|
||||||
description = ["List the options of the patches."],
|
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
)
|
||||||
private var withOptions: Boolean = false
|
private var withOptions: Boolean = false
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-u", "--with-universal-patches"],
|
names = ["-f", "--filter-package-name"], description = ["Filter patches by package name"]
|
||||||
description = ["List patches which are compatible with any app."],
|
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
|
||||||
private var withUniversalPatches: Boolean = true
|
|
||||||
|
|
||||||
@Option(
|
|
||||||
names = ["-i", "--index"],
|
|
||||||
description = ["List the index of each patch in relation to the supplied RVP files."],
|
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
|
||||||
private var withIndex: Boolean = true
|
|
||||||
|
|
||||||
@Option(
|
|
||||||
names = ["-f", "--filter-package-name"],
|
|
||||||
description = ["Filter patches by package name."],
|
|
||||||
)
|
)
|
||||||
private var packageName: String? = null
|
private var packageName: String? = null
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
fun Package.buildString(): String {
|
fun Patch.CompatiblePackage.buildString() = buildString {
|
||||||
val (name, versions) = this
|
|
||||||
|
|
||||||
return buildString {
|
|
||||||
if (withVersions && versions != null) {
|
if (withVersions && versions != null) {
|
||||||
appendLine("Package name: $name")
|
appendLine("Package name: $name")
|
||||||
appendLine("Compatible versions:")
|
appendLine("Compatible versions:")
|
||||||
append(versions.joinToString("\n") { version -> version }.prependIndent("\t"))
|
append(versions!!.joinToString("\n") { version -> version }.prependIndent("\t"))
|
||||||
} else {
|
} else append("Package name: $name")
|
||||||
append("Package name: $name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PatchOption<*>.buildString() =
|
fun PatchOption<*>.buildString() = buildString {
|
||||||
buildString {
|
|
||||||
appendLine("Title: $title")
|
appendLine("Title: $title")
|
||||||
description?.let { appendLine("Description: $it") }
|
appendLine("Description: $description")
|
||||||
appendLine("Required: $required")
|
|
||||||
default?.let {
|
value?.let {
|
||||||
appendLine("Key: $key")
|
appendLine("Key: $key")
|
||||||
append("Default: $it")
|
append("Value: $it")
|
||||||
} ?: append("Key: $key")
|
} ?: append("Key: $key")
|
||||||
|
|
||||||
values?.let { values ->
|
|
||||||
appendLine("\nPossible values:")
|
|
||||||
append(values.map { "${it.value} (${it.key})" }.joinToString("\n").prependIndent("\t"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
append("\nType: $type")
|
fun Patch<*>.buildString() = buildString {
|
||||||
}
|
append("Name: $name")
|
||||||
|
|
||||||
fun IndexedValue<Patch<*>>.buildString() =
|
if (withDescriptions) append("\nDescription: $description")
|
||||||
let { (index, patch) ->
|
|
||||||
buildString {
|
|
||||||
if (withIndex) appendLine("Index: $index")
|
|
||||||
|
|
||||||
append("Name: ${patch.name}")
|
if (withOptions && options.isNotEmpty()) {
|
||||||
|
|
||||||
if (withDescriptions) append("\nDescription: ${patch.description}")
|
|
||||||
|
|
||||||
append("\nEnabled: ${patch.use}")
|
|
||||||
|
|
||||||
if (withOptions && patch.options.isNotEmpty()) {
|
|
||||||
appendLine("\nOptions:")
|
appendLine("\nOptions:")
|
||||||
append(
|
append(
|
||||||
patch.options.values.joinToString("\n\n") { option ->
|
options.values.joinToString("\n\n") { option ->
|
||||||
option.buildString()
|
option.buildString()
|
||||||
}.prependIndent("\t"),
|
}.prependIndent("\t")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (withPackages && patch.compatiblePackages != null) {
|
if (withPackages && compatiblePackages != null) {
|
||||||
appendLine("\nCompatible packages:")
|
appendLine("\nCompatible packages:")
|
||||||
append(
|
append(
|
||||||
patch.compatiblePackages!!.joinToString("\n") {
|
compatiblePackages!!.joinToString("\n") { it.buildString() }.prependIndent("\t")
|
||||||
it.buildString()
|
|
||||||
}.prependIndent("\t"),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun Patch<*>.filterCompatiblePackages(name: String) =
|
fun Patch<*>.anyPackageName(name: String) = compatiblePackages?.any { it.name == name } == true
|
||||||
compatiblePackages?.any { (compatiblePackageName, _) -> compatiblePackageName == name }
|
|
||||||
?: withUniversalPatches
|
|
||||||
|
|
||||||
val patches = loadPatchesFromJar(patchesFiles).withIndex().toList()
|
val patches = PatchBundleLoader.Jar(*patchBundles)
|
||||||
|
|
||||||
val filtered =
|
val filtered = packageName?.let { patches.filter { patch -> patch.anyPackageName(it) } } ?: patches
|
||||||
packageName?.let { patches.filter { (_, patch) -> patch.filterCompatiblePackages(it) } } ?: patches
|
|
||||||
|
|
||||||
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
|
if (filtered.isNotEmpty()) logger.info(filtered.joinToString("\n\n") { it.buildString() })
|
||||||
}
|
}
|
||||||
|
@ -7,36 +7,33 @@ import picocli.CommandLine.Command
|
|||||||
import picocli.CommandLine.IVersionProvider
|
import picocli.CommandLine.IVersionProvider
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
Logger.setDefault()
|
Logger.setDefault()
|
||||||
CommandLine(MainCommand).execute(*args).let(System::exit)
|
CommandLine(MainCommand).execute(*args)
|
||||||
}
|
}
|
||||||
|
|
||||||
private object CLIVersionProvider : IVersionProvider {
|
private object CLIVersionProvider : IVersionProvider {
|
||||||
override fun getVersion() =
|
override fun getVersion() = arrayOf(
|
||||||
arrayOf(
|
|
||||||
MainCommand::class.java.getResourceAsStream(
|
MainCommand::class.java.getResourceAsStream(
|
||||||
"/app/revanced/cli/version.properties",
|
"/app/revanced/cli/version.properties"
|
||||||
)?.use { stream ->
|
)?.use { stream ->
|
||||||
Properties().apply {
|
Properties().apply { load(stream) }.let {
|
||||||
load(stream)
|
|
||||||
}.let {
|
|
||||||
"ReVanced CLI v${it.getProperty("version")}"
|
"ReVanced CLI v${it.getProperty("version")}"
|
||||||
}
|
}
|
||||||
} ?: "ReVanced CLI",
|
} ?: "ReVanced CLI")
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "revanced-cli",
|
name = "revanced-cli",
|
||||||
description = ["Command line application to use ReVanced."],
|
description = ["Command line application to use ReVanced"],
|
||||||
mixinStandardHelpOptions = true,
|
mixinStandardHelpOptions = true,
|
||||||
versionProvider = CLIVersionProvider::class,
|
versionProvider = CLIVersionProvider::class,
|
||||||
subcommands = [
|
subcommands = [
|
||||||
PatchCommand::class,
|
|
||||||
ListPatchesCommand::class,
|
ListPatchesCommand::class,
|
||||||
ListCompatibleVersions::class,
|
PatchCommand::class,
|
||||||
|
OptionsCommand::class,
|
||||||
UtilityCommand::class,
|
UtilityCommand::class,
|
||||||
],
|
]
|
||||||
)
|
)
|
||||||
private object MainCommand
|
private object MainCommand
|
53
src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt
Normal file
53
src/main/kotlin/app/revanced/cli/command/OptionsCommand.kt
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package app.revanced.cli.command
|
||||||
|
|
||||||
|
import app.revanced.library.Options
|
||||||
|
import app.revanced.library.Options.setOptions
|
||||||
|
import app.revanced.patcher.PatchBundleLoader
|
||||||
|
import picocli.CommandLine
|
||||||
|
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||||
|
import java.io.File
|
||||||
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
@CommandLine.Command(
|
||||||
|
name = "options",
|
||||||
|
description = ["Generate options file from patches"],
|
||||||
|
)
|
||||||
|
internal object OptionsCommand : Runnable {
|
||||||
|
private val logger = Logger.getLogger(OptionsCommand::class.java.name)
|
||||||
|
|
||||||
|
@CommandLine.Parameters(
|
||||||
|
description = ["Paths to patch bundles"], arity = "1..*"
|
||||||
|
)
|
||||||
|
private lateinit var patchBundles: Array<File>
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = ["-p", "--path"], description = ["Path to patch options JSON file"], showDefaultValue = ALWAYS
|
||||||
|
)
|
||||||
|
private var filePath: File = File("options.json")
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = ["-o", "--overwrite"], description = ["Overwrite existing options file"], showDefaultValue = ALWAYS
|
||||||
|
)
|
||||||
|
private var overwrite: Boolean = false
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = ["-u", "--update"],
|
||||||
|
description = ["Update existing options by adding missing and removing non-existent options"],
|
||||||
|
showDefaultValue = ALWAYS
|
||||||
|
)
|
||||||
|
private var update: Boolean = false
|
||||||
|
|
||||||
|
override fun run() = try {
|
||||||
|
PatchBundleLoader.Jar(*patchBundles).let { patches ->
|
||||||
|
if (!filePath.exists() || overwrite) {
|
||||||
|
if (update && filePath.exists()) patches.setOptions(filePath)
|
||||||
|
|
||||||
|
Options.serialize(patches, prettyPrint = true).let(filePath::writeText)
|
||||||
|
} else throw OptionsFileAlreadyExistsException()
|
||||||
|
}
|
||||||
|
} catch (ex: OptionsFileAlreadyExistsException) {
|
||||||
|
logger.severe("Options file already exists, use --overwrite to override it")
|
||||||
|
}
|
||||||
|
|
||||||
|
class OptionsFileAlreadyExistsException : Exception()
|
||||||
|
}
|
@ -1,16 +1,15 @@
|
|||||||
package app.revanced.cli.command
|
package app.revanced.cli.command
|
||||||
|
|
||||||
import app.revanced.library.ApkUtils
|
import app.revanced.library.ApkUtils
|
||||||
import app.revanced.library.ApkUtils.applyTo
|
import app.revanced.library.Options
|
||||||
import app.revanced.library.installation.installer.*
|
import app.revanced.library.Options.setOptions
|
||||||
import app.revanced.library.setOptions
|
import app.revanced.library.adb.AdbManager
|
||||||
|
import app.revanced.patcher.PatchBundleLoader
|
||||||
|
import app.revanced.patcher.PatchSet
|
||||||
import app.revanced.patcher.Patcher
|
import app.revanced.patcher.Patcher
|
||||||
import app.revanced.patcher.PatcherConfig
|
import app.revanced.patcher.PatcherOptions
|
||||||
import app.revanced.patcher.patch.Patch
|
|
||||||
import app.revanced.patcher.patch.loadPatchesFromJar
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import picocli.CommandLine
|
import picocli.CommandLine
|
||||||
import picocli.CommandLine.ArgGroup
|
|
||||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||||
import picocli.CommandLine.Model.CommandSpec
|
import picocli.CommandLine.Model.CommandSpec
|
||||||
import picocli.CommandLine.Spec
|
import picocli.CommandLine.Spec
|
||||||
@ -19,435 +18,314 @@ import java.io.PrintWriter
|
|||||||
import java.io.StringWriter
|
import java.io.StringWriter
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
|
||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
name = "patch",
|
name = "patch", description = ["Patch an APK file"]
|
||||||
description = ["Patch an APK file."],
|
|
||||||
)
|
)
|
||||||
internal object PatchCommand : Runnable {
|
internal object PatchCommand : Runnable {
|
||||||
private val logger = Logger.getLogger(this::class.java.name)
|
private val logger = Logger.getLogger(PatchCommand::class.java.name)
|
||||||
|
|
||||||
@Spec
|
@Spec
|
||||||
private lateinit var spec: CommandSpec
|
lateinit var spec: CommandSpec // injected by picocli
|
||||||
|
|
||||||
@ArgGroup(exclusive = false, multiplicity = "0..*")
|
private lateinit var apk: File
|
||||||
private var selection = mutableSetOf<Selection>()
|
|
||||||
|
|
||||||
internal class Selection {
|
private var integrations = listOf<File>()
|
||||||
@ArgGroup(exclusive = false)
|
|
||||||
internal var enabled: EnableSelection? = null
|
|
||||||
|
|
||||||
internal class EnableSelection {
|
private var patchBundles = emptyList<File>()
|
||||||
@ArgGroup(multiplicity = "1")
|
|
||||||
internal lateinit var selector: EnableSelector
|
|
||||||
|
|
||||||
internal class EnableSelector {
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["-e", "--enable"],
|
|
||||||
description = ["Name of the patch."],
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
internal var name: String? = null
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--ei"],
|
names = ["-i", "--include"], description = ["List of patches to include"]
|
||||||
description = ["Index of the patch in the combined list of the supplied RVP files."],
|
|
||||||
required = true,
|
|
||||||
)
|
)
|
||||||
internal var index: Int? = null
|
private var includedPatches = arrayOf<String>()
|
||||||
}
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-O", "--options"],
|
names = ["-e", "--exclude"], description = ["List of patches to exclude"]
|
||||||
description = ["Option values keyed by option keys."],
|
|
||||||
mapFallbackValue = CommandLine.Option.NULL_VALUE,
|
|
||||||
converter = [OptionKeyConverter::class, OptionValueConverter::class],
|
|
||||||
)
|
)
|
||||||
internal var options = mutableMapOf<String, Any?>()
|
private var excludedPatches = arrayOf<String>()
|
||||||
}
|
|
||||||
|
|
||||||
@ArgGroup(exclusive = false)
|
|
||||||
internal var disable: DisableSelection? = null
|
|
||||||
|
|
||||||
internal class DisableSelection {
|
|
||||||
@ArgGroup(multiplicity = "1")
|
|
||||||
internal lateinit var selector: DisableSelector
|
|
||||||
|
|
||||||
internal class DisableSelector {
|
|
||||||
@CommandLine.Option(
|
|
||||||
names = ["-d", "--disable"],
|
|
||||||
description = ["Name of the patch."],
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
internal var name: String? = null
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--di"],
|
names = ["--options"], description = ["Path to patch options JSON file"], showDefaultValue = ALWAYS
|
||||||
description = ["Index of the patch in the combined list of the supplied RVP files."],
|
|
||||||
required = true,
|
|
||||||
)
|
)
|
||||||
internal var index: Int? = null
|
private var optionsFile: File = File("options.json")
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--exclusive"],
|
names = ["--exclusive"],
|
||||||
description = ["Disable all patches except the ones enabled."],
|
description = ["Only include patches that are explicitly specified to be included"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var exclusive = false
|
private var exclusive = false
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-f","--force"],
|
names = ["-f","--force"],
|
||||||
description = ["Don't check for compatibility with the supplied APK's version."],
|
description = ["Bypass compatibility checks for the supplied APK's version"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var force: Boolean = false
|
private var force: Boolean = false
|
||||||
|
|
||||||
private var outputFilePath: File? = null
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-o", "--out"],
|
names = ["-o", "--out"], description = ["Path to save the patched APK file to"], required = true
|
||||||
description = ["Path to save the patched APK file to. Defaults to the same path as the supplied APK file."],
|
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
private lateinit var outputFilePath: File
|
||||||
private fun setOutputFilePath(outputFilePath: File?) {
|
|
||||||
this.outputFilePath = outputFilePath?.absoluteFile
|
|
||||||
}
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-i", "--install"],
|
names = ["-d", "--device-serial"], description = ["ADB device serial to install to"], showDefaultValue = ALWAYS
|
||||||
description = ["Serial of the ADB device to install to. If not specified, the first connected device will be used."],
|
|
||||||
// Empty string to indicate that the first connected device should be used.
|
|
||||||
fallbackValue = "",
|
|
||||||
arity = "0..1",
|
|
||||||
)
|
)
|
||||||
private var deviceSerial: String? = null
|
private var deviceSerial: String? = null
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--mount"],
|
names = ["--mount"], description = ["Install by mounting the patched APK file"], showDefaultValue = ALWAYS
|
||||||
description = ["Install the patched APK file by mounting."],
|
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
)
|
||||||
private var mount: Boolean = false
|
private var mount: Boolean = false
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--keystore"],
|
names = ["--keystore"], description = ["Path to the keystore to sign the patched APK file with"],
|
||||||
description = [
|
|
||||||
"Path to the keystore file containing a private key and certificate pair to sign the patched APK file with. " +
|
|
||||||
"Defaults to the same directory as the supplied APK file.",
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
private var keyStoreFilePath: File? = null
|
private var keystoreFilePath: File? = null
|
||||||
|
|
||||||
|
// key store password
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--keystore-password"],
|
names = ["--keystore-password"],
|
||||||
description = ["Password of the keystore. Empty password by default."],
|
description = ["The password of the keystore to sign the patched APK file with"],
|
||||||
)
|
)
|
||||||
private var keyStorePassword: String? = null // Empty password by default
|
private var keyStorePassword: String? = null // Empty password by default
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--keystore-entry-alias"],
|
names = ["--alias"], description = ["The alias of the key from the keystore to sign the patched APK file with"],
|
||||||
description = ["Alias of the private key and certificate pair keystore entry."],
|
showDefaultValue = ALWAYS
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
)
|
||||||
private var keyStoreEntryAlias = "ReVanced Key"
|
private var alias = "ReVanced Key"
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--keystore-entry-password"],
|
names = ["--keystore-entry-password"],
|
||||||
description = ["Password of the keystore entry."],
|
description = ["The password of the entry from the keystore for the key to sign the patched APK file with"]
|
||||||
)
|
)
|
||||||
private var keyStoreEntryPassword = "" // Empty password by default
|
private var password = "" // Empty password by default
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--signer"],
|
names = ["--signer"], description = ["The name of the signer to sign the patched APK file with"],
|
||||||
description = ["The name of the signer to sign the patched APK file with."],
|
showDefaultValue = ALWAYS
|
||||||
showDefaultValue = ALWAYS,
|
|
||||||
)
|
)
|
||||||
private var signer = "ReVanced"
|
private var signer = "ReVanced"
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-t", "--temporary-files-path"],
|
names = ["-r", "--resource-cache"],
|
||||||
description = ["Path to store temporary files."],
|
description = ["Path to temporary resource cache directory"],
|
||||||
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var temporaryFilesPath: File? = null
|
private var resourceCachePath = File("revanced-resource-cache")
|
||||||
|
|
||||||
private var aaptBinaryPath: File? = null
|
private var aaptBinaryPath: File? = null
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--purge"],
|
names = ["-p", "--purge"],
|
||||||
description = ["Purge temporary files directory after patching."],
|
description = ["Purge the temporary resource cache directory after patching"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var purge: Boolean = false
|
private var purge: Boolean = false
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = ["-w", "--warn"],
|
||||||
|
description = ["Warn if a patch can not be found in the supplied patch bundles"],
|
||||||
|
showDefaultValue = ALWAYS
|
||||||
|
)
|
||||||
|
private var warn: Boolean = false
|
||||||
|
|
||||||
@CommandLine.Parameters(
|
@CommandLine.Parameters(
|
||||||
description = ["APK file to patch."],
|
description = ["APK file to be patched"], arity = "1..1"
|
||||||
arity = "1",
|
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
private fun setApk(apk: File) {
|
private fun setApk(apk: File) {
|
||||||
if (!apk.exists()) {
|
if (!apk.exists()) throw CommandLine.ParameterException(
|
||||||
throw CommandLine.ParameterException(
|
|
||||||
spec.commandLine(),
|
spec.commandLine(),
|
||||||
"APK file ${apk.path} does not exist",
|
"APK file ${apk.name} does not exist"
|
||||||
)
|
)
|
||||||
}
|
|
||||||
this.apk = apk
|
this.apk = apk
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var apk: File
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["-p", "--patches"],
|
names = ["-m", "--merge"], description = ["One or more DEX files or containers to merge into the APK"]
|
||||||
description = ["One or more path to RVP files."],
|
|
||||||
required = true,
|
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
private fun setPatchesFile(patchesFiles: Set<File>) {
|
private fun setIntegrations(integrations: Array<File>) {
|
||||||
patchesFiles.firstOrNull { !it.exists() }?.let {
|
integrations.firstOrNull { !it.exists() }?.let {
|
||||||
throw CommandLine.ParameterException(spec.commandLine(), "${it.name} can't be found")
|
throw CommandLine.ParameterException(spec.commandLine(), "Integrations file ${it.name} does not exist")
|
||||||
}
|
}
|
||||||
this.patchesFiles = patchesFiles
|
this.integrations += integrations
|
||||||
}
|
}
|
||||||
|
|
||||||
private var patchesFiles = emptySet<File>()
|
|
||||||
|
|
||||||
@CommandLine.Option(
|
@CommandLine.Option(
|
||||||
names = ["--custom-aapt2-binary"],
|
names = ["-b", "--patch-bundle"], description = ["One or more bundles of patches"], required = true
|
||||||
description = ["Path to a custom AAPT binary to compile resources with."],
|
)
|
||||||
|
@Suppress("unused")
|
||||||
|
private fun setPatchBundles(patchBundles: Array<File>) {
|
||||||
|
patchBundles.firstOrNull { !it.exists() }?.let {
|
||||||
|
throw CommandLine.ParameterException(spec.commandLine(), "Patch bundle ${it.name} does not exist")
|
||||||
|
}
|
||||||
|
this.patchBundles = patchBundles.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandLine.Option(
|
||||||
|
names = ["--custom-aapt2-binary"], description = ["Path to a custom AAPT binary to compile resources with"]
|
||||||
)
|
)
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
private fun setAaptBinaryPath(aaptBinaryPath: File) {
|
private fun setAaptBinaryPath(aaptBinaryPath: File) {
|
||||||
if (!aaptBinaryPath.exists()) {
|
if (!aaptBinaryPath.exists()) throw CommandLine.ParameterException(
|
||||||
throw CommandLine.ParameterException(
|
|
||||||
spec.commandLine(),
|
spec.commandLine(),
|
||||||
"AAPT binary ${aaptBinaryPath.name} does not exist",
|
"AAPT binary ${aaptBinaryPath.name} does not exist"
|
||||||
)
|
)
|
||||||
}
|
|
||||||
this.aaptBinaryPath = aaptBinaryPath
|
this.aaptBinaryPath = aaptBinaryPath
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
// region Setup
|
val adbManager = deviceSerial?.let { serial -> AdbManager.getAdbManager(serial, mount) }
|
||||||
|
|
||||||
val outputFilePath =
|
|
||||||
outputFilePath ?: File("").absoluteFile.resolve(
|
|
||||||
"${apk.nameWithoutExtension}-patched.${apk.extension}",
|
|
||||||
)
|
|
||||||
|
|
||||||
val temporaryFilesPath =
|
|
||||||
temporaryFilesPath ?: outputFilePath.parentFile.resolve(
|
|
||||||
"${outputFilePath.nameWithoutExtension}-temporary-files",
|
|
||||||
)
|
|
||||||
|
|
||||||
val keystoreFilePath =
|
|
||||||
keyStoreFilePath ?: outputFilePath.parentFile
|
|
||||||
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
|
|
||||||
|
|
||||||
val installer = if (deviceSerial != null) {
|
|
||||||
val deviceSerial = deviceSerial!!.ifEmpty { null }
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (mount) {
|
|
||||||
AdbRootInstaller(deviceSerial)
|
|
||||||
} else {
|
|
||||||
AdbInstaller(deviceSerial)
|
|
||||||
}
|
|
||||||
} catch (e: DeviceNotFoundException) {
|
|
||||||
if (deviceSerial?.isNotEmpty() == true) {
|
|
||||||
logger.severe(
|
|
||||||
"Device with serial $deviceSerial not found to install to. " +
|
|
||||||
"Ensure the device is connected and the serial is correct when using the --install option.",
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
logger.severe(
|
|
||||||
"No device has been found to install to. " +
|
|
||||||
"Ensure a device is connected when using the --install option.",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Load patches
|
// region Load patches
|
||||||
|
|
||||||
logger.info("Loading patches")
|
logger.info("Loading patches")
|
||||||
|
|
||||||
val patches = loadPatchesFromJar(patchesFiles)
|
val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray())
|
||||||
|
|
||||||
// endregion
|
// Warn if a patch can not be found in the supplied patch bundles.
|
||||||
|
if (warn) patches.map { it.name }.toHashSet().let { availableNames ->
|
||||||
val patcherTemporaryFilesPath = temporaryFilesPath.resolve("patcher")
|
arrayOf(*includedPatches, *excludedPatches).filter { name ->
|
||||||
|
!availableNames.contains(name)
|
||||||
val (packageName, patcherResult) = Patcher(
|
}
|
||||||
PatcherConfig(
|
}.let { unknownPatches ->
|
||||||
apk,
|
if (unknownPatches.isEmpty()) return@let
|
||||||
patcherTemporaryFilesPath,
|
logger.warning("Unknown input of patches:\n${unknownPatches.joinToString("\n")}")
|
||||||
aaptBinaryPath?.path,
|
}
|
||||||
patcherTemporaryFilesPath.absolutePath,
|
|
||||||
),
|
|
||||||
).use { patcher ->
|
|
||||||
val packageName = patcher.context.packageMetadata.packageName
|
|
||||||
val packageVersion = patcher.context.packageMetadata.packageVersion
|
|
||||||
|
|
||||||
val filteredPatches = patches.filterPatchSelection(packageName, packageVersion)
|
|
||||||
|
|
||||||
logger.info("Setting patch options")
|
logger.info("Setting patch options")
|
||||||
|
|
||||||
val patchesList = patches.toList()
|
optionsFile.let {
|
||||||
selection.filter { it.enabled != null }.associate {
|
if (it.exists()) patches.setOptions(it)
|
||||||
val enabledSelection = it.enabled!!
|
else Options.serialize(patches, prettyPrint = true).let(it::writeText)
|
||||||
|
}
|
||||||
|
|
||||||
(enabledSelection.selector.name ?: patchesList[enabledSelection.selector.index!!].name!!) to
|
// endregion
|
||||||
enabledSelection.options
|
|
||||||
}.let(filteredPatches::setOptions)
|
|
||||||
|
|
||||||
patcher += filteredPatches
|
Patcher(
|
||||||
|
PatcherOptions(
|
||||||
|
apk,
|
||||||
|
resourceCachePath,
|
||||||
|
aaptBinaryPath?.path,
|
||||||
|
resourceCachePath.absolutePath,
|
||||||
|
)
|
||||||
|
).use { patcher ->
|
||||||
|
// region Patch
|
||||||
|
|
||||||
|
val patcherResult = patcher.apply {
|
||||||
|
acceptIntegrations(integrations)
|
||||||
|
acceptPatches(filterPatchSelection(patches))
|
||||||
|
|
||||||
// Execute patches.
|
// Execute patches.
|
||||||
runBlocking {
|
runBlocking {
|
||||||
patcher().collect { patchResult ->
|
apply(false).collect { patchResult ->
|
||||||
val exception = patchResult.exception
|
patchResult.exception?.let {
|
||||||
?: return@collect logger.info("\"${patchResult.patch}\" succeeded")
|
|
||||||
|
|
||||||
StringWriter().use { writer ->
|
StringWriter().use { writer ->
|
||||||
exception.printStackTrace(PrintWriter(writer))
|
it.printStackTrace(PrintWriter(writer))
|
||||||
|
logger.severe("${patchResult.patch.name} failed:\n$writer")
|
||||||
logger.severe("\"${patchResult.patch}\" failed:\n$writer")
|
}
|
||||||
|
} ?: logger.info("${patchResult.patch.name} succeeded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}.get()
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Save
|
||||||
|
|
||||||
|
val tempFile = resourceCachePath.resolve(apk.name).apply {
|
||||||
|
ApkUtils.copyAligned(apk, this, patcherResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
patcher.context.packageMetadata.packageName to patcher.get()
|
val keystoreFilePath = keystoreFilePath ?: outputFilePath.absoluteFile.parentFile
|
||||||
}
|
.resolve("${outputFilePath.nameWithoutExtension}.keystore")
|
||||||
|
|
||||||
// region Save.
|
if (!mount) ApkUtils.sign(
|
||||||
|
tempFile,
|
||||||
apk.copyTo(temporaryFilesPath.resolve(apk.name), overwrite = true).apply {
|
|
||||||
patcherResult.applyTo(this)
|
|
||||||
}.let { patchedApkFile ->
|
|
||||||
if (!mount) {
|
|
||||||
ApkUtils.signApk(
|
|
||||||
patchedApkFile,
|
|
||||||
outputFilePath,
|
outputFilePath,
|
||||||
signer,
|
ApkUtils.SigningOptions(
|
||||||
ApkUtils.KeyStoreDetails(
|
|
||||||
keystoreFilePath,
|
keystoreFilePath,
|
||||||
keyStorePassword,
|
keyStorePassword,
|
||||||
keyStoreEntryAlias,
|
alias,
|
||||||
keyStoreEntryPassword,
|
password,
|
||||||
),
|
signer
|
||||||
|
)
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
patchedApkFile.copyTo(outputFilePath, overwrite = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Saved to $outputFilePath")
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Install.
|
// region Install
|
||||||
|
|
||||||
deviceSerial?.let {
|
adbManager?.install(AdbManager.Apk(outputFilePath, patcher.context.packageMetadata.packageName))
|
||||||
runBlocking {
|
|
||||||
when (val result = installer!!.install(Installer.Apk(outputFilePath, packageName))) {
|
|
||||||
RootInstallerResult.FAILURE -> logger.severe("Failed to mount the patched APK file")
|
|
||||||
is AdbInstallerResult.Failure -> logger.severe(result.exception.toString())
|
|
||||||
else -> logger.info("Installed the patched APK file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
}
|
||||||
|
|
||||||
if (purge) {
|
if (purge) {
|
||||||
logger.info("Purging temporary files")
|
logger.info("Purging temporary files")
|
||||||
purge(temporaryFilesPath)
|
purge(resourceCachePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter the patches based on the selection.
|
* Filter the patches to be added to the patcher. The filter is based on the following:
|
||||||
*
|
*
|
||||||
* @param packageName The package name of the APK file to be patched.
|
* @param patches The patches to filter.
|
||||||
* @param packageVersion The version of the APK file to be patched.
|
|
||||||
* @return The filtered patches.
|
* @return The filtered patches.
|
||||||
*/
|
*/
|
||||||
private fun Set<Patch<*>>.filterPatchSelection(
|
private fun Patcher.filterPatchSelection(patches: PatchSet) = buildList {
|
||||||
packageName: String,
|
val packageName = context.packageMetadata.packageName
|
||||||
packageVersion: String,
|
val packageVersion = context.packageMetadata.packageVersion
|
||||||
): Set<Patch<*>> = buildSet {
|
|
||||||
val enabledPatchesByName =
|
|
||||||
selection.mapNotNull { it.enabled?.selector?.name }.toSet()
|
|
||||||
val enabledPatchesByIndex =
|
|
||||||
selection.mapNotNull { it.enabled?.selector?.index }.toSet()
|
|
||||||
|
|
||||||
val disabledPatches =
|
patches.forEach patch@{ patch ->
|
||||||
selection.mapNotNull { it.disable?.selector?.name }.toSet()
|
|
||||||
val disabledPatchesByIndex =
|
|
||||||
selection.mapNotNull { it.disable?.selector?.index }.toSet()
|
|
||||||
|
|
||||||
this@filterPatchSelection.withIndex().forEach patchLoop@{ (i, patch) ->
|
|
||||||
val patchName = patch.name!!
|
val patchName = patch.name!!
|
||||||
|
|
||||||
val isManuallyDisabled = patchName in disabledPatches || i in disabledPatchesByIndex
|
val explicitlyExcluded = excludedPatches.contains(patchName)
|
||||||
if (isManuallyDisabled) return@patchLoop logger.info("\"$patchName\" disabled manually")
|
if (explicitlyExcluded) return@patch logger.info("Excluding $patchName")
|
||||||
|
|
||||||
// Make sure the patch is compatible with the supplied APK files package name and version.
|
// Make sure the patch is compatible with the supplied APK files package name and version.
|
||||||
patch.compatiblePackages?.let { packages ->
|
patch.compatiblePackages?.let { packages ->
|
||||||
packages.singleOrNull { (name, _) -> name == packageName }?.let { (_, versions) ->
|
packages.singleOrNull { it.name == packageName }?.let { `package` ->
|
||||||
if (versions?.isEmpty() == true) {
|
val matchesVersion = force || `package`.versions?.let {
|
||||||
return@patchLoop logger.warning("\"$patchName\" incompatible with \"$packageName\"")
|
it.any { version -> version == packageVersion }
|
||||||
}
|
} ?: true
|
||||||
|
|
||||||
val matchesVersion =
|
if (!matchesVersion) return@patch logger.warning(
|
||||||
force || versions?.let { it.any { version -> version == packageVersion } } ?: true
|
"$patchName is incompatible with version $packageVersion. "
|
||||||
|
+ "This patch is only compatible with version "
|
||||||
if (!matchesVersion) {
|
+ packages.joinToString(";") { pkg ->
|
||||||
return@patchLoop logger.warning(
|
"${pkg.name}: ${pkg.versions!!.joinToString(", ")}"
|
||||||
"\"$patchName\" incompatible with $packageName $packageVersion " +
|
|
||||||
"but compatible with " +
|
|
||||||
packages.joinToString("; ") { (packageName, versions) ->
|
|
||||||
packageName + " " + versions!!.joinToString(", ")
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} ?: return@patchLoop logger.fine(
|
|
||||||
"\"$patchName\" incompatible with $packageName. " +
|
|
||||||
"It is only compatible with " +
|
|
||||||
packages.joinToString(", ") { (name, _) -> name },
|
|
||||||
)
|
)
|
||||||
|
} ?: return@patch logger.fine(
|
||||||
|
"$patchName is incompatible with $packageName. "
|
||||||
|
+ "This patch is only compatible with "
|
||||||
|
+ packages.joinToString(", ") { `package` -> `package`.name })
|
||||||
|
|
||||||
return@let
|
return@let
|
||||||
} ?: logger.fine("\"$patchName\" has no package constraints")
|
} ?: logger.fine("$patchName has no constraint on packages.")
|
||||||
|
|
||||||
val isEnabled = !exclusive && patch.use
|
// If the patch is implicitly used, it will be only included if [exclusive] is false.
|
||||||
val isManuallyEnabled = patchName in enabledPatchesByName || i in enabledPatchesByIndex
|
val implicitlyIncluded = !exclusive && patch.use
|
||||||
|
// If the patch is explicitly used, it will be included even if [exclusive] is false.
|
||||||
|
val explicitlyIncluded = includedPatches.contains(patchName)
|
||||||
|
|
||||||
if (!(isEnabled || isManuallyEnabled)) {
|
val included = implicitlyIncluded || explicitlyIncluded
|
||||||
return@patchLoop logger.info("\"$patchName\" disabled")
|
if (!included) return@patch logger.info("$patchName excluded") // Case 1.
|
||||||
}
|
|
||||||
|
logger.fine("Adding $patchName")
|
||||||
|
|
||||||
add(patch)
|
add(patch)
|
||||||
|
|
||||||
logger.fine("\"$patchName\" added")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun purge(resourceCachePath: File) {
|
private fun purge(resourceCachePath: File) {
|
||||||
val result =
|
val result = if (resourceCachePath.deleteRecursively()) "Purged resource cache directory"
|
||||||
if (resourceCachePath.deleteRecursively()) {
|
else "Failed to purge resource cache directory"
|
||||||
"Purged resource cache directory"
|
|
||||||
} else {
|
|
||||||
"Failed to purge resource cache directory"
|
|
||||||
}
|
|
||||||
logger.info(result)
|
logger.info(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,63 +1,38 @@
|
|||||||
package app.revanced.cli.command.utility
|
package app.revanced.cli.command.utility
|
||||||
|
|
||||||
import app.revanced.library.installation.installer.*
|
import app.revanced.library.adb.AdbManager
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import picocli.CommandLine.*
|
import picocli.CommandLine.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "install",
|
name = "install", description = ["Install an APK file to devices with the supplied ADB device serials"]
|
||||||
description = ["Install an APK file."],
|
|
||||||
)
|
)
|
||||||
internal object InstallCommand : Runnable {
|
internal object InstallCommand : Runnable {
|
||||||
private val logger = Logger.getLogger(this::class.java.name)
|
private val logger = Logger.getLogger(InstallCommand::class.java.name)
|
||||||
|
|
||||||
@Parameters(
|
@Parameters(
|
||||||
description = ["Serial of ADB devices. If not supplied, the first connected device will be used."],
|
description = ["ADB device serials"], arity = "1..*"
|
||||||
arity = "0..*",
|
|
||||||
)
|
)
|
||||||
private var deviceSerials: Array<String>? = null
|
private lateinit var deviceSerials: Array<String>
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-a", "--apk"],
|
names = ["-a", "--apk"], description = ["APK file to be installed"], required = true
|
||||||
description = ["APK file to be installed."],
|
|
||||||
required = true,
|
|
||||||
)
|
)
|
||||||
private lateinit var apk: File
|
private lateinit var apk: File
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-m", "--mount"],
|
names = ["-m", "--mount"],
|
||||||
description = ["Mount the supplied APK file over the app with the supplied package name."],
|
description = ["Mount the supplied APK file over the app with the supplied package name"],
|
||||||
)
|
)
|
||||||
private var packageName: String? = null
|
private var packageName: String? = null
|
||||||
|
|
||||||
override fun run() {
|
override fun run() = deviceSerials.forEach { deviceSerial ->
|
||||||
suspend fun install(deviceSerial: String? = null) {
|
try {
|
||||||
val result = try {
|
AdbManager.getAdbManager(deviceSerial, packageName != null).install(AdbManager.Apk(apk, packageName))
|
||||||
if (packageName != null) {
|
} catch (e: AdbManager.DeviceNotFoundException) {
|
||||||
AdbRootInstaller(deviceSerial)
|
|
||||||
} else {
|
|
||||||
AdbInstaller(deviceSerial)
|
|
||||||
}.install(Installer.Apk(apk, packageName))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.severe(e.toString())
|
logger.severe(e.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
when (result) {
|
|
||||||
RootInstallerResult.FAILURE ->
|
|
||||||
logger.severe("Failed to mount the APK file")
|
|
||||||
is AdbInstallerResult.Failure ->
|
|
||||||
logger.severe(result.exception.toString())
|
|
||||||
else ->
|
|
||||||
logger.info("Installed the APK file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
deviceSerials?.map { async { install(it) } }?.awaitAll() ?: install()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,66 +1,36 @@
|
|||||||
package app.revanced.cli.command.utility
|
package app.revanced.cli.command.utility
|
||||||
|
|
||||||
import app.revanced.library.installation.installer.AdbInstaller
|
import app.revanced.library.adb.AdbManager
|
||||||
import app.revanced.library.installation.installer.AdbInstallerResult
|
|
||||||
import app.revanced.library.installation.installer.AdbRootInstaller
|
|
||||||
import app.revanced.library.installation.installer.RootInstallerResult
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import picocli.CommandLine.*
|
import picocli.CommandLine.*
|
||||||
import picocli.CommandLine.Help.Visibility.ALWAYS
|
import picocli.CommandLine.Help.Visibility.ALWAYS
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "uninstall",
|
name = "uninstall",
|
||||||
description = ["Uninstall a patched app."],
|
description = ["Uninstall a patched app from the devices with the supplied ADB device serials"]
|
||||||
)
|
)
|
||||||
internal object UninstallCommand : Runnable {
|
internal object UninstallCommand : Runnable {
|
||||||
private val logger = Logger.getLogger(this::class.java.name)
|
private val logger = Logger.getLogger(UninstallCommand::class.java.name)
|
||||||
|
|
||||||
@Parameters(
|
@Parameters(description = ["ADB device serials"], arity = "1..*")
|
||||||
description = ["Serial of ADB devices. If not supplied, the first connected device will be used."],
|
private lateinit var deviceSerials: Array<String>
|
||||||
arity = "0..*",
|
|
||||||
)
|
|
||||||
private var deviceSerials: Array<String>? = null
|
|
||||||
|
|
||||||
@Option(
|
@Option(names = ["-p", "--package-name"], description = ["Package name of the app to uninstall"], required = true)
|
||||||
names = ["-p", "--package-name"],
|
|
||||||
description = ["Package name of the app to uninstall."],
|
|
||||||
required = true,
|
|
||||||
)
|
|
||||||
private lateinit var packageName: String
|
private lateinit var packageName: String
|
||||||
|
|
||||||
@Option(
|
@Option(
|
||||||
names = ["-u", "--unmount"],
|
names = ["-u", "--unmount"],
|
||||||
description = ["Uninstall the patched APK file by unmounting."],
|
description = ["Uninstall by unmounting the patched APK file"],
|
||||||
showDefaultValue = ALWAYS,
|
showDefaultValue = ALWAYS
|
||||||
)
|
)
|
||||||
private var unmount: Boolean = false
|
private var unmount: Boolean = false
|
||||||
|
|
||||||
override fun run() {
|
override fun run() = deviceSerials.forEach { deviceSerial ->
|
||||||
suspend fun uninstall(deviceSerial: String? = null) {
|
try {
|
||||||
val result = try {
|
AdbManager.getAdbManager(deviceSerial, unmount).uninstall(packageName)
|
||||||
if (unmount) {
|
} catch (e: AdbManager.DeviceNotFoundException) {
|
||||||
AdbRootInstaller(deviceSerial)
|
|
||||||
} else {
|
|
||||||
AdbInstaller(deviceSerial)
|
|
||||||
}.uninstall(packageName)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.severe(e.toString())
|
logger.severe(e.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
when (result) {
|
|
||||||
RootInstallerResult.FAILURE ->
|
|
||||||
logger.severe("Failed to unmount the patched APK file")
|
|
||||||
is AdbInstallerResult.Failure ->
|
|
||||||
logger.severe(result.exception.toString())
|
|
||||||
else -> logger.info("Uninstalled the patched APK file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
deviceSerials?.map { async { uninstall(it) } }?.awaitAll() ?: uninstall()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ import picocli.CommandLine
|
|||||||
|
|
||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
name = "utility",
|
name = "utility",
|
||||||
description = ["Commands for utility purposes."],
|
description = ["Commands for utility purposes"],
|
||||||
subcommands = [InstallCommand::class, UninstallCommand::class],
|
subcommands = [InstallCommand::class, UninstallCommand::class],
|
||||||
)
|
)
|
||||||
internal object UtilityCommand
|
internal object UtilityCommand
|
@ -1,78 +0,0 @@
|
|||||||
package app.revanced.cli.command
|
|
||||||
|
|
||||||
import kotlin.test.Test
|
|
||||||
|
|
||||||
class OptionValueConverterTest {
|
|
||||||
@Test
|
|
||||||
fun `converts to string`() {
|
|
||||||
"string" convertsTo "string" because "Strings should remain the same"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `converts to null`() {
|
|
||||||
"null" convertsTo null because "null should convert to null"
|
|
||||||
"\"null\"" convertsTo "null" because "Escaped null should convert to a string"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `converts to boolean`() {
|
|
||||||
"true" convertsTo true because "true should convert to a boolean true"
|
|
||||||
"True" convertsTo true because "Casing should not matter"
|
|
||||||
"\"true\"" convertsTo "true" because "Escaped booleans should be converted to strings"
|
|
||||||
"\'True\'" convertsTo "True" because "Casing in escaped booleans should not matter"
|
|
||||||
"tr ue" convertsTo "tr ue" because "Malformed booleans should be converted to strings"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `converts to numbers`() {
|
|
||||||
"1" convertsTo 1 because "Integers should convert to integers"
|
|
||||||
"1.0" convertsTo 1.0 because "Doubles should convert to doubles"
|
|
||||||
"1.0f" convertsTo 1.0f because "The suffix f should convert to a float"
|
|
||||||
Long.MAX_VALUE.toString() convertsTo Long.MAX_VALUE because "Values that are too large for an integer should convert to longs"
|
|
||||||
"1L" convertsTo 1L because "The suffix L should convert to a long"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `converts escaped numbers to string`() {
|
|
||||||
"\"1\"" convertsTo "1" because "Escaped numbers should convert to strings"
|
|
||||||
"\"1.0\"" convertsTo "1.0" because "Escaped doubles should convert to strings"
|
|
||||||
"\"1L\"" convertsTo "1L" because "Escaped longs should convert to strings"
|
|
||||||
"\'1\'" convertsTo "1" because "Single quotes should not be treated as escape symbols"
|
|
||||||
"\'.0\'" convertsTo ".0" because "Single quotes should not be treated as escape symbols"
|
|
||||||
"\'1L\'" convertsTo "1L" because "Single quotes should not be treated as escape symbols"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `trims escape symbols once`() {
|
|
||||||
"\"\"\"1\"\"\"" convertsTo "\"\"1\"\"" because "The escape symbols should be trimmed once"
|
|
||||||
"\'\'\'1\'\'\'" convertsTo "''1''" because "Single quotes should not be treated as escape symbols"
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `converts lists`() {
|
|
||||||
"1,2" convertsTo "1,2" because "Lists without square brackets should not be converted to lists"
|
|
||||||
"[1,2" convertsTo "[1,2" because "Invalid lists should not be converted to lists"
|
|
||||||
"\"[1,2]\"" convertsTo "[1,2]" because "Lists with escaped square brackets should not be converted to lists"
|
|
||||||
|
|
||||||
"[]" convertsTo emptyList<Any>() because "Empty untyped lists should convert to empty lists of any"
|
|
||||||
"int[]" convertsTo emptyList<Int>() because "Empty typed lists should convert to lists of the specified type"
|
|
||||||
"[[int[]]]" convertsTo listOf(listOf(emptyList<Int>())) because "Nested typed lists should convert to nested lists of the specified type"
|
|
||||||
"[\"int[]\"]" convertsTo listOf("int[]") because "Lists of escaped empty typed lists should not be converted to lists"
|
|
||||||
|
|
||||||
"[1,2,3]" convertsTo listOf(1, 2, 3) because "Lists of integers should convert to lists of integers"
|
|
||||||
"[[1]]" convertsTo listOf(listOf(1)) because "Nested lists with one element should convert to nested lists"
|
|
||||||
"[[1,2],[3,4]]" convertsTo listOf(listOf(1, 2), listOf(3, 4)) because "Nested lists should convert to nested lists"
|
|
||||||
|
|
||||||
"[\"1,2\"]" convertsTo listOf("1,2") because "Values in lists should not be split by commas in strings"
|
|
||||||
"[[\"1,2\"]]" convertsTo listOf(listOf("1,2")) because "Values in nested lists should not be split by commas in strings"
|
|
||||||
|
|
||||||
"[\"\\\"\"]" convertsTo listOf("\"") because "Escaped quotes in strings should be converted to quotes"
|
|
||||||
"[[\"\\\"\"]]" convertsTo listOf(listOf("\"")) because "Escaped quotes in strings nested in lists should be converted to quotes"
|
|
||||||
"[.1,.2f,,true,FALSE]" convertsTo listOf(.1, .2f, "", true, false) because "Values in lists should be converted to the correct type"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val convert = OptionValueConverter()::convert
|
|
||||||
|
|
||||||
private infix fun String.convertsTo(to: Any?) = convert(this) to to
|
|
||||||
private infix fun Pair<Any?, Any?>.because(reason: String) = assert(this.first == this.second) { reason }
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user