Compare commits

...

155 Commits

Author SHA1 Message Date
semantic-release-bot
44cc88b25d chore(release): 3.0.0-dev.1 [skip ci]
# [3.0.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.5...v3.0.0-dev.1) (2023-08-23)

### Bug Fixes

* do not use absolute path from custom AAPT2 binary option ([a9c2a5f](a9c2a5f096))
* use correct option name ([f8972ea](f8972eac3e))

* refactor!: restructure code ([07da528](07da528ce2))

### Features

* add options command ([9edbbf3](9edbbf3163))
* use better logging text ([b0e748d](b0e748daff))
* use separate command to list patches ([b74213f](b74213f66e))
* use separate command to patch ([32da961](32da961d57))
* use separate command to uninstall ([c0cc909](c0cc909626))
* use simpler log ([ba758f0](ba758f00f4))

### BREAKING CHANGES

* This introduces major changes to how ReVanced CLI is used from the command line.
2023-08-23 03:17:57 +00:00
oSumAtrIX
97548f80b3 build: fix dummy publish task 2023-08-23 05:16:17 +02:00
oSumAtrIX
d766f0e229 refactor!: restructure code (#242) 2023-08-23 04:57:46 +02:00
oSumAtrIX
b0e748daff feat: use better logging text 2023-08-23 04:46:42 +02:00
oSumAtrIX
ba758f00f4 feat: use simpler log 2023-08-23 04:32:28 +02:00
oSumAtrIX
a9c2a5f096 fix: do not use absolute path from custom AAPT2 binary option 2023-08-23 04:29:58 +02:00
oSumAtrIX
0dcd838de3 build: migrate dependencies to version catalogs 2023-08-23 04:28:12 +02:00
oSumAtrIX
a7290353bf build: make sure to add use all necessary repositories 2023-08-23 03:56:31 +02:00
oSumAtrIX
47a20afd2d docs: improve correctness 2023-08-23 03:53:24 +02:00
oSumAtrIX
f8972eac3e fix: use correct option name 2023-08-23 03:40:42 +02:00
oSumAtrIX
9edbbf3163 feat: add options command 2023-08-23 03:35:38 +02:00
oSumAtrIX
32da961d57 feat: use separate command to patch 2023-08-23 03:32:39 +02:00
oSumAtrIX
8a5daab2a3 build: add properties resource file 2023-08-23 03:30:13 +02:00
oSumAtrIX
c0cc909626 feat: use separate command to uninstall 2023-08-23 03:30:04 +02:00
oSumAtrIX
b74213f66e feat: use separate command to list patches 2023-08-22 23:41:32 +02:00
oSumAtrIX
fe75d4ab87 docs: use correct description 2023-08-22 23:41:32 +02:00
oSumAtrIX
07da528ce2 refactor!: restructure code
This commit focuses on improving code quality in a couple of places and bumping the dependency to ReVanced Patcher.

BREAKING CHANGE: This introduces major changes to how ReVanced CLI is used from the command line.
2023-08-22 23:41:31 +02:00
semantic-release-bot
ef5fa9b4c9 chore(release): 2.23.0-dev.5 [skip ci]
# [2.23.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.4...v2.23.0-dev.5) (2023-08-14)
2023-08-14 02:14:18 +00:00
oSumAtrIX
fc359923e3 build(Needs bump): Bump dependencies 2023-08-14 04:12:10 +02:00
semantic-release-bot
2e3cd90537 chore(release): 2.23.0-dev.4 [skip ci]
# [2.23.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.3...v2.23.0-dev.4) (2023-08-13)

### Features

* show full package name when listing patches ([#240](https://github.com/ReVanced/revanced-cli/issues/240)) ([7174364](7174364ef8))
2023-08-13 11:44:20 +00:00
programminghoch10
7174364ef8 feat: show full package name when listing patches (#240) 2023-08-13 13:42:16 +02:00
oSumAtrIX
4c9d414228 docs: fix some mistakes 2023-08-10 02:06:13 +02:00
taku
5e73e6d2de docs: add missing prerequisites (#239)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-08-07 02:51:01 +02:00
semantic-release-bot
667ca3051c chore(release): 2.23.0-dev.3 [skip ci]
# [2.23.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.2...v2.23.0-dev.3) (2023-08-03)
2023-08-03 18:41:14 +00:00
oSumAtrIX
9220642a7b build(Needs bump): Bump compatibility 2023-08-03 20:38:48 +02:00
semantic-release-bot
3f47235c64 chore(release): 2.23.0-dev.2 [skip ci]
# [2.23.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.1...v2.23.0-dev.2) (2023-08-03)
2023-08-03 02:22:52 +00:00
oSumAtrIX
83b475c2e3 build(Needs bump): Update dependencies 2023-08-03 04:21:02 +02:00
semantic-release-bot
4105b638c0 chore(release): 2.23.0-dev.1 [skip ci]
# [2.23.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.22.1-dev.1...v2.23.0-dev.1) (2023-07-30)

### Features

* Improve command line argument descriptions ([f9cf7d2](f9cf7d21b7))
2023-07-30 00:52:33 +00:00
oSumAtrIX
f9cf7d21b7 feat: Improve command line argument descriptions 2023-07-30 02:49:49 +02:00
oSumAtrIX
0a758d86df build(Needs bump): Bump dependencies 2023-07-30 02:49:48 +02:00
oSumAtrIX
83f99e29ec ci: Change bumping commit scope 2023-07-30 02:49:39 +02:00
semantic-release-bot
00410d54c0 chore(release): 2.22.1-dev.1 [skip ci]
## [2.22.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.22.0...v2.22.1-dev.1) (2023-07-24)

### Bug Fixes

* print original instead of kebab cased names ([5eaad33](5eaad33dc1))
2023-07-24 12:20:19 +00:00
oSumAtrIX
5eaad33dc1 fix: print original instead of kebab cased names 2023-07-24 14:18:15 +02:00
semantic-release-bot
fa85482c4a chore(release): 2.22.0 [skip ci]
# [2.22.0](https://github.com/revanced/revanced-cli/compare/v2.21.5...v2.22.0) (2023-07-11)

### Features

* use new patch naming convention ([f6c221d](f6c221d72d))
2023-07-11 03:14:04 +00:00
oSumAtrIX
caed39af7f chore: merge branch dev to main (#233) 2023-07-11 05:12:30 +02:00
oSumAtrIX
20e1fdc18d chore: add notice to move option 2023-07-11 05:11:24 +02:00
semantic-release-bot
19cd541e9a chore(release): 2.22.0-dev.1 [skip ci]
# [2.22.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.5...v2.22.0-dev.1) (2023-07-10)

### Features

* use new patch naming convention ([e4908c7](e4908c7105))
2023-07-11 05:06:46 +02:00
oSumAtrIX
f6c221d72d feat: use new patch naming convention 2023-07-11 05:06:46 +02:00
oSumAtrIX
9c148c96bf chore: add README file 2023-07-06 20:19:19 +02:00
oSumAtrIX
2c5b53c7e9 build: update gradle 2023-07-05 23:07:31 +02:00
semantic-release-bot
77d9cb98d1 chore(release): 2.21.5 [skip ci]
## [2.21.5](https://github.com/revanced/revanced-cli/compare/v2.21.4...v2.21.5) (2023-07-01)
2023-07-01 12:45:44 +00:00
oSumAtrIX
38677e2319 chore: merge branch dev to main (#230) 2023-07-01 14:43:45 +02:00
semantic-release-bot
e5e768fa34 chore(release): 2.21.5-dev.2 [skip ci]
## [2.21.5-dev.2](https://github.com/revanced/revanced-cli/compare/v2.21.5-dev.1...v2.21.5-dev.2) (2023-07-01)
2023-07-01 00:00:31 +00:00
oSumAtrIX
9082181ce5 build(revanced-patcher): bump version 2023-07-01 01:58:28 +02:00
oSumAtrIX
542580ecff docs: add section for patch options 2023-06-30 19:40:52 +02:00
semantic-release-bot
26112a4fd2 chore(release): 2.21.5-dev.1 [skip ci]
## [2.21.5-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.4...v2.21.5-dev.1) (2023-06-27)
2023-06-27 02:36:32 +00:00
oSumAtrIX
553fbdbb8f build(revanced-patcher): bump version 2023-06-27 04:10:34 +02:00
semantic-release-bot
be429a4770 chore(release): 2.21.4 [skip ci]
## [2.21.4](https://github.com/revanced/revanced-cli/compare/v2.21.3...v2.21.4) (2023-06-21)

### Bug Fixes

* remove duplicate options entries. ([d0fc886](d0fc886428))
2023-06-21 23:31:29 +00:00
oSumAtrIX
8c391cecce chore: merge branch dev to main (#229) 2023-06-22 01:29:31 +02:00
semantic-release-bot
bd14bdb5ea chore(release): 2.21.4-dev.1 [skip ci]
## [2.21.4-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.3...v2.21.4-dev.1) (2023-06-18)

### Bug Fixes

* remove duplicate options entries. ([d0fc886](d0fc886428))
2023-06-18 00:20:12 +00:00
oSumAtrIX
d0fc886428 fix: remove duplicate options entries. 2023-06-18 02:18:28 +02:00
semantic-release-bot
1ccbed8d17 chore(release): 2.21.3 [skip ci]
## [2.21.3](https://github.com/revanced/revanced-cli/compare/v2.21.2...v2.21.3) (2023-06-12)
2023-06-12 01:45:08 +00:00
oSumAtrIX
3b89fb7bc2 chore: merge branch dev to main (#228) 2023-06-12 03:43:20 +02:00
oSumAtrIX
16bb1a60fc ci: add cache step 2023-06-12 02:33:21 +02:00
oSumAtrIX
5f1843771e ci: build before running semantic-release 2023-06-12 01:52:53 +02:00
oSumAtrIX
9de90703c8 ci: remove unnecessary steps 2023-06-12 01:49:18 +02:00
semantic-release-bot
1201f9edc5 chore(release): 2.21.3-dev.1 [skip ci]
## [2.21.3-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.2...v2.21.3-dev.1) (2023-06-07)
2023-06-07 01:48:39 +00:00
oSumAtrIX
9c8f9608b2 build(revanced-patcher): bump version 2023-06-07 03:46:32 +02:00
semantic-release-bot
be90d2e360 chore(release): 2.21.2 [skip ci]
## [2.21.2](https://github.com/revanced/revanced-cli/compare/v2.21.1...v2.21.2) (2023-05-24)
2023-05-24 19:19:03 +00:00
oSumAtrIX
79dc99aa9b chore: merge branch dev to main (#225) 2023-05-24 21:17:06 +02:00
semantic-release-bot
260ff00951 chore(release): 2.21.2-dev.2 [skip ci]
## [2.21.2-dev.2](https://github.com/revanced/revanced-cli/compare/v2.21.2-dev.1...v2.21.2-dev.2) (2023-05-15)
2023-05-24 01:57:56 +02:00
LisoUseInAIKyrios
cfe4c5ed0e build(revanced-patcher): bump version (#226) 2023-05-24 01:57:56 +02:00
oSumAtrIX
7133242691 build: use Java SDK 17 for building 2023-05-09 07:13:17 +02:00
semantic-release-bot
55750ce16a chore(release): 2.21.2-dev.1 [skip ci]
## [2.21.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.1...v2.21.2-dev.1) (2023-05-07)
2023-05-07 23:24:29 +00:00
oSumAtrIX
6003e68d47 docs: remove "the" in front of ReVanced names 2023-05-08 01:20:20 +02:00
oSumAtrIX
9f8c2aeedf build: downgrade to JDK version 11 2023-05-08 01:15:27 +02:00
oSumAtrIX
0a16bc849b build(revanced-patcher): bump version 2023-05-08 01:15:07 +02:00
semantic-release-bot
ecd5147590 chore(release): 2.21.1 [skip ci]
## [2.21.1](https://github.com/revanced/revanced-cli/compare/v2.21.0...v2.21.1) (2023-05-06)
2023-05-06 22:21:27 +00:00
oSumAtrIX
ca255c9e1b chore: merge branch dev to main (#224) 2023-05-07 00:19:48 +02:00
semantic-release-bot
e9aa490355 chore(release): 2.21.1-dev.1 [skip ci]
## [2.21.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.0...v2.21.1-dev.1) (2023-05-06)
2023-05-06 21:23:52 +00:00
oSumAtrIX
69fe59f97b ci: release when bumping ReVanced Patcher
This is required when two projects bump ReVanced Patcher, but one does not release a new version, resulting them to get out of sync. For that reason, commits of type `build` and scope `revanced-patcher` are treated as releasing commits.
2023-05-06 23:22:53 +02:00
oSumAtrIX
995e1712bc build(revanced-patcher): bump version 2023-05-06 23:22:52 +02:00
semantic-release-bot
a236f10bb0 chore(release): 2.21.0 [skip ci]
# [2.21.0](https://github.com/revanced/revanced-cli/compare/v2.20.2...v2.21.0) (2023-05-04)

### Bug Fixes

* **tests:** set order of tests ([2ef48af](2ef48af1b3))
* use working JADB dependency version ([#222](https://github.com/revanced/revanced-cli/issues/222)) ([da2c918](da2c91874d))

### Features

* add appreciation message for new contributors ([6962fc2](6962fc2f4c))
2023-05-04 00:33:50 +00:00
oSumAtrIX
4a6134ea60 chore: merge branch dev to main (#219) 2023-05-04 02:32:03 +02:00
semantic-release-bot
b084024742 chore(release): 2.21.0-dev.1 [skip ci]
# [2.21.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.2...v2.21.0-dev.1) (2023-05-04)

### Bug Fixes

* **tests:** set order of tests ([2ef48af](2ef48af1b3))
* use working JADB dependency version ([#222](https://github.com/revanced/revanced-cli/issues/222)) ([da2c918](da2c91874d))

### Features

* add appreciation message for new contributors ([6962fc2](6962fc2f4c))
2023-05-04 00:31:04 +00:00
oSumAtrIX
2ef48af1b3 fix(tests): set order of tests 2023-05-04 02:30:11 +02:00
bogadana
da2c91874d fix: use working JADB dependency version (#222)
This fixes a current issue with CI/CD failing
2023-05-04 02:30:10 +02:00
oSumAtrIX
379687c814 fix!: support null as option value (#221)
BREAKING-CHANGE: serialize options as JSON instead of TOML
2023-05-04 02:30:10 +02:00
oSumAtrIX
2f5577e464 chore: update gradle and dependencies 2023-05-04 02:30:10 +02:00
oSumAtrIX
6962fc2f4c feat: add appreciation message for new contributors 2023-05-04 02:30:09 +02:00
semantic-release-bot
a6cef26210 chore(release): 2.20.2 [skip ci]
## [2.20.2](https://github.com/revanced/revanced-cli/compare/v2.20.1...v2.20.2) (2023-04-30)

### Bug Fixes

* correct spelling mistake ([31fb316](31fb3166d9))
2023-04-30 01:00:27 +00:00
oSumAtrIX
b4892c4413 chore: merge branch dev to main (#210) 2023-04-30 02:58:45 +02:00
bitingsock
90368405ad docs: update name of example patch (#218) 2023-04-30 02:55:27 +02:00
oSumAtrIX
26967959e2 ci: only dispatch documentation update event if on branch main 2023-04-30 02:53:24 +02:00
oSumAtrIX
eac6f6fbe3 docs: fix spelling (#213) 2023-04-21 17:14:09 +02:00
EvadeMaster
af4ec43352 docs: fix misspelling word 2023-04-21 21:23:41 +07:00
semantic-release-bot
4f5644b62c chore(release): 2.20.2-dev.1 [skip ci]
## [2.20.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.1...v2.20.2-dev.1) (2023-04-03)

### Bug Fixes

* correct spelling mistake ([31fb316](31fb3166d9))
2023-04-03 03:08:42 +00:00
oSumAtrIX
31fb3166d9 fix: correct spelling mistake 2023-04-03 05:07:45 +02:00
oSumAtrIX
a76bd0ad35 chore: bump dependencies 2023-04-03 03:04:07 +02:00
oSumAtrIX
ba07ab1ac2 build: update Kotlin to 1.8.10 2023-03-31 17:20:15 +02:00
oSumAtrIX
92bf57f279 docs: remove unnecessary option 2023-03-19 22:48:37 +01:00
semantic-release-bot
886d501026 chore(release): 2.20.1 [skip ci]
## [2.20.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1) (2023-03-14)

### Bug Fixes

* correctly word option descriptions ([ac3a8f6](ac3a8f66f7))
2023-03-14 15:00:44 +00:00
oSumAtrIX
4b04cc4b59 chore: merge branch dev to main (#205) 2023-03-14 15:59:14 +01:00
semantic-release-bot
75d237058f chore(release): 2.20.1-dev.1 [skip ci]
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-05)

### Bug Fixes

* correctly word option descriptions ([ac3a8f6](ac3a8f66f7))
2023-03-05 01:06:31 +00:00
oSumAtrIX
40026fe300 docs: fix output file name 2023-03-05 02:05:40 +01:00
semantic-release-bot
dbec559ed7 chore(release): 2.20.1-dev.1 [skip ci]
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-03)

### Bug Fixes

* correctly word option descriptions ([ac3a8f6](ac3a8f66f7))
2023-03-03 13:09:06 +00:00
Professsional
00e49719ca docs: fix invalid grammar (#206)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-03-03 14:08:13 +01:00
semantic-release-bot
df276846e1 chore(release): 2.20.1-dev.1 [skip ci]
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-02)

### Bug Fixes

* correctly word option descriptions ([ac3a8f6](ac3a8f66f7))
2023-03-02 19:39:20 +00:00
oSumAtrIX
ac3a8f66f7 fix: correctly word option descriptions
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-03-02 20:38:02 +01:00
oSumAtrIX
e900ce8486 chore: remove project files 2023-03-02 20:37:57 +01:00
oSumAtrIX
ee6dd5a57c docs: update options usage
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-27 01:07:57 +01:00
oSumAtrIX
23d9e1e841 ci: fix usage of backmergeBranches option
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-27 00:57:46 +01:00
oSumAtrIX
3718b7992c build: update dependencies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-27 00:53:27 +01:00
oSumAtrIX
bce5e86874 ci: fix backmerge direction
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-22 16:39:51 +01:00
oSumAtrIX
cda6df6238 ci: add backmerge target branch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-22 06:46:23 +01:00
oSumAtrIX
0dc230292a ci: use new semantic-release-backmerge option
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-18 21:55:41 +01:00
oSumAtrIX
695cd1ba41 docs: correct note on excluding patches 2023-02-14 23:27:28 +01:00
Palm
d08bbf8664 ci: update actions (#204) 2023-02-13 22:35:05 +01:00
oSumAtrIX
d55dd0a1fc chore: merge branch dev to main (#201) 2023-02-10 05:36:19 +01:00
oSumAtrIX
a53d3482de build: bump patcher dependency version
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-10 05:28:35 +01:00
semantic-release-bot
7a3d0420f7 chore(release): 2.20.0 [skip ci]
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-18)

### Bug Fixes

* bump patcher dependency version ([51c04b7](51c04b7b16))
* do not list compatible packages if patches do not define them ([31e4a41](31e4a41dd2))

### Features

* connect to first device if given device was not found ([6485e47](6485e477a1))
* remove option `--with-descriptions` ([07a423b](07a423b19e))
2023-01-18 20:36:39 +00:00
semantic-release-bot
5cddf5004e chore(release): 2.20.0 [skip ci]
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-17)

### Bug Fixes

* bump patcher dependency version ([51c04b7](51c04b7b16))
* do not list compatible packages if patches do not define them ([31e4a41](31e4a41dd2))

### Features

* connect to first device if given device was not found ([6485e47](6485e477a1))
* remove option `--with-descriptions` ([07a423b](07a423b19e))
2023-01-17 23:48:27 +00:00
oSumAtrIX
6393a5016a chore: merge branch dev to main (#196) 2023-01-18 00:47:01 +01:00
oSumAtrIX
cad38ca3bd ci: use PAT in step Release 2023-01-18 00:44:39 +01:00
oSumAtrIX
6c1169b433 chore: merge branch dev to main (#195) 2023-01-18 00:39:15 +01:00
oSumAtrIX
bf2bb72ce0 build: update dependencies
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-01-18 00:33:00 +01:00
oSumAtrIX
567bdee887 chore: merge branch dev to main (#194) 2023-01-15 06:16:46 +01:00
semantic-release-bot
9888b0e08e chore(release): 2.20.0-dev.3 [skip ci]
# [2.20.0-dev.3](https://github.com/revanced/revanced-cli/compare/v2.20.0-dev.2...v2.20.0-dev.3) (2023-01-15)

### Bug Fixes

* bump patcher dependency version ([51c04b7](51c04b7b16))
2023-01-15 04:36:31 +00:00
oSumAtrIX
51c04b7b16 fix: bump patcher dependency version
This commit addresses https://github.com/revanced/multidexlib2/issues/2.
2023-01-15 05:34:52 +01:00
semantic-release-bot
a39cf893d6 chore(release): 2.20.0-dev.2 [skip ci]
# [2.20.0-dev.2](https://github.com/revanced/revanced-cli/compare/v2.20.0-dev.1...v2.20.0-dev.2) (2023-01-15)

### Features

* connect to first device if given device was not found ([6485e47](6485e477a1))
2023-01-15 04:25:04 +00:00
oSumAtrIX
6485e477a1 feat: connect to first device if given device was not found 2023-01-15 05:17:38 +01:00
oSumAtrIX
f99d340534 chore: merge branch dev to main (#193) 2023-01-13 22:33:19 +01:00
oSumAtrIX
4edc325978 ci: use PAT in step Release 2023-01-13 22:31:11 +01:00
oSumAtrIX
cffa1ea3a4 chore: merge branch dev to main (#192) 2023-01-13 16:04:32 +01:00
oSumAtrIX
d15505adaa ci: downgrade semantic release and plugins to v19 2023-01-13 15:50:39 +01:00
oSumAtrIX
aaf452a103 refactor: fix formatting 2023-01-13 14:41:38 +01:00
oSumAtrIX
1753a1aa3e ci: give jobs names 2023-01-13 14:41:18 +01:00
oSumAtrIX
f4e74cb4f2 docs: improve CLI usage commands 2023-01-13 00:13:45 +01:00
oSumAtrIX
50df4e117e docs: improve wording and accuracy 2023-01-09 10:11:15 +01:00
oSumAtrIX
9fcd2b4cd1 Merge branch 'main' into dev 2023-01-08 16:43:59 +01:00
oSumAtrIX
e6bb05c0b9 docs: init (#191) 2023-01-08 16:43:19 +01:00
oSumAtrIX
6bd7d42e32 ci: dispatch event to revanced/revanced-documentation on push to /docs 2023-01-08 14:46:13 +01:00
oSumAtrIX
19200eacc1 docs: init 2023-01-08 14:37:41 +01:00
semantic-release-bot
666738ee57 chore(release): 2.20.0 [skip ci]
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-02)

### Bug Fixes

* do not list compatible packages if patches do not define them ([31e4a41](31e4a41dd2))

### Features

* remove option `--with-descriptions` ([07a423b](07a423b19e))
2023-01-02 08:15:31 +00:00
oSumAtrIX
961267b8cd chore: merge branch dev to main (#190) 2023-01-02 09:13:55 +01:00
oSumAtrIX
6b7314a399 build: bump patcher dependency version (#189) 2023-01-02 09:11:19 +01:00
semantic-release-bot
c8a47c51df chore(release): 2.20.0 [skip ci]
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-01)

### Bug Fixes

* do not list compatible packages if patches do not define them ([31e4a41](31e4a41dd2))

### Features

* remove option `--with-descriptions` ([07a423b](07a423b19e))
2023-01-01 17:15:28 +00:00
oSumAtrIX
72d8f73d7f chore: merge branch dev to main (#188) 2023-01-01 18:14:36 +01:00
semantic-release-bot
1957a2c4ff chore(release): 2.20.0-dev.1 [skip ci]
# [2.20.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0-dev.1) (2023-01-01)

### Bug Fixes

* do not list compatible packages if patches do not define them ([31e4a41](31e4a41dd2))

### Features

* remove option `--with-descriptions` ([07a423b](07a423b19e))
2023-01-01 17:12:07 +00:00
oSumAtrIX
07a423b19e feat: remove option --with-descriptions 2023-01-01 18:11:10 +01:00
oSumAtrIX
31e4a41dd2 fix: do not list compatible packages if patches do not define them 2023-01-01 18:11:10 +01:00
semantic-release-bot
8284c1048f chore(release): 2.19.0 [skip ci]
# [2.19.0](https://github.com/revanced/revanced-cli/compare/v2.18.2...v2.19.0) (2022-12-31)

### Features

* improve description of options ([#185](https://github.com/revanced/revanced-cli/issues/185)) ([b69e784](b69e784785))
2022-12-31 18:22:25 +00:00
oSumAtrIX
9c64f5ec3e chore: merge branch dev to main (#184) 2022-12-31 19:20:26 +01:00
semantic-release-bot
f4c447e71b chore(release): 2.19.0-dev.1 [skip ci]
# [2.19.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.18.2...v2.19.0-dev.1) (2022-12-31)

### Features

* improve description of options ([#185](https://github.com/revanced/revanced-cli/issues/185)) ([b69e784](b69e784785))
2022-12-31 18:19:03 +00:00
oSumAtrIX
b69e784785 feat: improve description of options (#185) 2022-12-31 19:17:57 +01:00
oSumAtrIX
ccce9c926d ci: do not escape in environment variable MESSAGE 2022-12-29 19:07:33 +01:00
oSumAtrIX
dc4ab22f41 chore: bump patcher dependency version 2022-12-18 22:20:20 +01:00
semantic-release-bot
25d8ad4aaf chore(release): 2.18.2 [skip ci]
## [2.18.2](https://github.com/revanced/revanced-cli/compare/v2.18.1...v2.18.2) (2022-12-16)

### Bug Fixes

* exclude patcher dependency from minimizing ([d5794b9](d5794b94ca))
2022-12-16 16:10:17 +00:00
oSumAtrIX
3d9436e691 chore: merge branch dev to main (#180) 2022-12-16 17:08:38 +01:00
semantic-release-bot
ee70423527 chore(release): 2.18.2-dev.1 [skip ci]
## [2.18.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.18.1...v2.18.2-dev.1) (2022-12-16)

### Bug Fixes

* exclude patcher dependency from minimizing ([d5794b9](d5794b94ca))
2022-12-16 15:54:28 +00:00
oSumAtrIX
d5794b94ca fix: exclude patcher dependency from minimizing 2022-12-16 16:53:01 +01:00
oSumAtrIX
3160d894da chore: merge branch dev to main (#179) 2022-12-16 01:25:15 +01:00
oSumAtrIX
545597959a refactor: remove unused class ZipFileUtils 2022-12-16 01:23:37 +01:00
semantic-release-bot
a6db0edc70 chore(release): 2.18.1 [skip ci]
## [2.18.1](https://github.com/revanced/revanced-cli/compare/v2.18.0...v2.18.1) (2022-12-15)

### Bug Fixes

* don't log when package is incompatible and `exclusive` option is used ([ad81a1b](ad81a1b656))
2022-12-15 23:50:16 +00:00
oSumAtrIX
ff0d3dd224 chore: merge branch dev to main (#178) 2022-12-15 23:43:46 +01:00
55 changed files with 2393 additions and 1127 deletions

9
.gitattributes vendored Normal file
View File

@@ -0,0 +1,9 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf
# These are Windows script files and should use crlf
*.bat text eol=crlf

2
.github/config.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
firstPRMergeComment: >
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.

View File

@@ -7,10 +7,11 @@ on:
workflow_dispatch:
env:
MESSAGE: merge branch \`${{ github.head_ref || github.ref_name }}\` to \`main\`
MESSAGE: merge branch `${{ github.head_ref || github.ref_name }}` to `main`
jobs:
pull-request:
name: Open pull request
runs-on: ubuntu-latest
steps:
- name: Checkout

View File

@@ -1,4 +1,5 @@
name: Release
on:
workflow_dispatch:
push:
@@ -9,6 +10,7 @@ on:
branches:
- main
- dev
jobs:
release:
name: Release
@@ -17,21 +19,27 @@ jobs:
- name: Checkout
uses: actions/checkout@v3
with:
# Make sure the release step uses its own credentials:
# https://github.com/cycjimmy/semantic-release-action#private-packages
persist-credentials: false
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v3
- name: Cache
uses: actions/cache@v3
with:
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: "latest"
cache: 'npm'
- name: Setup semantic-release
run: npm install semantic-release @saithodev/semantic-release-backmerge @semantic-release/git @semantic-release/changelog gradle-semantic-release-plugin -D
- name: Create release
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 with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
run: ./gradlew clean --no-daemon
- name: Setup semantic-release
run: npm install
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }}
run: npm exec semantic-release

View File

@@ -0,0 +1,19 @@
name: Update documentation
on:
push:
paths:
- docs/**
jobs:
trigger:
runs-on: ubuntu-latest
name: Dispatch event to documentation repository
if: github.ref == 'refs/heads/main'
steps:
- uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }}
repository: revanced/revanced-documentation
event-type: update-documentation
client-payload: '{"repo": "${{ github.event.repository.name }}", "ref": "${{ github.ref }}"}'

1
.gitignore vendored
View File

@@ -74,6 +74,7 @@ cmake-build-*/
# IntelliJ
out/
.idea
# mpeltonen/sbt-idea plugin
.idea_modules/

11
.idea/.gitignore generated vendored
View File

@@ -1,11 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
/kotlinc.xml
/vcs.xml
/codeStyles

7
.idea/discord.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

14
.idea/misc.xml generated
View File

@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="PWA">
<option name="enabled" value="true" />
<option name="wasEnabledAtLeastOnce" value="true" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

12
.idea/vcs.xml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="CommitFormat" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="CommitNamingConvention" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -7,7 +7,13 @@
}
],
"plugins": [
"@semantic-release/commit-analyzer",
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"gradle-semantic-release-plugin",
@@ -34,7 +40,7 @@
[
"@saithodev/semantic-release-backmerge",
{
branches: [{from: "main", to: "dev"}],
backmergeBranches: [{"from": "main", "to": "dev"}],
clearWorkspace: true
}
]

View File

@@ -1,3 +1,285 @@
# [3.0.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.5...v3.0.0-dev.1) (2023-08-23)
### Bug Fixes
* do not use absolute path from custom AAPT2 binary option ([a9c2a5f](https://github.com/ReVanced/revanced-cli/commit/a9c2a5f096627dbbf8ab1b8da26fb14529ce6bc3))
* use correct option name ([f8972ea](https://github.com/ReVanced/revanced-cli/commit/f8972eac3e5ee0a4a186c12cbe711925656d657b))
* refactor!: restructure code ([07da528](https://github.com/ReVanced/revanced-cli/commit/07da528ce2223582f84bf64d2fec69714c647ddc))
### Features
* add options command ([9edbbf3](https://github.com/ReVanced/revanced-cli/commit/9edbbf31635603f89fc7bc5dcc6c023d4cdbb5a6))
* use better logging text ([b0e748d](https://github.com/ReVanced/revanced-cli/commit/b0e748daff527ee7f417b3069882e074896fc131))
* use separate command to list patches ([b74213f](https://github.com/ReVanced/revanced-cli/commit/b74213f66e0d04d3a0ae6197d069631388e06580))
* use separate command to patch ([32da961](https://github.com/ReVanced/revanced-cli/commit/32da961d57537e99b39fd92b625a1c73f8314bc6))
* use separate command to uninstall ([c0cc909](https://github.com/ReVanced/revanced-cli/commit/c0cc90962646cfffd5e2730ae556423271a7990b))
* use simpler log ([ba758f0](https://github.com/ReVanced/revanced-cli/commit/ba758f00f4ce18791439b7e72fe1ad2e7f11f8af))
### BREAKING CHANGES
* This introduces major changes to how ReVanced CLI is used from the command line.
# [2.23.0-dev.5](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.4...v2.23.0-dev.5) (2023-08-14)
# [2.23.0-dev.4](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.3...v2.23.0-dev.4) (2023-08-13)
### Features
* show full package name when listing patches ([#240](https://github.com/ReVanced/revanced-cli/issues/240)) ([7174364](https://github.com/ReVanced/revanced-cli/commit/7174364ef8ef5d6ce8351a8340f9c1a5b58eac3c))
# [2.23.0-dev.3](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.2...v2.23.0-dev.3) (2023-08-03)
# [2.23.0-dev.2](https://github.com/ReVanced/revanced-cli/compare/v2.23.0-dev.1...v2.23.0-dev.2) (2023-08-03)
# [2.23.0-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.22.1-dev.1...v2.23.0-dev.1) (2023-07-30)
### Features
* Improve command line argument descriptions ([f9cf7d2](https://github.com/ReVanced/revanced-cli/commit/f9cf7d21b7f1c2f11234d604a1047b9d2b165f83))
## [2.22.1-dev.1](https://github.com/ReVanced/revanced-cli/compare/v2.22.0...v2.22.1-dev.1) (2023-07-24)
### Bug Fixes
* print original instead of kebab cased names ([5eaad33](https://github.com/ReVanced/revanced-cli/commit/5eaad33dc1fbd24c36e1498f04e21d068e85f53e))
# [2.22.0](https://github.com/revanced/revanced-cli/compare/v2.21.5...v2.22.0) (2023-07-11)
### Features
* use new patch naming convention ([f6c221d](https://github.com/revanced/revanced-cli/commit/f6c221d72dc43ebea00e5eba6bfa02751ae8ad77))
# [2.22.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.5...v2.22.0-dev.1) (2023-07-10)
### Features
* use new patch naming convention ([e4908c7](https://github.com/revanced/revanced-cli/commit/e4908c71051a535f8ce3406427cebbb0941464df))
## [2.21.5](https://github.com/revanced/revanced-cli/compare/v2.21.4...v2.21.5) (2023-07-01)
## [2.21.5-dev.2](https://github.com/revanced/revanced-cli/compare/v2.21.5-dev.1...v2.21.5-dev.2) (2023-07-01)
## [2.21.5-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.4...v2.21.5-dev.1) (2023-06-27)
## [2.21.4](https://github.com/revanced/revanced-cli/compare/v2.21.3...v2.21.4) (2023-06-21)
### Bug Fixes
* remove duplicate options entries. ([d0fc886](https://github.com/revanced/revanced-cli/commit/d0fc8864286adc2677f91a319a11a90272c1001d))
## [2.21.4-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.3...v2.21.4-dev.1) (2023-06-18)
### Bug Fixes
* remove duplicate options entries. ([d0fc886](https://github.com/revanced/revanced-cli/commit/d0fc8864286adc2677f91a319a11a90272c1001d))
## [2.21.3](https://github.com/revanced/revanced-cli/compare/v2.21.2...v2.21.3) (2023-06-12)
## [2.21.3-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.2...v2.21.3-dev.1) (2023-06-07)
## [2.21.2](https://github.com/revanced/revanced-cli/compare/v2.21.1...v2.21.2) (2023-05-24)
## [2.21.2-dev.2](https://github.com/revanced/revanced-cli/compare/v2.21.2-dev.1...v2.21.2-dev.2) (2023-05-15)
## [2.21.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.1...v2.21.2-dev.1) (2023-05-07)
## [2.21.1](https://github.com/revanced/revanced-cli/compare/v2.21.0...v2.21.1) (2023-05-06)
## [2.21.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.21.0...v2.21.1-dev.1) (2023-05-06)
# [2.21.0](https://github.com/revanced/revanced-cli/compare/v2.20.2...v2.21.0) (2023-05-04)
### Bug Fixes
* **tests:** set order of tests ([2ef48af](https://github.com/revanced/revanced-cli/commit/2ef48af1b339ab729a05d69cb0c8c1ee1e3ab486))
* use working JADB dependency version ([#222](https://github.com/revanced/revanced-cli/issues/222)) ([da2c918](https://github.com/revanced/revanced-cli/commit/da2c91874d5623402febfcc0677ada3d648565e1))
### Features
* add appreciation message for new contributors ([6962fc2](https://github.com/revanced/revanced-cli/commit/6962fc2f4c0f0c96e88a823be64f8ebd1312ee17))
# [2.21.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.2...v2.21.0-dev.1) (2023-05-04)
### Bug Fixes
* **tests:** set order of tests ([2ef48af](https://github.com/revanced/revanced-cli/commit/2ef48af1b339ab729a05d69cb0c8c1ee1e3ab486))
* use working JADB dependency version ([#222](https://github.com/revanced/revanced-cli/issues/222)) ([da2c918](https://github.com/revanced/revanced-cli/commit/da2c91874d5623402febfcc0677ada3d648565e1))
### Features
* add appreciation message for new contributors ([6962fc2](https://github.com/revanced/revanced-cli/commit/6962fc2f4c0f0c96e88a823be64f8ebd1312ee17))
## [2.20.2](https://github.com/revanced/revanced-cli/compare/v2.20.1...v2.20.2) (2023-04-30)
### Bug Fixes
* correct spelling mistake ([31fb316](https://github.com/revanced/revanced-cli/commit/31fb3166d922ae1f568f52e44cbe726dd1c891a4))
## [2.20.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.1...v2.20.2-dev.1) (2023-04-03)
### Bug Fixes
* correct spelling mistake ([31fb316](https://github.com/revanced/revanced-cli/commit/31fb3166d922ae1f568f52e44cbe726dd1c891a4))
## [2.20.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1) (2023-03-14)
### Bug Fixes
* correctly word option descriptions ([ac3a8f6](https://github.com/revanced/revanced-cli/commit/ac3a8f66f77a7218974465eebbfc78a536b76d51))
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-05)
### Bug Fixes
* correctly word option descriptions ([ac3a8f6](https://github.com/revanced/revanced-cli/commit/ac3a8f66f77a7218974465eebbfc78a536b76d51))
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-03)
### Bug Fixes
* correctly word option descriptions ([ac3a8f6](https://github.com/revanced/revanced-cli/commit/ac3a8f66f77a7218974465eebbfc78a536b76d51))
## [2.20.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.20.0...v2.20.1-dev.1) (2023-03-02)
### Bug Fixes
* correctly word option descriptions ([ac3a8f6](https://github.com/revanced/revanced-cli/commit/ac3a8f66f77a7218974465eebbfc78a536b76d51))
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-18)
### Bug Fixes
* bump patcher dependency version ([51c04b7](https://github.com/revanced/revanced-cli/commit/51c04b7b162ad2876bbeb248b7ccddd105b5076d))
* do not list compatible packages if patches do not define them ([31e4a41](https://github.com/revanced/revanced-cli/commit/31e4a41dd20f5fa62f840cd8e3b92fe0814eda87))
### Features
* connect to first device if given device was not found ([6485e47](https://github.com/revanced/revanced-cli/commit/6485e477a10bb89dfb2e40f3596d72b20bf23cc8))
* remove option `--with-descriptions` ([07a423b](https://github.com/revanced/revanced-cli/commit/07a423b19ec72e9f020aeb0222f4ced571036dbe))
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-17)
### Bug Fixes
* bump patcher dependency version ([51c04b7](https://github.com/revanced/revanced-cli/commit/51c04b7b162ad2876bbeb248b7ccddd105b5076d))
* do not list compatible packages if patches do not define them ([31e4a41](https://github.com/revanced/revanced-cli/commit/31e4a41dd20f5fa62f840cd8e3b92fe0814eda87))
### Features
* connect to first device if given device was not found ([6485e47](https://github.com/revanced/revanced-cli/commit/6485e477a10bb89dfb2e40f3596d72b20bf23cc8))
* remove option `--with-descriptions` ([07a423b](https://github.com/revanced/revanced-cli/commit/07a423b19ec72e9f020aeb0222f4ced571036dbe))
# [2.20.0-dev.3](https://github.com/revanced/revanced-cli/compare/v2.20.0-dev.2...v2.20.0-dev.3) (2023-01-15)
### Bug Fixes
* bump patcher dependency version ([51c04b7](https://github.com/revanced/revanced-cli/commit/51c04b7b162ad2876bbeb248b7ccddd105b5076d))
# [2.20.0-dev.2](https://github.com/revanced/revanced-cli/compare/v2.20.0-dev.1...v2.20.0-dev.2) (2023-01-15)
### Features
* connect to first device if given device was not found ([6485e47](https://github.com/revanced/revanced-cli/commit/6485e477a10bb89dfb2e40f3596d72b20bf23cc8))
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-02)
### Bug Fixes
* do not list compatible packages if patches do not define them ([31e4a41](https://github.com/revanced/revanced-cli/commit/31e4a41dd20f5fa62f840cd8e3b92fe0814eda87))
### Features
* remove option `--with-descriptions` ([07a423b](https://github.com/revanced/revanced-cli/commit/07a423b19ec72e9f020aeb0222f4ced571036dbe))
# [2.20.0](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0) (2023-01-01)
### Bug Fixes
* do not list compatible packages if patches do not define them ([31e4a41](https://github.com/revanced/revanced-cli/commit/31e4a41dd20f5fa62f840cd8e3b92fe0814eda87))
### Features
* remove option `--with-descriptions` ([07a423b](https://github.com/revanced/revanced-cli/commit/07a423b19ec72e9f020aeb0222f4ced571036dbe))
# [2.20.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.19.0...v2.20.0-dev.1) (2023-01-01)
### Bug Fixes
* do not list compatible packages if patches do not define them ([31e4a41](https://github.com/revanced/revanced-cli/commit/31e4a41dd20f5fa62f840cd8e3b92fe0814eda87))
### Features
* remove option `--with-descriptions` ([07a423b](https://github.com/revanced/revanced-cli/commit/07a423b19ec72e9f020aeb0222f4ced571036dbe))
# [2.19.0](https://github.com/revanced/revanced-cli/compare/v2.18.2...v2.19.0) (2022-12-31)
### Features
* improve description of options ([#185](https://github.com/revanced/revanced-cli/issues/185)) ([b69e784](https://github.com/revanced/revanced-cli/commit/b69e784785f7f262f83b35c4f241c90036169fc7))
# [2.19.0-dev.1](https://github.com/revanced/revanced-cli/compare/v2.18.2...v2.19.0-dev.1) (2022-12-31)
### Features
* improve description of options ([#185](https://github.com/revanced/revanced-cli/issues/185)) ([b69e784](https://github.com/revanced/revanced-cli/commit/b69e784785f7f262f83b35c4f241c90036169fc7))
## [2.18.2](https://github.com/revanced/revanced-cli/compare/v2.18.1...v2.18.2) (2022-12-16)
### Bug Fixes
* exclude patcher dependency from minimizing ([d5794b9](https://github.com/revanced/revanced-cli/commit/d5794b94ca19c9287190a3b863c97a089893cc07))
## [2.18.2-dev.1](https://github.com/revanced/revanced-cli/compare/v2.18.1...v2.18.2-dev.1) (2022-12-16)
### Bug Fixes
* exclude patcher dependency from minimizing ([d5794b9](https://github.com/revanced/revanced-cli/commit/d5794b94ca19c9287190a3b863c97a089893cc07))
## [2.18.1](https://github.com/revanced/revanced-cli/compare/v2.18.0...v2.18.1) (2022-12-15)
### Bug Fixes
* don't log when package is incompatible and `exclusive` option is used ([ad81a1b](https://github.com/revanced/revanced-cli/commit/ad81a1b656586226f8b7b8d1123c52b0f3f2e6f7))
## [2.18.1-dev.1](https://github.com/revanced/revanced-cli/compare/v2.18.0...v2.18.1-dev.1) (2022-12-15)

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# 💻 ReVanced CLI
Command line application to use ReVanced.

View File

@@ -1,42 +1,40 @@
plugins {
kotlin("jvm") version "1.7.0"
id("com.github.johnrengelman.shadow") version "7.1.2"
kotlin("jvm") version "1.8.20"
alias(libs.plugins.shadow)
}
group = "app.revanced"
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
repositories {
mavenCentral()
mavenLocal()
maven {
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = githubUsername
password = githubPassword
}
}
maven { url = uri("https://jitpack.io") }
google()
}
dependencies {
implementation(kotlin("reflect"))
implementation("app.revanced:revanced-patcher:6.3.1")
implementation("info.picocli:picocli:4.7.0")
implementation("com.android.tools.build:apksig:7.2.1")
implementation("com.github.revanced:jadb:master-SNAPSHOT") // updated fork
implementation("org.bouncycastle:bcpkix-jdk15on:1.70")
implementation("cc.ekblad:4koma:1.1.0")
implementation(libs.revanced.patcher)
implementation(libs.kotlin.reflect)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.picocli)
implementation(libs.jadb) // Updated fork
implementation(libs.apksig)
implementation(libs.bcpkix.jdk15on)
implementation(libs.jackson.module.kotlin)
testImplementation(libs.kotlin.test)
}
kotlin { jvmToolchain(11) }
tasks {
test {
useJUnitPlatform()
testLogging {
events("PASSED", "SKIPPED", "FAILED")
}
}
processResources {
expand("projectVersion" to project.version)
}
build {
dependsOn(shadowJar)
}
shadowJar {
manifest {
attributes("Main-Class" to "app.revanced.cli.main.MainKt")
@@ -44,14 +42,15 @@ tasks {
minimize {
exclude(dependency("org.jetbrains.kotlin:.*"))
exclude(dependency("org.bouncycastle:.*"))
exclude(dependency("app.revanced:.*"))
}
}
// Dummy task to fix the Gradle semantic-release plugin.
// Remove this if you forked it to support building only.
// Tracking issue: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435
register<DefaultTask>("publish") {
group = "publish"
description = "Dummy task"
dependsOn(build)
}
}

17
docs/0_prerequisites.md Normal file
View File

@@ -0,0 +1,17 @@
# 💼 Prerequisites
To use ReVanced CLI, you will need to fulfil specific requirements.
## 🤝 Requirements
- 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
- 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
The following section will show you how to use ReVanced CLI.
Continue: [🛠️ Using ReVanced CLI](1_usage.md)

99
docs/1_usage.md Normal file
View File

@@ -0,0 +1,99 @@
# 🛠️ Using ReVanced CLI
Learn how to ReVanced CLI.
## ⚡ 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 serial
```bash
adb devices
```
## 🔨 Using ReVanced CLI
- ### ⚙️ Show all available options for ReVanced CLI
```bash
java -jar revanced-cli.jar -h
```
- ### 📃 List patches from supplied patch bundles
```bash
java -jar revanced-cli.jar list-patches \
--with-packages \
--with-versions \
--with-options \
revanced-patches.jar [<patch-bundle> ...]
```
- ### ⚙️ Generate options from patches using ReVanced CLI
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 of intervention when using the `patch` command.
```bash
- ### 💉 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
java -jar revanced-cli.jar patch \
--patch-bundle revanced-patches.jar \
--out output.apk \
--device-serial <device-serial> \
input.apk
```
- ### 👾 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
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
```
> **Note**: Some patches may require integrations
such as [ReVanced Integrations](https://github.com/revanced/revanced-integrations).
Supply them with the option `-m`. If any patches accepted by ReVanced Patcher require ReVanced Integrations,
they will be merged into the APK file automatically.
- ### 🗑️ Uninstall a patched
```bash
java -jar revanced-cli.jar uninstall \
--package-name <package-name> \
<device-serial>
```

8
docs/README.md Normal file
View File

@@ -0,0 +1,8 @@
# 💻 Documentation and guides of ReVanced CLI
This documentation explains how to use [ReVanced CLI](https://github.com/revanced/revanced-cli).
## 📖 Table of contents
1. [💼 Prerequisites](0_prerequisites.md)
2. [🛠️ Using ReVanced CLI](1_usage.md)

View File

@@ -1,2 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 2.18.1-dev.1
version = 3.0.0-dev.1

25
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,25 @@
[versions]
shadow = "8.1.1"
apksig = "8.1.0"
bcpkix-jdk15on = "1.70"
jackson-module-kotlin = "2.14.3"
jadb = "2531a28109"
kotlin-reflect = "1.9.0"
kotlin-test = "1.8.20-RC"
kotlinx-coroutines-core = "1.7.1"
picocli = "4.7.3"
revanced-patcher = "14.0.0"
[libraries]
apksig = { module = "com.android.tools.build:apksig", version.ref = "apksig" }
bcpkix-jdk15on = { module = "org.bouncycastle:bcpkix-jdk15on", version.ref = "bcpkix-jdk15on" }
jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson-module-kotlin" }
jadb = { module = "com.github.revanced:jadb", version.ref = "jadb" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin-reflect" }
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-coroutines-core" }
picocli = { module = "info.picocli:picocli", version.ref = "picocli" }
revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" }
[plugins]
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

293
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,98 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# 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"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +118,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,88 +129,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# 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"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

15
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

727
package-lock.json generated
View File

@@ -5,10 +5,11 @@
"packages": {
"": {
"devDependencies": {
"@saithodev/semantic-release-backmerge": "^3.1.0",
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.4",
"semantic-release": "^19.0.5"
"gradle-semantic-release-plugin": "^1.7.6",
"semantic-release": "^20.1.0"
}
},
"node_modules/@babel/code-frame": {
@@ -312,6 +313,20 @@
"@octokit/openapi-types": "^14.0.0"
}
},
"node_modules/@saithodev/semantic-release-backmerge": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@saithodev/semantic-release-backmerge/-/semantic-release-backmerge-3.1.0.tgz",
"integrity": "sha512-92AN5eI8svpxeUD6cw2JjCrHHZVlWIxQ67SiSSwoI1UP4N5QohCOf9O/W3OUApxKg3C8Y0RpGt7TUpGEwGhXhw==",
"dev": true,
"dependencies": {
"@semantic-release/error": "^3.0.0",
"aggregate-error": "^3.1.0",
"debug": "^4.3.4",
"execa": "^5.1.1",
"lodash": "^4.17.21",
"semantic-release": ">=20.0.0"
}
},
"node_modules/@semantic-release/changelog": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.2.tgz",
@@ -498,12 +513,6 @@
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==",
"dev": true
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
"dev": true
},
"node_modules/@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
@@ -580,6 +589,12 @@
"integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
"node_modules/argv-formatter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz",
@@ -735,14 +750,17 @@
}
},
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/color-convert": {
@@ -887,19 +905,18 @@
"dev": true
},
"node_modules/cosmiconfig": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.0.0.tgz",
"integrity": "sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==",
"dev": true,
"dependencies": {
"@types/parse-json": "^4.0.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"parse-json": "^5.0.0",
"path-type": "^4.0.0",
"yaml": "^1.10.0"
"path-type": "^4.0.0"
},
"engines": {
"node": ">=10"
"node": ">=14"
}
},
"node_modules/cross-spawn": {
@@ -1077,17 +1094,126 @@
"dev": true
},
"node_modules/env-ci": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/env-ci/-/env-ci-5.5.0.tgz",
"integrity": "sha512-o0JdWIbOLP+WJKIUt36hz1ImQQFuN92nhsfTkHHap+J8CiI8WgGpH/a9jEGHh4/TU5BUUGjlnKXNoDb57+ne+A==",
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/env-ci/-/env-ci-8.0.0.tgz",
"integrity": "sha512-W+3BqGZozFua9MPeXpmTm5eYEBtGgL76jGu/pwMVp/L8PdECSCEWaIp7d4Mw7kuUrbUldK0oV0bNd6ZZjLiMiA==",
"dev": true,
"dependencies": {
"execa": "^5.0.0",
"fromentries": "^1.3.2",
"java-properties": "^1.0.0"
"execa": "^6.1.0",
"java-properties": "^1.0.2"
},
"engines": {
"node": ">=10.17"
"node": "^16.10 || >=18"
}
},
"node_modules/env-ci/node_modules/execa": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
"integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.1",
"human-signals": "^3.0.1",
"is-stream": "^3.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^5.1.0",
"onetime": "^6.0.0",
"signal-exit": "^3.0.7",
"strip-final-newline": "^3.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/env-ci/node_modules/human-signals": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz",
"integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==",
"dev": true,
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/env-ci/node_modules/is-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/env-ci/node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/env-ci/node_modules/npm-run-path": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
"integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
"dev": true,
"dependencies": {
"path-key": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/env-ci/node_modules/onetime": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/env-ci/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/env-ci/node_modules/strip-final-newline": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/error-ex": {
@@ -1179,15 +1305,28 @@
}
},
"node_modules/figures": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz",
"integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==",
"dev": true,
"dependencies": {
"escape-string-regexp": "^1.0.5"
"escape-string-regexp": "^5.0.0",
"is-unicode-supported": "^1.2.0"
},
"engines": {
"node": ">=8"
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/figures/node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -1219,15 +1358,15 @@
}
},
"node_modules/find-versions": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz",
"integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==",
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz",
"integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==",
"dev": true,
"dependencies": {
"semver-regex": "^3.1.2"
"semver-regex": "^4.0.5"
},
"engines": {
"node": ">=10"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -1243,26 +1382,6 @@
"readable-stream": "^2.0.0"
}
},
"node_modules/fromentries": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz",
"integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/fs-extra": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz",
@@ -1402,9 +1521,9 @@
"dev": true
},
"node_modules/gradle-semantic-release-plugin": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.7.4.tgz",
"integrity": "sha512-Mm2JnmodHxQlCmn0GtSi5j8z4PS2+2VBY993b9GuNGGM+JaIrr8T3tF9uTLR2nGH/oJba6a9jx1ZqVEJdOXDPw==",
"version": "1.7.6",
"resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.7.6.tgz",
"integrity": "sha512-FNoZAm9jntxOXLee5uJLlCb9hsFsJ1d4jUnvz08NF6p72OwSmaSBeFN7Wnl6RjW8mPrAuOSwkuinuWWjVeO2aw==",
"dev": true,
"funding": [
{
@@ -1413,14 +1532,14 @@
}
],
"dependencies": {
"promisified-properties": "^2.0.3",
"promisified-properties": "^2.0.27",
"split2": "^4.1.0"
},
"engines": {
"node": ">=16 || ^14.17"
"node": ">=18"
},
"peerDependencies": {
"semantic-release": "^19.0.2"
"semantic-release": "^20.0.0"
}
},
"node_modules/handlebars": {
@@ -1475,12 +1594,15 @@
}
},
"node_modules/hook-std": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-2.0.0.tgz",
"integrity": "sha512-zZ6T5WcuBMIUVh49iPQS9t977t7C0l7OtHrpeMb5uk48JdflRX0NSFvCekfYNmGQETnLq9W/isMyHl69kxGi8g==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz",
"integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==",
"dev": true,
"engines": {
"node": ">=8"
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/hosted-git-info": {
@@ -1750,6 +1872,18 @@
"node": ">=0.10.0"
}
},
"node_modules/is-unicode-supported": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz",
"integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -1793,6 +1927,18 @@
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-parse-better-errors": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
@@ -1909,6 +2055,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
"dev": true
},
"node_modules/lodash.capitalize": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz",
@@ -4817,12 +4969,12 @@
}
},
"node_modules/p-each-series": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
"integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz",
"integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==",
"dev": true,
"engines": {
"node": ">=8"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -5102,9 +5254,9 @@
"dev": true
},
"node_modules/promisified-properties": {
"version": "2.0.25",
"resolved": "https://registry.npmjs.org/promisified-properties/-/promisified-properties-2.0.25.tgz",
"integrity": "sha512-FtyMDSNf3IwVBjVq4uj5JD4lG+YmOMzt/Huuc+VwPHVqbzim3/U04iMBnVH3lYgOc9s5Jj9sC4G0OVGoo2KbWA==",
"version": "2.0.27",
"resolved": "https://registry.npmjs.org/promisified-properties/-/promisified-properties-2.0.27.tgz",
"integrity": "sha512-fmx256M3b0QcHnqOj+Ok127LoYpmnYRf7g2OyLl7qD7Z0fzNbIZhHHIPKyvegbA29iAPP5BVWv7BJ/y2cMHHjA==",
"dev": true,
"dependencies": {
"parsimmon": "^1.13.0"
@@ -5393,9 +5545,9 @@
"dev": true
},
"node_modules/semantic-release": {
"version": "19.0.5",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.5.tgz",
"integrity": "sha512-NMPKdfpXTnPn49FDogMBi36SiBfXkSOJqCkk0E4iWOY1tusvvgBwqUmxTX1kmlT6kIYed9YwNKD1sfPpqa5yaA==",
"version": "20.1.0",
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-20.1.0.tgz",
"integrity": "sha512-+9+n6RIr0Fz0F53cXrjpawxWlUg3O7/qr1jF9lrE+/v6WqwBrSWnavVHTPaf2WLerET2EngoqI0M4pahkKl6XQ==",
"dev": true,
"dependencies": {
"@semantic-release/commit-analyzer": "^9.0.2",
@@ -5403,35 +5555,350 @@
"@semantic-release/github": "^8.0.0",
"@semantic-release/npm": "^9.0.0",
"@semantic-release/release-notes-generator": "^10.0.0",
"aggregate-error": "^3.0.0",
"cosmiconfig": "^7.0.0",
"aggregate-error": "^4.0.1",
"cosmiconfig": "^8.0.0",
"debug": "^4.0.0",
"env-ci": "^5.0.0",
"execa": "^5.0.0",
"figures": "^3.0.0",
"find-versions": "^4.0.0",
"env-ci": "^8.0.0",
"execa": "^6.1.0",
"figures": "^5.0.0",
"find-versions": "^5.1.0",
"get-stream": "^6.0.0",
"git-log-parser": "^1.2.0",
"hook-std": "^2.0.0",
"hosted-git-info": "^4.0.0",
"lodash": "^4.17.21",
"marked": "^4.0.10",
"marked-terminal": "^5.0.0",
"hook-std": "^3.0.0",
"hosted-git-info": "^6.0.0",
"lodash-es": "^4.17.21",
"marked": "^4.1.0",
"marked-terminal": "^5.1.1",
"micromatch": "^4.0.2",
"p-each-series": "^2.1.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^7.0.0",
"p-each-series": "^3.0.0",
"p-reduce": "^3.0.0",
"read-pkg-up": "^9.1.0",
"resolve-from": "^5.0.0",
"semver": "^7.3.2",
"semver-diff": "^3.1.1",
"semver-diff": "^4.0.0",
"signale": "^1.2.1",
"yargs": "^16.2.0"
"yargs": "^17.5.1"
},
"bin": {
"semantic-release": "bin/semantic-release.js"
},
"engines": {
"node": ">=16 || ^14.17"
"node": ">=18"
}
},
"node_modules/semantic-release/node_modules/aggregate-error": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz",
"integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==",
"dev": true,
"dependencies": {
"clean-stack": "^4.0.0",
"indent-string": "^5.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/clean-stack": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz",
"integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==",
"dev": true,
"dependencies": {
"escape-string-regexp": "5.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/execa": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz",
"integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.1",
"human-signals": "^3.0.1",
"is-stream": "^3.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^5.1.0",
"onetime": "^6.0.0",
"signal-exit": "^3.0.7",
"strip-final-newline": "^3.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/semantic-release/node_modules/find-up": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz",
"integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==",
"dev": true,
"dependencies": {
"locate-path": "^7.1.0",
"path-exists": "^5.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/hosted-git-info": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz",
"integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==",
"dev": true,
"dependencies": {
"lru-cache": "^7.5.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/semantic-release/node_modules/human-signals": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz",
"integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==",
"dev": true,
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/semantic-release/node_modules/indent-string": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz",
"integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/is-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/locate-path": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
"integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
"dev": true,
"dependencies": {
"p-locate": "^6.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/lru-cache": {
"version": "7.14.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz",
"integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/semantic-release/node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/npm-run-path": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
"integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
"dev": true,
"dependencies": {
"path-key": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/onetime": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/p-limit": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^1.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/p-locate": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
"integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
"dev": true,
"dependencies": {
"p-limit": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/p-reduce": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz",
"integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/path-exists": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
"integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/semantic-release/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/read-pkg": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz",
"integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==",
"dev": true,
"dependencies": {
"@types/normalize-package-data": "^2.4.1",
"normalize-package-data": "^3.0.2",
"parse-json": "^5.2.0",
"type-fest": "^2.0.0"
},
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/read-pkg-up": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz",
"integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==",
"dev": true,
"dependencies": {
"find-up": "^6.3.0",
"read-pkg": "^7.1.0",
"type-fest": "^2.5.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/strip-final-newline": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semantic-release/node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
"dev": true,
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semver": {
@@ -5450,33 +5917,27 @@
}
},
"node_modules/semver-diff": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
"integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz",
"integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==",
"dev": true,
"dependencies": {
"semver": "^6.3.0"
"semver": "^7.3.5"
},
"engines": {
"node": ">=8"
}
},
"node_modules/semver-diff/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/semver-regex": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.4.tgz",
"integrity": "sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA==",
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz",
"integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==",
"dev": true,
"engines": {
"node": ">=8"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -6067,31 +6528,22 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yaml": {
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"engines": {
"node": ">= 6"
}
},
"node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
"version": "17.6.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz",
"integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==",
"dev": true,
"dependencies": {
"cliui": "^7.0.2",
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.0",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^20.2.2"
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=10"
"node": ">=12"
}
},
"node_modules/yargs-parser": {
@@ -6102,6 +6554,27 @@
"engines": {
"node": ">=10"
}
},
"node_modules/yargs/node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/yocto-queue": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
"dev": true,
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
}
}
}

View File

@@ -1,8 +1,9 @@
{
"devDependencies": {
"@saithodev/semantic-release-backmerge": "^3.1.0",
"@semantic-release/changelog": "^6.0.2",
"@semantic-release/git": "^10.0.1",
"gradle-semantic-release-plugin": "^1.7.4",
"semantic-release": "^19.0.5"
"gradle-semantic-release-plugin": "^1.7.6",
"semantic-release": "^20.1.0"
}
}

View File

@@ -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"

View File

@@ -1,37 +0,0 @@
package app.revanced.cli.aligning
import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.PatcherResult
import app.revanced.utils.signing.align.ZipAligner
import app.revanced.utils.signing.align.zip.ZipFile
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import java.io.File
object Aligning {
fun align(result: PatcherResult, inputFile: File, outputFile: File) {
logger.info("Aligning ${inputFile.name} to ${outputFile.name}")
if (outputFile.exists()) outputFile.delete()
ZipFile(outputFile).use { file ->
result.dexFiles.forEach {
file.addEntryCompressData(
ZipEntry.createWithName(it.name),
it.stream.readBytes()
)
}
result.resourceFile?.let {
file.copyEntriesFromFileAligned(
ZipFile(it),
ZipAligner::getEntryAlignment
)
}
file.copyEntriesFromFileAligned(
ZipFile(inputFile),
ZipAligner::getEntryAlignment
)
}
}
}

View File

@@ -0,0 +1,94 @@
package app.revanced.cli.command
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.PatchClass
import app.revanced.patcher.patch.PatchOption
import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File
@Command(name = "list-patches", description = ["List patches from supplied patch bundles"])
internal object ListPatchesCommand : Runnable {
@Parameters(
description = ["Paths to patch bundles"],
arity = "1..*"
)
lateinit var patchBundles: Array<File>
@Option(
names = ["-d", "--with-descriptions"],
description = ["List their descriptions"],
showDefaultValue = ALWAYS
)
var withDescriptions: Boolean = true
@Option(
names = ["-p", "--with-packages"],
description = ["List the packages the patches are compatible with"],
showDefaultValue = ALWAYS
)
var withPackages: Boolean = false
@Option(
names = ["-v", "--with-versions"],
description = ["List the versions of the packages the patches are compatible with"],
showDefaultValue = ALWAYS
)
var withVersions: Boolean = false
@Option(
names = ["-o", "--with-options"],
description = ["List the options of the patches"],
showDefaultValue = ALWAYS
)
var withOptions: Boolean = false
override fun run() {
fun Package.buildString() = buildString {
if (withVersions && versions.isNotEmpty()) {
appendLine("Package name: $name")
appendLine("Compatible versions:")
append(versions.joinToString("\n") { version -> version }.prependIndent("\t"))
} else
append("Package name: $name")
}
fun PatchOption<*>.buildString() = buildString {
appendLine("Title: $title")
appendLine("Description: $description")
value?.let {
appendLine("Key: $key")
append("Value: $it")
} ?: append("Key: $key")
}
fun PatchClass.buildString() = buildString {
append("Name: $patchName")
if (withDescriptions) append("\nDescription: $description")
if (withOptions && options != null) {
appendLine("\nOptions:")
append(
options!!.joinToString("\n\n") { option -> option.buildString() }.prependIndent("\t")
)
}
if (withPackages && compatiblePackages != null) {
appendLine("\nCompatible packages:")
append(
compatiblePackages!!.joinToString("\n") { it.buildString() }.prependIndent("\t")
)
}
}
logger.info(PatchBundleLoader.Jar(*patchBundles).joinToString("\n\n") { it.buildString() })
}
}

View File

@@ -0,0 +1,40 @@
package app.revanced.cli.command
import app.revanced.cli.logging.impl.DefaultCliLogger
import app.revanced.patcher.patch.PatchClass
import picocli.CommandLine
import picocli.CommandLine.Command
import picocli.CommandLine.IVersionProvider
import java.util.*
fun main(args: Array<String>) {
CommandLine(Main).execute(*args)
}
internal typealias PatchList = List<PatchClass>
internal val logger = DefaultCliLogger()
object CLIVersionProvider : IVersionProvider {
override fun getVersion(): Array<String> {
Properties().apply {
load(Main::class.java.getResourceAsStream("/app/revanced/cli/version.properties"))
}.let {
return arrayOf("ReVanced CLI v${it.getProperty("version")}")
}
}
}
@Command(
name = "revanced-cli",
description = ["Command line application to use ReVanced"],
mixinStandardHelpOptions = true,
versionProvider = CLIVersionProvider::class,
subcommands = [
ListPatchesCommand::class,
PatchCommand::class,
UninstallCommand::class,
OptionsCommand::class,
]
)
internal object Main

View File

@@ -1,252 +0,0 @@
package app.revanced.cli.command
import app.revanced.cli.aligning.Aligning
import app.revanced.cli.logging.impl.DefaultCliLogger
import app.revanced.cli.patcher.Patcher
import app.revanced.cli.patcher.logging.impl.PatcherLogger
import app.revanced.cli.signing.Signing
import app.revanced.cli.signing.SigningOptions
import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.util.patch.PatchBundle
import app.revanced.utils.OptionsLoader
import app.revanced.utils.adb.Adb
import picocli.CommandLine.*
import java.io.File
import java.nio.file.Files
private class CLIVersionProvider : IVersionProvider {
override fun getVersion() = arrayOf(
MainCommand::class.java.`package`.implementationVersion ?: "unknown"
)
}
@Command(
name = "ReVanced-CLI",
mixinStandardHelpOptions = true,
versionProvider = CLIVersionProvider::class
)
internal object MainCommand : Runnable {
val logger = DefaultCliLogger()
@ArgGroup(exclusive = false, multiplicity = "1")
lateinit var args: Args
class Args {
@Option(names = ["-a", "--apk"], description = ["Input file to be patched"], required = true)
lateinit var inputFile: File
@Option(names = ["--uninstall"], description = ["Uninstall the mount variant"])
var uninstall: Boolean = false
@Option(names = ["-d", "--deploy-on"], description = ["If specified, deploy to adb device with given name"])
var deploy: String? = null
@ArgGroup(exclusive = false)
var patchArgs: PatchArgs? = null
}
class PatchArgs {
@Option(names = ["-b", "--bundles"], description = ["One or more bundles of patches"], required = true)
var patchBundles = arrayOf<String>()
@Option(names = ["--options"], description = ["Configuration file for all patch options"])
var options: File = File("options.toml")
@ArgGroup(exclusive = false)
var listingArgs: ListingArgs? = null
@ArgGroup(exclusive = false)
var patchingArgs: PatchingArgs? = null
}
class ListingArgs {
@Option(names = ["-l", "--list"], description = ["List patches only"], required = true)
var listOnly: Boolean = false
@Option(names = ["--with-versions"], description = ["List patches with compatible versions"])
var withVersions: Boolean = false
@Option(names = ["--with-packages"], description = ["List patches with compatible packages"])
var withPackages: Boolean = false
@Option(names = ["--with-descriptions"], description = ["List patches with their descriptions"])
var withDescriptions: Boolean = true
}
class PatchingArgs {
@Option(names = ["-o", "--out"], description = ["Output file path"], required = true)
lateinit var outputPath: String
@Option(names = ["-e", "--exclude"], description = ["Explicitly exclude patches"])
var excludedPatches = arrayOf<String>()
@Option(
names = ["--exclusive"],
description = ["Only installs the patches you include, not including any patch by default"]
)
var exclusive = false
@Option(names = ["-i", "--include"], description = ["Include patches"])
var includedPatches = arrayOf<String>()
@Option(names = ["--experimental"], description = ["Disable patch version compatibility patch"])
var experimental: Boolean = false
@Option(names = ["-m", "--merge"], description = ["One or more dex file containers to merge"])
var mergeFiles = listOf<File>()
@Option(names = ["--mount"], description = ["If specified, instead of installing, mount"])
var mount: Boolean = false
@Option(names = ["--cn"], description = ["Overwrite the default CN for the signed file"])
var cn = "ReVanced"
@Option(names = ["--keystore"], description = ["File path to your keystore"])
var keystorePath: String? = null
@Option(names = ["-p", "--password"], description = ["Overwrite the default password for the signed file"])
var password = "ReVanced"
@Option(names = ["-t", "--temp-dir"], description = ["Temporary resource cache directory"])
var cacheDirectory = "revanced-cache"
@Option(
names = ["-c", "--clean"],
description = ["Clean the temporary resource cache directory. This will be done anyways when running the patcher"]
)
var clean: Boolean = false
@Option(names = ["--custom-aapt2-binary"], description = ["Path to custom aapt2 binary"])
var aaptPath: String = ""
}
override fun run() {
if (args.patchArgs?.listingArgs?.listOnly == true) return printListOfPatches()
if (args.uninstall) return uninstall()
val pArgs = this.args.patchArgs?.patchingArgs ?: return
val outputFile = File(pArgs.outputPath) // the file to write to
val allPatches = args.patchArgs!!.patchBundles.flatMap { bundle ->
PatchBundle.Jar(bundle).loadPatches()
}
OptionsLoader.init(args.patchArgs!!.options, allPatches)
val patcher = app.revanced.patcher.Patcher(
PatcherOptions(
args.inputFile.also { if (!it.exists()) return logger.error("Input file ${args.inputFile} does not exist.") },
pArgs.cacheDirectory,
pArgs.aaptPath,
pArgs.cacheDirectory,
PatcherLogger
)
)
// prepare adb
val adb: Adb? = args.deploy?.let {
Adb(outputFile, patcher.context.packageMetadata.packageName, args.deploy!!, !pArgs.mount)
}
// start the patcher
val result = Patcher.start(patcher, allPatches)
val cacheDirectory = File(pArgs.cacheDirectory)
// align the file
val alignedFile = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_aligned.apk")
Aligning.align(result, args.inputFile, alignedFile)
// sign the file
val finalFile = if (!pArgs.mount) {
val signedOutput = cacheDirectory.resolve("${outputFile.nameWithoutExtension}_signed.apk")
Signing.sign(
alignedFile,
signedOutput,
SigningOptions(
pArgs.cn,
pArgs.password,
pArgs.keystorePath ?: outputFile.absoluteFile.parentFile
.resolve("${outputFile.nameWithoutExtension}.keystore")
.canonicalPath
)
)
signedOutput
} else
alignedFile
// finally copy to the specified output file
logger.info("Copying ${finalFile.name} to ${outputFile.name}")
finalFile.copyTo(outputFile, overwrite = true)
// clean up the cache directory if needed
if (pArgs.clean)
cleanUp(pArgs.cacheDirectory)
// deploy if specified
adb?.deploy()
if (pArgs.clean && args.deploy != null) Files.delete(outputFile.toPath())
logger.info("Finished")
}
private fun cleanUp(cacheDirectory: String) {
val result = if (File(cacheDirectory).deleteRecursively())
"Cleaned up cache directory"
else
"Failed to clean up cache directory"
logger.info(result)
}
private fun uninstall() {
val adb: Adb? = args.deploy?.let {
Adb(
File("placeholder_file"),
app.revanced.patcher.Patcher(PatcherOptions(args.inputFile, "")).context.packageMetadata.packageName,
args.deploy!!,
false
)
}
adb?.uninstall()
}
private fun printListOfPatches() {
val logged = mutableListOf<String>()
for (patchBundlePath in args.patchArgs?.patchBundles!!) for (patch in PatchBundle.Jar(patchBundlePath)
.loadPatches()) {
if (patch.patchName in logged) continue
for (compatiblePackage in patch.compatiblePackages!!) {
val packageEntryStr = buildString {
// Add package if flag is set
if (args.patchArgs?.listingArgs?.withPackages == true) {
val packageName = compatiblePackage.name.substringAfterLast(".").padStart(10)
append(packageName)
append("\t")
}
// Add patch name
val patchName = patch.patchName.padStart(25)
append(patchName)
// Add description if flag is set.
if (args.patchArgs?.listingArgs?.withDescriptions == true) {
append("\t")
append(patch.description)
}
// Add compatible versions, if flag is set
if (args.patchArgs?.listingArgs?.withVersions == true) {
val compatibleVersions = compatiblePackage.versions.joinToString(separator = ", ")
append("\t")
append(compatibleVersions)
}
}
logged.add(patch.patchName)
logger.info(packageEntryStr)
}
}
}
}

View File

@@ -0,0 +1,50 @@
package app.revanced.cli.command
import app.revanced.patcher.PatchBundleLoader
import app.revanced.utils.Options
import app.revanced.utils.Options.setOptions
import picocli.CommandLine
import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File
@CommandLine.Command(
name = "options",
description = ["Generate options file from patches"],
)
internal object OptionsCommand : Runnable {
@CommandLine.Parameters(
description = ["Paths to patch bundles"],
arity = "1..*"
)
lateinit var patchBundles: Array<File>
@CommandLine.Option(
names = ["-p", "--path"],
description = ["Path to patch options JSON file"],
showDefaultValue = ALWAYS
)
var path: File = File("options.json")
@CommandLine.Option(
names = ["-o", "--overwrite"],
description = ["Overwrite existing options file"],
showDefaultValue = ALWAYS
)
var overwrite: Boolean = false
@CommandLine.Option(
names = ["-u", "--update"],
description = ["Update existing options by adding missing and removing non-existent options"],
showDefaultValue = ALWAYS
)
var update: Boolean = false
override fun run() = if (!path.exists() || overwrite)
with(PatchBundleLoader.Jar(*patchBundles)) {
if (update) setOptions(path, logger)
Options.serialize(this, prettyPrint = true)
.let(path::writeText)
}
else logger.error("Options file already exists, use --override to override it")
}

View File

@@ -0,0 +1,412 @@
package app.revanced.cli.command
import app.revanced.cli.patcher.logging.impl.PatcherLogger
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.Patcher
import app.revanced.patcher.PatcherOptions
import app.revanced.patcher.PatcherResult
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.utils.Options
import app.revanced.utils.Options.setOptions
import app.revanced.utils.adb.AdbManager
import app.revanced.utils.align.ZipAligner
import app.revanced.utils.align.zip.ZipFile
import app.revanced.utils.align.zip.structures.ZipEntry
import app.revanced.utils.signing.ApkSigner
import app.revanced.utils.signing.SigningOptions
import kotlinx.coroutines.runBlocking
import picocli.CommandLine
import picocli.CommandLine.Help.Visibility.ALWAYS
import java.io.File
@CommandLine.Command(
name = "patch",
description = ["Patch the supplied APK file with the supplied patches and integrations"]
)
internal object PatchCommand: Runnable {
@CommandLine.Parameters(
description = ["APK file to be patched"],
arity = "1..1"
)
lateinit var apk: File
@CommandLine.Option(
names = ["-b", "--patch-bundle"],
description = ["One or more bundles of patches"],
required = true
)
var patchBundles = emptyList<File>()
@CommandLine.Option(
names = ["-m", "--merge"],
description = ["One or more DEX files or containers to merge into the APK"]
)
var integrations = listOf<File>()
@CommandLine.Option(
names = ["-i", "--include"],
description = ["List of patches to include"]
)
var includedPatches = arrayOf<String>()
@CommandLine.Option(
names = ["-e", "--exclude"],
description = ["List of patches to exclude"]
)
var excludedPatches = arrayOf<String>()
@CommandLine.Option(
names = ["--options"],
description = ["Path to patch options JSON file"],
showDefaultValue = ALWAYS
)
var optionsFile: File = File("options.json")
@CommandLine.Option(
names = ["--exclusive"],
description = ["Only include patches that are explicitly specified to be included"],
showDefaultValue = ALWAYS
)
var exclusive = false
@CommandLine.Option(
names = ["--experimental"],
description = ["Ignore patches incompatibility to versions"],
showDefaultValue = ALWAYS
)
var experimental: Boolean = false
@CommandLine.Option(
names = ["-o", "--out"],
description = ["Path to save the patched APK file to"],
required = true
)
lateinit var outputFilePath: File
@CommandLine.Option(
names = ["-d", "--device-serial"],
description = ["ADB device serial to install to"],
showDefaultValue = ALWAYS
)
var deviceSerial: String? = null
@CommandLine.Option(
names = ["--mount"],
description = ["Install by mounting the patched package"],
showDefaultValue = ALWAYS
)
var mount: Boolean = false
@CommandLine.Option(
names = ["--common-name"],
description = ["The common name of the signer of the patched APK file"],
showDefaultValue = ALWAYS
)
var commonName = "ReVanced"
@CommandLine.Option(
names = ["--keystore"],
description = ["Path to the keystore to sign the patched APK file with"]
)
var keystorePath: String? = null
@CommandLine.Option(
names = ["--password"],
description = ["The password of the keystore to sign the patched APK file with"]
)
var password = "ReVanced"
@CommandLine.Option(
names = ["-r", "--resource-cache"],
description = ["Path to temporary resource cache directory"],
showDefaultValue = ALWAYS
)
var resourceCachePath = File("revanced-resource-cache")
@CommandLine.Option(
names = ["--custom-aapt2-binary"],
description = ["Path to a custom AAPT binary to compile resources with"]
)
var aaptBinaryPath = File("")
@CommandLine.Option(
names = ["-p", "--purge"],
description = ["Purge the temporary resource cache directory after patching"],
showDefaultValue = ALWAYS
)
var purge: Boolean = false
override fun run() {
// region Prepare
if (!apk.exists()) {
logger.error("Input file ${apk.name} does not exist")
return
}
val adbManager = deviceSerial?.let { serial ->
if (mount) AdbManager.RootAdbManager(serial, logger) else AdbManager.UserAdbManager(
serial,
logger
)
}
// endregion
// region Load patches
logger.info("Loading patches")
val patches = PatchBundleLoader.Jar(*patchBundles.toTypedArray())
val integrations = integrations
logger.info("Setting patch options")
optionsFile.let {
if (it.exists()) patches.setOptions(it, logger)
else Options.serialize(patches, prettyPrint = true).let(it::writeText)
}
// endregion
// region Patch
val patcher = Patcher(
PatcherOptions(
apk,
resourceCachePath,
aaptBinaryPath.path,
resourceCachePath.absolutePath,
PatcherLogger
)
)
val result = patcher.apply {
acceptIntegrations(integrations)
acceptPatches(filterPatchSelection(patches))
// Execute patches.
runBlocking {
apply(false).collect { patchResult ->
patchResult.exception?.let {
logger.error("${patchResult.patchName} failed:\n${patchResult.exception}")
} ?: logger.info("${patchResult.patchName} succeeded")
}
}
}.get()
patcher.close()
// endregion
// region Finish
val alignAndSignedFile = sign(
apk.newAlignedFile(
result,
resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_aligned.apk")
)
)
logger.info("Copying to ${outputFilePath.name}")
alignAndSignedFile.copyTo(outputFilePath, overwrite = true)
adbManager?.install(AdbManager.Apk(outputFilePath, patcher.context.packageMetadata.packageName))
if (purge) {
logger.info("Purging temporary files")
outputFilePath.delete()
purge(resourceCachePath)
}
// endregion
}
/**
* Filter the patches to be added to the patcher. The filter is based on the following:
* - [includedPatches] (explicitly included)
* - [excludedPatches] (explicitly excluded)
* - [exclusive] (only include patches that are explicitly included)
* - [experimental] (ignore patches incompatibility to versions)
* - package name and version of the input APK file (if [experimental] is false)
*
* @param patches The patches to filter.
* @return The filtered patches.
*/
private fun Patcher.filterPatchSelection(patches: PatchList) = buildList {
val packageName = context.packageMetadata.packageName
val packageVersion = context.packageMetadata.packageVersion
patches.forEach patch@{ patch ->
val formattedPatchName = patch.patchName.lowercase().replace(" ", "-")
/**
* Check if the patch is explicitly excluded.
*
* Cases:
* 1. -e patch.name
* 2. -i patch.name -e patch.name
*/
/**
* Check if the patch is explicitly excluded.
*
* Cases:
* 1. -e patch.name
* 2. -i patch.name -e patch.name
*/
val excluded = excludedPatches.contains(formattedPatchName)
if (excluded) return@patch logger.info("Excluding ${patch.patchName}")
/**
* Check if the patch is constrained to packages.
*/
/**
* Check if the patch is constrained to packages.
*/
patch.compatiblePackages?.let { packages ->
packages.singleOrNull { it.name == packageName }?.let { `package` ->
/**
* Check if the package version matches.
* If experimental is true, version matching will be skipped.
*/
/**
* Check if the package version matches.
* If experimental is true, version matching will be skipped.
*/
val matchesVersion = experimental || `package`.versions.let {
it.isEmpty() || it.any { version -> version == packageVersion }
}
if (!matchesVersion) return@patch logger.warn(
"${patch.patchName} is incompatible with version $packageVersion. " +
"This patch is only compatible with version " +
packages.joinToString(";") { pkg ->
"${pkg.name}: ${pkg.versions.joinToString(", ")}"
}
)
} ?: return@patch logger.trace(
"${patch.patchName} is incompatible with $packageName. " +
"This patch is only compatible with " +
packages.joinToString(", ") { `package` -> `package`.name }
)
return@let
} ?: logger.trace("$formattedPatchName: No constraint on packages.")
/**
* Check if the patch is explicitly included.
*
* Cases:
* 1. --exclusive
* 2. --exclusive -i patch.name
*/
/**
* Check if the patch is explicitly included.
*
* Cases:
* 1. --exclusive
* 2. --exclusive -i patch.name
*/
val explicitlyIncluded = includedPatches.contains(formattedPatchName)
val implicitlyIncluded = !exclusive && patch.include // Case 3.
val exclusivelyIncluded = exclusive && explicitlyIncluded // Case 2.
val included = implicitlyIncluded || exclusivelyIncluded
if (!included) return@patch logger.info("${patch.patchName} excluded by default") // Case 1.
logger.trace("Adding $formattedPatchName")
add(patch)
}
}
/**
* Create a new aligned APK file.
*
* @param result The result of the patching process.
* @param outputFile The file to save the aligned APK to.
*/
private fun File.newAlignedFile(
result: PatcherResult,
outputFile: File
): File {
logger.info("Aligning $name")
if (outputFile.exists()) outputFile.delete()
ZipFile(outputFile).use { file ->
result.dexFiles.forEach {
file.addEntryCompressData(
ZipEntry.createWithName(it.name),
it.stream.readBytes()
)
}
result.resourceFile?.let {
file.copyEntriesFromFileAligned(
ZipFile(it),
ZipAligner::getEntryAlignment
)
}
// TODO: Do not compress result.doNotCompress
file.copyEntriesFromFileAligned(
ZipFile(this),
ZipAligner::getEntryAlignment
)
}
return outputFile
}
/**
* Sign the APK file.
*
* @param inputFile The APK file to sign.
* @return The signed APK file. If [mount] is true, the input file will be returned.
*/
private fun sign(inputFile: File) = if (mount)
inputFile
else {
logger.info("Signing ${inputFile.name}")
val keyStoreFilePath = keystorePath ?: outputFilePath
.absoluteFile.parentFile.resolve("${outputFilePath.nameWithoutExtension}.keystore").canonicalPath
val options = SigningOptions(
commonName,
password,
keyStoreFilePath
)
ApkSigner(options)
.signApk(
inputFile,
resourceCachePath.resolve("${outputFilePath.nameWithoutExtension}_signed.apk")
)
}
private fun purge(resourceCachePath: File) {
val result = if (resourceCachePath.deleteRecursively())
"Purged resource cache directory"
else
"Failed to purge resource cache directory"
logger.info(result)
}
}

View File

@@ -0,0 +1,44 @@
package app.revanced.cli.command
import app.revanced.utils.adb.AdbManager
import picocli.CommandLine.*
import picocli.CommandLine.Help.Visibility.ALWAYS
@Command(
name = "uninstall",
description = ["Uninstall a patched APK file from the devices with the supplied ADB device serials"]
)
internal object UninstallCommand : Runnable {
@Parameters(
description = ["ADB device serials"],
arity = "1..*"
)
lateinit var deviceSerials: Array<String>
@Option(
names = ["-p", "--package-name"],
description = ["Package name to uninstall"],
required = true
)
lateinit var packageName: String
@Option(
names = ["-u", "--unmount"],
description = ["Uninstall by unmounting the patched package"],
showDefaultValue = ALWAYS
)
var unmount: Boolean = false
override fun run() = try {
deviceSerials.forEach {deviceSerial ->
if (unmount) {
AdbManager.RootAdbManager(deviceSerial, logger)
} else {
AdbManager.UserAdbManager(deviceSerial, logger)
}.uninstall(packageName)
}
} catch (e: AdbManager.DeviceNotFoundException) {
logger.error(e.toString())
}
}

View File

@@ -1,12 +1,12 @@
package app.revanced.cli.logging.impl
import app.revanced.cli.command.MainCommand
import app.revanced.cli.command.Main
import app.revanced.cli.logging.CliLogger
import java.util.logging.Logger
import java.util.logging.SimpleFormatter
internal class DefaultCliLogger(
private val logger: Logger = Logger.getLogger(MainCommand::class.java.name),
private val logger: Logger = Logger.getLogger(Main::class.java.name),
private val errorLogger: Logger = Logger.getLogger(logger.name + "Err")
) : CliLogger {

View File

@@ -1,8 +0,0 @@
package app.revanced.cli.main
import app.revanced.cli.command.MainCommand
import picocli.CommandLine
internal fun main(args: Array<String>) {
CommandLine(MainCommand).execute(*args)
}

View File

@@ -1,24 +0,0 @@
package app.revanced.cli.patcher
import app.revanced.patcher.PatcherResult
import app.revanced.patcher.data.Context
import app.revanced.patcher.patch.Patch
import app.revanced.utils.patcher.addPatchesFiltered
import app.revanced.utils.patcher.applyPatchesVerbose
import app.revanced.utils.patcher.mergeFiles
internal object Patcher {
internal fun start(
patcher: app.revanced.patcher.Patcher,
allPatches: List<Class<out Patch<Context>>>
): PatcherResult {
// merge files like necessary integrations
patcher.mergeFiles()
// add patches, but filter incompatible or excluded patches
patcher.addPatchesFiltered(allPatches)
// apply patches
patcher.applyPatchesVerbose()
return patcher.save()
}
}

View File

@@ -1,12 +0,0 @@
package app.revanced.cli.signing
import app.revanced.cli.command.MainCommand.logger
import app.revanced.utils.signing.Signer
import java.io.File
object Signing {
fun sign(alignedFile: File, signedOutput: File, signingOptions: SigningOptions) {
logger.info("Signing ${alignedFile.name} to ${signedOutput.name}")
Signer(signingOptions).signApk(alignedFile, signedOutput)
}
}

View File

@@ -0,0 +1,107 @@
package app.revanced.utils
import app.revanced.cli.command.PatchList
import app.revanced.cli.logging.CliLogger
import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.NoSuchOptionException
import app.revanced.utils.Options.PatchOption.Option
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.File
internal object Options {
private var mapper = jacksonObjectMapper()
/**
* Serializes the options for the patches in the list.
*
* @param patches The list of patches to serialize.
* @param prettyPrint Whether to pretty print the JSON.
* @return The JSON string containing the options.
* @see PatchList
*/
fun serialize(patches: PatchList, prettyPrint: Boolean = false): String = patches
.filter { it.options?.any() == true }
.map { patch ->
PatchOption(
patch.patchName,
patch.options!!.map { option -> Option(option.key, option.value) }
)
}
// See https://github.com/revanced/revanced-patches/pull/2434/commits/60e550550b7641705e81aa72acfc4faaebb225e7.
.distinctBy { it.patchName }
.let {
if (prettyPrint)
mapper.writerWithDefaultPrettyPrinter().writeValueAsString(it)
else
mapper.writeValueAsString(it)
}
/**
* Deserializes the options for the patches in the list.
*
* @param json The JSON string containing the options.
* @return The list of [PatchOption]s.
* @see PatchOption
* @see PatchList
*/
@Suppress("MemberVisibilityCanBePrivate")
fun deserialize(json: String): Array<PatchOption> = mapper.readValue(json, Array<PatchOption>::class.java)
/**
* Sets the options for the patches in the list.
*
* @param json The JSON string containing the options.
* @param logger The logger to use for logging.
*/
fun PatchList.setOptions(json: String, logger: CliLogger? = null) {
filter { it.options?.any() == true }.let { patches ->
if (patches.isEmpty()) return
val patchOptions = deserialize(json)
patches.forEach { patch ->
patchOptions.find { option -> option.patchName == patch.patchName }?.let {
it.options.forEach { option ->
try {
patch.options?.set(option.key, option.value)
?: logger?.warn("${patch.patchName} has no options")
} catch (e: NoSuchOptionException) {
logger?.error(e.message ?: "Unknown error")
}
}
}
}
}
}
/**
* Sets the options for the patches in the list.
*
* @param file The file containing the JSON string containing the options.
* @param logger The logger to use for logging.
* @see setOptions
*/
fun PatchList.setOptions(file: File, logger: CliLogger? = null) = setOptions(file.readText(), logger)
/**
* Data class for a patch and its [Option]s.
*
* @property patchName The name of the patch.
* @property options The [Option]s for the patch.
*/
internal data class PatchOption(
val patchName: String,
val options: List<Option>
) {
/**
* Data class for patch option.
*
* @property key The name of the option.
* @property value The value of the option.
*/
internal data class Option(val key: String, val value: Any?)
}
}

View File

@@ -1,77 +0,0 @@
package app.revanced.utils
import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.Patcher
import app.revanced.patcher.data.Context
import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
import cc.ekblad.toml.encodeToString
import cc.ekblad.toml.model.TomlValue
import cc.ekblad.toml.serialization.from
import cc.ekblad.toml.tomlMapper
import java.io.File
private typealias PatchList = List<Class<out Patch<Context>>>
private typealias OptionsMap = MutableMap<String, MutableMap<String, Any>>
object OptionsLoader {
@JvmStatic
private val mapper = tomlMapper {}
@JvmStatic
fun init(file: File, patches: PatchList) {
if (!file.exists()) file.createNewFile()
val map = mapper.decodeWithDefaults(generateDefaults(patches), TomlValue.from(file.toPath()))
readAndSet(map, patches)
save(map, file)
}
private fun readAndSet(map: OptionsMap, patches: PatchList) {
for ((patchName, options) in map) {
val patch = patches.find { it.patchName == patchName } ?: continue
val patchOptions = patch.options ?: continue
for ((key, value) in options) {
if (value == "null") { // backwards compatibility, subject to removal
options.remove(key)
continue
}
try {
patchOptions[key] = value
} catch (e: Exception) {
logger.error("Error while setting option $key for patch $patchName: ${e.message}")
e.printStackTrace()
}
}
}
}
private fun save(map: OptionsMap, file: File) {
val toml = mapper.encodeToString(map)
file.writeText(
"""
# A list of options for each patch.
# This file does not contain all options by default.
# Run the CLI with the "--list --with-options" flags to see all available options.
# You can also run the CLI with the aforementioned flags and a patch name to see all available options for that patch.
# To set an option, add a line with the format "option = value" or set the value if the option already exists.
# To reset an option to its default value, delete the line.
# To reset all options to their default values, delete this file.
#
# This file was generated by ReVanced Patcher version ${Patcher.version}.
""".trimIndent() + "\n\n$toml"
)
}
private fun generateDefaults(patches: PatchList) = buildMap {
for (patch in patches) {
val options = patch.options ?: continue
if (!options.iterator().hasNext()) continue
put(patch.patchName, buildMap {
for (option in options) {
put(option.key, option.value ?: continue)
}
} as MutableMap)
}
} as MutableMap
}

View File

@@ -1,113 +0,0 @@
package app.revanced.utils.adb
import app.revanced.cli.command.MainCommand.logger
import se.vidstige.jadb.JadbConnection
import se.vidstige.jadb.JadbDevice
import se.vidstige.jadb.managers.PackageManager
import java.io.File
import java.util.concurrent.Executors
internal class Adb(
private val file: File,
private val packageName: String,
deviceName: String,
private val modeInstall: Boolean = false,
private val logging: Boolean = true
) {
private val device: JadbDevice
init {
device = JadbConnection().devices.find { it.serial == deviceName }
?: throw IllegalArgumentException("No such device with name $deviceName")
if (!modeInstall && device.run("su -h", false) != 0)
throw IllegalArgumentException("Root required on $deviceName. Task failed")
}
private fun String.replacePlaceholder(with: String? = null): String {
return this.replace(Constants.PLACEHOLDER, with ?: packageName)
}
internal fun deploy() {
if (modeInstall) {
logger.info("Installing without mounting")
PackageManager(device).install(file)
} else {
logger.info("Installing by mounting")
// push patched file
device.copy(Constants.PATH_INIT_PUSH, file)
// create revanced folder path
device.run("${Constants.COMMAND_CREATE_DIR} ${Constants.PATH_REVANCED}")
// prepare mounting the apk
device.run(Constants.COMMAND_PREPARE_MOUNT_APK.replacePlaceholder())
// push mount script
device.createFile(
Constants.PATH_INIT_PUSH,
Constants.CONTENT_MOUNT_SCRIPT.replacePlaceholder()
)
// install mount script
device.run(Constants.COMMAND_INSTALL_MOUNT.replacePlaceholder())
// unmount the apk for sanity
device.run(Constants.COMMAND_UMOUNT.replacePlaceholder())
// mount the apk
device.run(Constants.PATH_MOUNT.replacePlaceholder())
// relaunch app
device.run(Constants.COMMAND_RESTART.replacePlaceholder())
// log the app
log()
}
}
internal fun uninstall() {
logger.info("Uninstalling by unmounting")
// unmount the apk
device.run(Constants.COMMAND_UMOUNT.replacePlaceholder())
// delete revanced app
device.run(Constants.COMMAND_DELETE.replacePlaceholder(Constants.PATH_REVANCED_APP).replacePlaceholder())
// delete mount script
device.run(Constants.COMMAND_DELETE.replacePlaceholder(Constants.PATH_MOUNT).replacePlaceholder())
logger.info("Finished uninstalling")
}
private fun log() {
val executor = Executors.newSingleThreadExecutor()
val pipe = if (logging) {
ProcessBuilder.Redirect.INHERIT
} else {
ProcessBuilder.Redirect.PIPE
}
val process = device.buildCommand(Constants.COMMAND_LOGCAT.replacePlaceholder())
.redirectOutput(pipe)
.redirectError(pipe)
.useExecutor(executor)
.start()
Thread.sleep(500) // give the app some time to start up.
while (true) {
try {
while (device.run("${Constants.COMMAND_PID_OF} $packageName") == 0) {
Thread.sleep(1000)
}
break
} catch (e: Exception) {
throw RuntimeException("An error occurred while monitoring the state of app", e)
}
}
logger.info("Stopped logging because the app was closed")
process.destroy()
executor.shutdown()
}
}

View File

@@ -0,0 +1,135 @@
package app.revanced.utils.adb
import app.revanced.cli.logging.CliLogger
import app.revanced.utils.adb.AdbManager.Apk
import app.revanced.utils.adb.Constants.COMMAND_CREATE_DIR
import app.revanced.utils.adb.Constants.COMMAND_DELETE
import app.revanced.utils.adb.Constants.COMMAND_INSTALL_MOUNT
import app.revanced.utils.adb.Constants.COMMAND_PREPARE_MOUNT_APK
import app.revanced.utils.adb.Constants.COMMAND_RESTART
import app.revanced.utils.adb.Constants.COMMAND_UMOUNT
import app.revanced.utils.adb.Constants.CONTENT_MOUNT_SCRIPT
import app.revanced.utils.adb.Constants.PATH_INIT_PUSH
import app.revanced.utils.adb.Constants.PATH_INSTALLATION
import app.revanced.utils.adb.Constants.PATH_MOUNT
import app.revanced.utils.adb.Constants.PATH_PATCHED_APK
import app.revanced.utils.adb.Constants.PLACEHOLDER
import se.vidstige.jadb.JadbConnection
import se.vidstige.jadb.managers.Package
import se.vidstige.jadb.managers.PackageManager
import java.io.Closeable
import java.io.File
/**
* Adb manager. Used to install and uninstall [Apk] files.
*
* @param deviceSerial The serial of the device.
*/
internal sealed class AdbManager(deviceSerial: String? = null, protected val logger: CliLogger? = null) : Closeable {
protected val device = JadbConnection().devices.find { device -> device.serial == deviceSerial }
?: throw DeviceNotFoundException(deviceSerial)
init {
logger?.trace("Established connection to $deviceSerial")
}
/**
* Installs the [Apk] file.
*
* @param apk The [Apk] file.
*/
open fun install(apk: Apk) {
logger?.info("Finished installing ${apk.file.name}")
}
/**
* Uninstalls the package.
*
* @param packageName The package name.
*/
open fun uninstall(packageName: String) {
logger?.info("Finished uninstalling $packageName")
}
/**
* Closes the [AdbManager] instance.
*/
override fun close() {
logger?.trace("Closed")
}
class RootAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) {
init {
if (!device.hasSu()) throw IllegalArgumentException("Root required on $deviceSerial. Task failed")
}
override fun install(apk: Apk) {
logger?.info("Installing by mounting")
val applyReplacement = getPlaceholderReplacement(
apk.packageName ?: throw IllegalArgumentException("Package name is required")
)
device.copyFile(apk.file, PATH_INIT_PUSH)
device.run("$COMMAND_CREATE_DIR $PATH_INSTALLATION")
device.run(COMMAND_PREPARE_MOUNT_APK.applyReplacement())
device.createFile(PATH_INIT_PUSH, CONTENT_MOUNT_SCRIPT.applyReplacement())
device.run(COMMAND_INSTALL_MOUNT.applyReplacement())
device.run(COMMAND_UMOUNT.applyReplacement()) // Sanity check.
device.run(PATH_MOUNT.applyReplacement())
device.run(COMMAND_RESTART.applyReplacement())
super.install(apk)
}
override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName by unmounting and deleting the package")
val applyReplacement = getPlaceholderReplacement(packageName)
device.run(COMMAND_UMOUNT.applyReplacement(packageName))
device.run(COMMAND_DELETE.applyReplacement(PATH_PATCHED_APK).applyReplacement())
device.run(COMMAND_DELETE.applyReplacement(PATH_MOUNT).applyReplacement())
super.uninstall(packageName)
}
companion object Utils {
private fun getPlaceholderReplacement(with: String): String.() -> String = { replace(PLACEHOLDER, with) }
private fun String.applyReplacement(with: String) = replace(PLACEHOLDER, with)
}
}
class UserAdbManager(deviceSerial: String, logger: CliLogger? = null) : AdbManager(deviceSerial, logger) {
private val packageManager = PackageManager(device)
override fun install(apk: Apk) {
PackageManager(device).install(apk.file)
super.install(apk)
}
override fun uninstall(packageName: String) {
logger?.info("Uninstalling $packageName")
packageManager.uninstall(Package(packageName))
super.uninstall(packageName)
}
}
/**
* Apk file for [AdbManager].
*
* @param file The [Apk] file.
*/
internal class Apk(val file: File, val packageName: String? = null)
internal class DeviceNotFoundException(deviceSerial: String?) :
Exception(deviceSerial?.let {
"The device with the ADB device serial \"$deviceSerial\" can not be found"
} ?: "No ADB device found")
}

View File

@@ -2,28 +2,28 @@ package app.revanced.utils.adb
import se.vidstige.jadb.JadbDevice
import se.vidstige.jadb.RemoteFile
import se.vidstige.jadb.ShellProcessBuilder
import java.io.File
import java.util.concurrent.Callable
import java.util.concurrent.Executors
internal fun JadbDevice.buildCommand(command: String, su: Boolean = true): ShellProcessBuilder {
if (su) {
return shellProcessBuilder("su -c \'$command\'")
// return the input or output stream, depending on which first returns a value
internal fun JadbDevice.run(command: String, su: Boolean = false) = with(this.startCommand(command, su)) {
Executors.newFixedThreadPool(2).let { service ->
arrayOf(inputStream, errorStream).map { stream ->
Callable { stream.bufferedReader().use { it.readLine() } }
}.let { tasks -> service.invokeAny(tasks).also { service.shutdown() } }
}
val args = command.split(" ") as ArrayList<String>
val cmd = args.removeFirst()
return shellProcessBuilder(cmd, *args.toTypedArray())
}
internal fun JadbDevice.run(command: String, su: Boolean = true): Int {
return this.buildCommand(command, su).start().waitFor()
}
internal fun JadbDevice.hasSu() =
this.startCommand("su -h", false).waitFor() == 0
internal fun JadbDevice.copy(targetPath: String, file: File) {
push(file, RemoteFile(targetPath))
}
internal fun JadbDevice.copyFile(file: File, targetFile: String) =
push(file, RemoteFile(targetFile))
internal fun JadbDevice.createFile(targetFile: String, content: String) {
internal fun JadbDevice.createFile(targetFile: String, content: String) =
push(content.byteInputStream(), System.currentTimeMillis(), 644, RemoteFile(targetFile))
}
private fun JadbDevice.startCommand(command: String, su: Boolean) =
shellProcessBuilder(if (su) "su -c '$command'" else command).start()

View File

@@ -1,57 +1,40 @@
package app.revanced.utils.adb
internal object Constants {
// template placeholder to replace a string in commands
internal const val PLACEHOLDER = "TEMPLATE_PACKAGE_NAME"
// utility commands
private const val COMMAND_CHMOD_MOUNT = "chmod +x"
internal const val COMMAND_PID_OF = "pidof -s"
internal const val COMMAND_CREATE_DIR = "mkdir -p"
internal const val COMMAND_LOGCAT = "logcat -c && logcat | grep AndroidRuntime"
internal const val COMMAND_RESTART = "pm resolve-activity --brief $PLACEHOLDER | tail -n 1 | xargs am start -n && kill ${'$'}($COMMAND_PID_OF $PLACEHOLDER)"
// default mount file name
private const val NAME_MOUNT_SCRIPT = "mount_revanced_$PLACEHOLDER.sh"
// initial directory to push files to via adb push
internal const val PATH_INIT_PUSH = "/data/local/tmp/revanced.delete"
internal const val PATH_INSTALLATION = "/data/adb/revanced/"
internal const val PATH_PATCHED_APK = "$PATH_INSTALLATION$PLACEHOLDER.apk"
internal const val PATH_MOUNT = "/data/adb/service.d/mount_revanced_$PLACEHOLDER.sh"
// revanced path
internal const val PATH_REVANCED = "/data/adb/revanced/"
// revanced apk path
internal const val PATH_REVANCED_APP = "$PATH_REVANCED$PLACEHOLDER.apk"
// delete command
internal const val COMMAND_DELETE = "rm -rf $PLACEHOLDER"
internal const val COMMAND_CREATE_DIR = "mkdir -p"
internal const val COMMAND_RESTART = "pm resolve-activity --brief $PLACEHOLDER | tail -n 1 | " +
"xargs am start -n && kill ${'$'}(pidof -s $PLACEHOLDER)"
// mount script path
internal const val PATH_MOUNT = "/data/adb/service.d/$NAME_MOUNT_SCRIPT"
internal const val COMMAND_PREPARE_MOUNT_APK = "base_path=\"$PATH_PATCHED_APK\" && " +
"mv $PATH_INIT_PUSH ${'$'}base_path && " +
"chmod 644 ${'$'}base_path && " +
"chown system:system ${'$'}base_path && " +
"chcon u:object_r:apk_data_file:s0 ${'$'}base_path"
// move to revanced apk path & set permissions
internal const val COMMAND_PREPARE_MOUNT_APK =
"base_path=\"$PATH_REVANCED_APP\" && mv $PATH_INIT_PUSH ${'$'}base_path && chmod 644 ${'$'}base_path && chown system:system ${'$'}base_path && chcon u:object_r:apk_data_file:s0 ${'$'}base_path"
// unmount command
internal const val COMMAND_UMOUNT =
"grep $PLACEHOLDER /proc/mounts | while read -r line; do echo ${'$'}line | cut -d \" \" -f 2 | sed 's/apk.*/apk/' | xargs -r umount -l; done"
// install mount script & set permissions
internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && $COMMAND_CHMOD_MOUNT $PATH_MOUNT"
internal const val COMMAND_INSTALL_MOUNT = "mv $PATH_INIT_PUSH $PATH_MOUNT && chmod +x $PATH_MOUNT"
// mount script
internal val CONTENT_MOUNT_SCRIPT =
internal const val CONTENT_MOUNT_SCRIPT =
"""
#!/system/bin/sh
MAGISKTMP="${'$'}(magisk --path)" || MAGISKTMP=/sbin
MIRROR="${'$'}MAGISKTMP/.magisk/mirror"
while [ "${'$'}(getprop sys.boot_completed | tr -d '\r')" != "1" ]; do sleep 1; done
base_path="$PATH_REVANCED_APP"
base_path="$PATH_PATCHED_APK"
stock_path=${'$'}( pm path $PLACEHOLDER | grep base | sed 's/package://g' )
chcon u:object_r:apk_data_file:s0 ${'$'}base_path
mount -o bind ${'$'}MIRROR${'$'}base_path ${'$'}stock_path
""".trimIndent()
"""
}

View File

@@ -1,6 +1,6 @@
package app.revanced.utils.signing.align
package app.revanced.utils.align
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import app.revanced.utils.align.zip.structures.ZipEntry
internal object ZipAligner {
private const val DEFAULT_ALIGNMENT = 4

View File

@@ -1,4 +1,4 @@
package app.revanced.utils.signing.align.zip
package app.revanced.utils.align.zip
import java.io.DataInput
import java.io.DataOutput

View File

@@ -1,7 +1,7 @@
package app.revanced.utils.signing.align.zip
package app.revanced.utils.align.zip
import app.revanced.utils.signing.align.zip.structures.ZipEndRecord
import app.revanced.utils.signing.align.zip.structures.ZipEntry
import app.revanced.utils.align.zip.structures.ZipEndRecord
import app.revanced.utils.align.zip.structures.ZipEntry
import java.io.Closeable
import java.io.File
import java.io.RandomAccessFile
@@ -11,15 +11,15 @@ import java.util.zip.CRC32
import java.util.zip.Deflater
class ZipFile(file: File) : Closeable {
var entries: MutableList<ZipEntry> = mutableListOf()
private var entries: MutableList<ZipEntry> = mutableListOf()
private val filePointer: RandomAccessFile = RandomAccessFile(file, "rw")
private var CDNeedsRewrite = false
private var centralDirectoryNeedsRewrite = false
private val compressionLevel = 5
init {
//if file isn't empty try to load entries
// If file isn't empty try to load entries.
if (file.length() > 0) {
val endRecord = findEndRecord()
@@ -29,17 +29,17 @@ class ZipFile(file: File) : Closeable {
entries = readEntries(endRecord).toMutableList()
}
//seek back to start for writing
// Seek back to start for writing.
filePointer.seek(0)
}
private fun findEndRecord(): ZipEndRecord {
//look from end to start since end record is at the end
// Look from end to start since end record is at the end.
for (i in filePointer.length() - 1 downTo 0) {
filePointer.seek(i)
//possible beginning of signature
// Possible beginning of signature.
if (filePointer.readByte() == 0x50.toByte()) {
//seek back to get the full int
// Seek back to get the full int.
filePointer.seek(i)
val possibleSignature = filePointer.readUIntLE()
if (possibleSignature == ZipEndRecord.ECD_SIGNATURE) {
@@ -76,7 +76,7 @@ class ZipFile(file: File) : Closeable {
}
private fun writeCD() {
val CDStart = filePointer.channel.position().toUInt()
val centralDirectoryStartOffset = filePointer.channel.position().toUInt()
entries.forEach {
filePointer.channel.write(it.toCDE())
@@ -89,8 +89,8 @@ class ZipFile(file: File) : Closeable {
0u,
entriesCount,
entriesCount,
filePointer.channel.position().toUInt() - CDStart,
CDStart,
filePointer.channel.position().toUInt() - centralDirectoryStartOffset,
centralDirectoryStartOffset,
""
)
@@ -98,7 +98,7 @@ class ZipFile(file: File) : Closeable {
}
private fun addEntry(entry: ZipEntry, data: ByteBuffer) {
CDNeedsRewrite = true
centralDirectoryNeedsRewrite = true
entry.localHeaderOffset = filePointer.channel.position().toUInt()
@@ -114,8 +114,7 @@ class ZipFile(file: File) : Closeable {
compressor.finish()
val uncompressedSize = data.size
val compressedData =
ByteArray(uncompressedSize) //i'm guessing compression won't make the data bigger
val compressedData = ByteArray(uncompressedSize) // I'm guessing compression won't make the data bigger.
val compressedDataLength = compressor.deflate(compressedData)
val compressedBuffer =
@@ -126,7 +125,7 @@ class ZipFile(file: File) : Closeable {
val crc = CRC32()
crc.update(data)
entry.compression = 8u //deflate compression
entry.compression = 8u // Deflate compression.
entry.uncompressedSize = uncompressedSize.toUInt()
entry.compressedSize = compressedDataLength.toUInt()
entry.crc32 = crc.value.toUInt()
@@ -136,14 +135,14 @@ class ZipFile(file: File) : Closeable {
private fun addEntryCopyData(entry: ZipEntry, data: ByteBuffer, alignment: Int? = null) {
alignment?.let {
//calculate where data would end up
// Calculate where data would end up.
val dataOffset = filePointer.filePointer + entry.LFHSize
val mod = dataOffset % alignment
//wrong alignment
// Wrong alignment.
if (mod != 0L) {
//add padding at end of extra field
// Add padding at end of extra field.
entry.localExtraField =
entry.localExtraField.copyOf((entry.localExtraField.size + (alignment - mod)).toInt())
}
@@ -152,7 +151,7 @@ class ZipFile(file: File) : Closeable {
addEntry(entry, data)
}
fun getDataForEntry(entry: ZipEntry): ByteBuffer {
private fun getDataForEntry(entry: ZipEntry): ByteBuffer {
return filePointer.channel.map(
FileChannel.MapMode.READ_ONLY,
entry.dataOffset.toLong(),
@@ -160,9 +159,15 @@ class ZipFile(file: File) : Closeable {
)
}
/**
* Copies all entries from [file] to this file but skip already existing entries.
*
* @param file The file to copy entries from.
* @param entryAlignment A function that returns the alignment for a given entry.
*/
fun copyEntriesFromFileAligned(file: ZipFile, entryAlignment: (entry: ZipEntry) -> Int?) {
for (entry in file.entries) {
if (entries.any { it.fileName == entry.fileName }) continue //don't add duplicates
if (entries.any { it.fileName == entry.fileName }) continue // Skip duplicates
val data = file.getDataForEntry(entry)
addEntryCopyData(entry, data, entryAlignment(entry))
@@ -170,7 +175,7 @@ class ZipFile(file: File) : Closeable {
}
override fun close() {
if (CDNeedsRewrite) writeCD()
if (centralDirectoryNeedsRewrite) writeCD()
filePointer.close()
}
}

View File

@@ -1,9 +1,9 @@
package app.revanced.utils.signing.align.zip.structures
package app.revanced.utils.align.zip.structures
import app.revanced.utils.signing.align.zip.putUInt
import app.revanced.utils.signing.align.zip.putUShort
import app.revanced.utils.signing.align.zip.readUIntLE
import app.revanced.utils.signing.align.zip.readUShortLE
import app.revanced.utils.align.zip.putUInt
import app.revanced.utils.align.zip.putUShort
import app.revanced.utils.align.zip.readUIntLE
import app.revanced.utils.align.zip.readUShortLE
import java.io.DataInput
import java.nio.ByteBuffer
import java.nio.ByteOrder

View File

@@ -1,6 +1,6 @@
package app.revanced.utils.signing.align.zip.structures
package app.revanced.utils.align.zip.structures
import app.revanced.utils.signing.align.zip.*
import app.revanced.utils.align.zip.*
import java.io.DataInput
import java.nio.ByteBuffer
import java.nio.ByteOrder

View File

@@ -1,64 +0,0 @@
package app.revanced.utils.filesystem
import java.io.Closeable
import java.io.File
import java.nio.file.FileSystems
import java.nio.file.Files
import java.nio.file.Path
import java.util.zip.ZipEntry
internal class ZipFileSystemUtils(
file: File
) : Closeable {
private var zipFileSystem = FileSystems.newFileSystem(file.toPath(), mapOf("noCompression" to true))
private fun Path.deleteRecursively() {
if (!Files.exists(this)) {
throw IllegalStateException("File exists in real folder but not in zip file system")
}
if (Files.isDirectory(this)) {
Files.list(this).forEach { path ->
path.deleteRecursively()
}
}
Files.delete(this)
}
internal fun getFile(path: String) = zipFileSystem.getPath(path)
internal fun writePathRecursively(path: Path) {
Files.list(path).use { fileStream ->
fileStream.forEach { filePath ->
val fileSystemPath = filePath.getRelativePath(path)
fileSystemPath.deleteRecursively()
}
}
Files.walk(path).use { fileStream ->
// don't include build directory
// by skipping the root node.
fileStream.skip(1).forEach { filePath ->
val relativePath = filePath.getRelativePath(path)
if (Files.isDirectory(filePath)) {
Files.createDirectory(relativePath)
return@forEach
}
Files.copy(filePath, relativePath)
}
}
}
internal fun write(path: String, content: ByteArray) = Files.write(zipFileSystem.getPath(path), content)
private fun Path.getRelativePath(path: Path): Path = zipFileSystem.getPath(path.relativize(this).toString())
// TODO: figure out why the file system is uncompressed by default and how to fix it
internal fun uncompress(vararg paths: String) =
paths.forEach { Files.setAttribute(zipFileSystem.getPath(it), "zip:method", ZipEntry.STORED) }
override fun close() = zipFileSystem.close()
}

View File

@@ -1,75 +0,0 @@
package app.revanced.utils.patcher
import app.revanced.cli.command.MainCommand
import app.revanced.cli.command.MainCommand.args
import app.revanced.cli.command.MainCommand.logger
import app.revanced.patcher.Patcher
import app.revanced.patcher.data.Context
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
fun Patcher.addPatchesFiltered(allPatches: List<Class<out Patch<Context>>>) {
val packageName = this.context.packageMetadata.packageName
val packageVersion = this.context.packageMetadata.packageVersion
val includedPatches = mutableListOf<Class<out Patch<Context>>>()
allPatches.forEach patchLoop@{ patch ->
val compatiblePackages = patch.compatiblePackages
val patchName = patch.patchName
val args = MainCommand.args.patchArgs?.patchingArgs!!
val prefix = "Skipping $patchName"
if (compatiblePackages == null) logger.trace("$patchName: No constraint on packages.")
else {
if (!compatiblePackages.any { it.name == packageName }) {
logger.trace("$prefix: Incompatible with $packageName. This patch is only compatible with ${
compatiblePackages.joinToString(
", "
) { it.name }
}")
return@patchLoop
}
if (!(args.experimental || compatiblePackages.any { it.versions.isEmpty() || it.versions.any { version -> version == packageVersion } })) {
val compatibleWith = compatiblePackages.joinToString(";") { _package ->
"${_package.name}: ${_package.versions.joinToString(", ")}"
}
logger.warn("$prefix: Incompatible with version $packageVersion. This patch is only compatible with version $compatibleWith")
return@patchLoop
}
}
if (args.excludedPatches.contains(patchName)) {
logger.info("$prefix: Manually excluded")
return@patchLoop
} else if ((!patch.include || args.exclusive) && !args.includedPatches.contains(patchName)) {
logger.info("$prefix: Excluded by default")
return@patchLoop
}
logger.trace("Adding $patchName")
includedPatches.add(patch)
}
this.addPatches(includedPatches)
}
fun Patcher.applyPatchesVerbose() {
this.executePatches().forEach { (patch, result) ->
if (result.isSuccess) {
logger.info("$patch succeeded")
return@forEach
}
logger.error("$patch failed:")
result.exceptionOrNull()!!.printStackTrace()
}
}
fun Patcher.mergeFiles() {
this.addFiles(args.patchArgs?.patchingArgs!!.mergeFiles) { file ->
logger.info("Merging $file")
}
}

View File

@@ -1,7 +1,6 @@
package app.revanced.utils.signing
import app.revanced.cli.command.MainCommand.logger
import app.revanced.cli.signing.SigningOptions
import app.revanced.cli.command.logger
import com.android.apksig.ApkSigner
import org.bouncycastle.asn1.x500.X500Name
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
@@ -18,10 +17,40 @@ import java.security.*
import java.security.cert.X509Certificate
import java.util.*
internal class Signer(
internal class ApkSigner(
private val signingOptions: SigningOptions
) {
private val signer: ApkSigner.Builder
private val passwordCharArray = signingOptions.password.toCharArray()
init {
Security.addProvider(BouncyCastleProvider())
val keyStore = KeyStore.getInstance("BKS", "BC")
val alias = keyStore.let { store ->
FileInputStream(File(signingOptions.keyStoreFilePath).also {
if (!it.exists()) {
logger.info("Creating keystore at ${it.absolutePath}")
newKeystore(it)
} else {
logger.info("Using keystore at ${it.absolutePath}")
}
}).use { fis -> store.load(fis, null) }
store.aliases().nextElement()
}
with(
ApkSigner.SignerConfig.Builder(
signingOptions.cn,
keyStore.getKey(alias, passwordCharArray) as PrivateKey,
listOf(keyStore.getCertificate(alias) as X509Certificate)
).build()
) {
this@ApkSigner.signer = ApkSigner.Builder(listOf(this))
signer.setCreatedBy(signingOptions.cn)
}
}
private fun newKeystore(out: File) {
val (publicKey, privateKey) = createKey()
val privateKS = KeyStore.getInstance("BKS", "BC")
@@ -50,30 +79,12 @@ internal class Signer(
return JcaX509CertificateConverter().getCertificate(builder.build(signer)) to pair.private
}
fun signApk(input: File, output: File) {
Security.addProvider(BouncyCastleProvider())
// TODO: keystore should be saved securely
val ks = File(signingOptions.keyStoreFilePath)
if (!ks.exists()) newKeystore(ks) else {
logger.info("Found existing keystore: ${ks.name}")
}
val keyStore = KeyStore.getInstance("BKS", "BC")
FileInputStream(ks).use { fis -> keyStore.load(fis, null) }
val alias = keyStore.aliases().nextElement()
val config = ApkSigner.SignerConfig.Builder(
signingOptions.cn,
keyStore.getKey(alias, passwordCharArray) as PrivateKey,
listOf(keyStore.getCertificate(alias) as X509Certificate)
).build()
val signer = ApkSigner.Builder(listOf(config))
signer.setCreatedBy(signingOptions.cn)
fun signApk(input: File, output: File): File {
signer.setInputApk(input)
signer.setOutputApk(output)
signer.build().sign()
return output
}
}

View File

@@ -1,4 +1,4 @@
package app.revanced.cli.signing
package app.revanced.utils.signing
data class SigningOptions(
val cn: String,

View File

@@ -0,0 +1 @@
version=${projectVersion}

View File

@@ -0,0 +1,60 @@
package app.revanced.patcher.options
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.Context
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.OptionsContainer
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchOption
import app.revanced.utils.Options
import app.revanced.utils.Options.setOptions
import org.junit.jupiter.api.MethodOrderer
import org.junit.jupiter.api.Order
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestMethodOrder
class PatchOptionsTestPatch : BytecodePatch() {
override fun execute(context: BytecodeContext) {
// Do nothing
}
companion object : OptionsContainer() {
var key1 by option(
PatchOption.StringOption(
"key1", null, "title1", "description1"
)
)
var key2 by option(
PatchOption.BooleanOption(
"key2", true, "title2", "description2"
)
)
}
}
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
internal object PatchOptionOptionsTest {
private var patches = listOf(PatchOptionsTestPatch::class.java as Class<out Patch<Context<*>>>)
@Test
@Order(1)
fun serializeTest() {
assert(SERIALIZED_JSON == Options.serialize(patches))
}
@Test
@Order(2)
fun loadOptionsTest() {
patches.setOptions(CHANGED_JSON)
assert(PatchOptionsTestPatch.key1 == "test")
assert(PatchOptionsTestPatch.key2 == false)
}
private const val SERIALIZED_JSON =
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":null},{\"key\":\"key2\",\"value\":true}]}]"
private const val CHANGED_JSON =
"[{\"patchName\":\"PatchOptionsTestPatch\",\"options\":[{\"key\":\"key1\",\"value\":\"test\"},{\"key\":\"key2\",\"value\":false}]}]"
}