├── Makefile ├── setup ├── android-sdk-minimal.txt ├── create_user.sh ├── make.sh ├── ccache.sh ├── acpi_call.sh ├── crowdin-cli.sh ├── git.sh ├── install_android_sdk.sh ├── clear.sh ├── solus.sh ├── arch-manjaro.sh ├── fedora.sh ├── hub.sh ├── opensuse.sh └── android_build_env.sh ├── gitlab ├── list-repos.sh ├── make-project-public.sh └── list-repos.py ├── rr ├── copy_ftp.sh ├── crowdin.sh ├── push_json.sh ├── channel.sh └── build.sh ├── personal-setup ├── hub-zsh-autocomplete ├── arch-setup.sh └── deb-setup.sh ├── .github └── workflows │ └── shellcheck.yml ├── aosip ├── crowdin.sh ├── release.sh ├── crowdin-merge.sh ├── push.sh ├── create-project.sh ├── build-gsi.sh ├── merge.sh ├── rebase.sh ├── sign.sh └── build.sh ├── github ├── push-all-repos-git.sh ├── create-project.sh ├── change-default-branch.sh ├── delete.py ├── change-default-branch.py └── org-size.py ├── gerrit ├── push-all-repos.sh ├── review.py ├── change-merge-type.sh ├── create-projects.sh └── parsepicks.py ├── misc ├── masspush.sh ├── ssh-copy-id-github.sh └── extract_and_push.sh ├── aliases ├── random-html └── generate-index.sh ├── files ├── random-py ├── sort_apn.py ├── apn-copy-tag.py └── apn-copy-entries.py ├── README.mkdn ├── zsh └── setup.sh ├── release-kernel ├── functions └── LICENSE /Makefile: -------------------------------------------------------------------------------- 1 | check: 2 | while read -r script; do shellcheck --exclude=SC1090,SC1091 $$script; done < files 3 | 4 | .PHONY: check 5 | -------------------------------------------------------------------------------- /setup/android-sdk-minimal.txt: -------------------------------------------------------------------------------- 1 | build-tools;31.0.0 2 | build-tools;32.0.0 3 | cmake;3.18.1 4 | ndk;23.1.7779620 5 | platform-tools 6 | tools 7 | platforms;android-31 8 | platforms;android-32 9 | -------------------------------------------------------------------------------- /gitlab/list-repos.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PROJECT_ID=6775874 4 | 5 | curl "https://gitlab.com/api/v4/groups/${PROJECT_ID}/projects" -H "Authorization: Bearer ${GITLAB_TOKEN}" -G -d per_page=100 6 | -------------------------------------------------------------------------------- /rr/copy_ftp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | [[ -f ${FILENAME:?} ]] || exit 3 | mkdir -pv ../downloads.resurrectionremix.com/"${DEVICE:?}"/ 4 | cp -v "${FILENAME}" ../downloads.resurrectionremix.com/"${DEVICE}"/ 5 | rm -v "${FILENAME}" 6 | -------------------------------------------------------------------------------- /personal-setup/hub-zsh-autocomplete: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | mkdir -pv ~/.zsh/completions 3 | curl -L https://github.com/github/hub/raw/master/etc/hub.zsh_completion -o ~/.zsh/completions/_hub 4 | echo 'fpath=$(~/.zsh/completions $fpath) 5 | autoload compinit 6 | compinit' >> ~/.zshrc 7 | -------------------------------------------------------------------------------- /gitlab/make-project-public.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # visibility can be one of 'public', 'private', or 'internal' 4 | 5 | PROJECT="exconfidential%2fsprd%2fbuild" 6 | 7 | curl -X PUT "https://gitlab.com/api/v4/projects/${PROJECT}" -H "Authorization: Bearer ${GITLAB_TOKEN}" -d "{ 'visibility': 'public' }" 8 | -------------------------------------------------------------------------------- /setup/create_user.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to add a new username to a Linux System 4 | 5 | export username="${1}" 6 | if [ -z "${username}" ]; then 7 | echo -e "Please enter a username" 8 | read -r username 9 | fi 10 | sudo useradd "${username}" -m -s /bin/bash 11 | passwd "${username}" 12 | chage -d 0 "${username}" 13 | -------------------------------------------------------------------------------- /setup/make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd /tmp || exit 1 4 | axel -a -n 10 https://ftp.gnu.org/gnu/make/make-"${1:?}".tar.gz 5 | tar xvzf /tmp/make-"${1:?}".tar.gz 6 | cd /tmp/make-"${1:?}" || exit 1 7 | ./configure 8 | bash ./build.sh 9 | sudo install ./make /usr/local/bin/make 10 | cd - || exit 1 11 | rm -rf /tmp/make-"${1:?}"{,.tar.gz} 12 | -------------------------------------------------------------------------------- /setup/ccache.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cd /tmp || exit 1 4 | git clone https://github.com/ccache/ccache.git 5 | cd ccache || exit 1 6 | mkdir -p build && cd build || exit 1 7 | cmake -DHIREDIS_FROM_INTERNET=ON -DZSTD_FROM_INTERNET=ON -DCMAKE_BUILD_TYPE=Release .. 8 | make -j"$(nproc)" 9 | sudo make install 10 | rm -rf "${PWD}" 11 | cd - || exit 1 12 | -------------------------------------------------------------------------------- /.github/workflows/shellcheck.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: ShellCheck scripts 3 | jobs: 4 | shellCheck: 5 | name: ShellCheck 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Run shellcheck. 10 | run: | 11 | while read -r script; do shellcheck --exclude=SC1090,SC1091 $script; done < files 12 | -------------------------------------------------------------------------------- /setup/acpi_call.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | lsmod | rg -q acpi_call && { 5 | echo "acpi_call already installed"; 6 | exit 0; 7 | } 8 | 9 | git clone https://github.com/nix-community/acpi_call /tmp/acpi_call 10 | make -C /tmp/acpi_call 11 | sudo make -C /tmp/acpi_call install 12 | sudo depmod -a 13 | sudo modprobe acpi_call 14 | rm -rf /tmp/acpi_call/ 15 | -------------------------------------------------------------------------------- /aosip/crowdin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | source ~/.rvm/scripts/rvm 3 | repo init -u git://github.com/AOSiP/platform_manifest.git -b pie -m crowdin.xml --no-tags --current-branch 4 | time repo sync -j"$(nproc)" --force-sync --force-broken --no-tags --current-branch 5 | repo forall -j"$(nproc)" -c "scp -p -P 29418 review.aosip.dev:hooks/commit-msg .git/hooks/" 6 | ./crowdin/sync.py "${@}" 7 | -------------------------------------------------------------------------------- /setup/crowdin-cli.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to setup environment for crowdin 4 | # shellcheck disable=SC1010 5 | 6 | # Install crowdin-cli 7 | wget https://artifacts.crowdin.com/repo/deb/crowdin3.deb -O crowdin.deb 8 | sudo dpkg -i crowdin.deb 9 | echo "crowdin-cli installed" 10 | echo "" 11 | 12 | # Test crowdin-cli 13 | echo "Your crowdin version:" 14 | crowdin --version -------------------------------------------------------------------------------- /personal-setup/arch-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | git config --global user.name "Akhil Narang" 4 | git config --global user.email "akhilnarang.1999@gmail.com" 5 | git config --global credential.helper "cache --timeout=7200" 6 | printf '\n' | tee -a ~/.bashrc 7 | echo "source ~/scripts/functions" >> ~/.bashrc 8 | echo "onLogin" >> ~/.bashrc 9 | yaourt -S figlet fortune-mod hub byobu --noconfirm 10 | -------------------------------------------------------------------------------- /setup/git.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | LATEST_TAG=$(curl https://api.github.com/repos/git/git/tags | jq -r '.[0].name') 4 | 5 | git clone https://github.com/git/git -b "$LATEST_TAG" 6 | 7 | cd git || exit 8 | 9 | make configure 10 | 11 | ./configure --prefix=/usr/local --with-curl 12 | 13 | sudo make install -j"$(nproc)" 14 | 15 | git --version 16 | 17 | cd - || exit 18 | 19 | rm -rf git 20 | -------------------------------------------------------------------------------- /personal-setup/deb-setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | source ~/scripts/setup/hub.sh 4 | git config --global user.name "Akhil Narang" 5 | git config --global user.email "akhilnarang.1999@gmail.com" 6 | git config --global credential.helper "cache --timeout=7200" 7 | printf '\n' | tee -a ~/.bashrc 8 | echo "source ~/scripts/functions" >> ~/.bashrc 9 | echo "onLogin" >> ~/.bashrc 10 | sudo apt install figlet fortune byobu mosh -y 11 | -------------------------------------------------------------------------------- /rr/crowdin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to init RR's crowdin manifest and update translations 4 | 5 | mkdir crowdin 6 | cd crowdin || exit 7 | repo init -u ssh://git@github.com/ResurrectionRemix/platform_manifest.git -b nougat -m crowdin.xml 8 | source "${HOME}"/android_shell_tools/android_bash.rc 9 | source "${HOME}"/.rvm/scripts/rvm 10 | bashsync 11 | time reposy -j8 12 | # export RR_CROWDIN_API_KEY= 13 | ./rr_crowdin/crowdin_sync.py -b nougat 14 | -------------------------------------------------------------------------------- /aosip/release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck disable=SC2086 4 | # SC2086: Double quote to prevent globbing and word splitting. 5 | 6 | DEVICE=$1 7 | BUILD_NUMBER=$2 8 | AOSIP_BUILDTYPE=$3 9 | 10 | pushd /tmp/"$BUILD_NUMBER" || exit 11 | 12 | if [[ -d "/home/kronic/builds/$DEVICE" ]]; then 13 | rm -fv /home/kronic/builds/"$DEVICE"/*"$AOSIP_BUILDTYPE"* 14 | else 15 | mkdir -pv "/home/kronic/builds/$DEVICE" 16 | fi 17 | cp -v /tmp/"$BUILD_NUMBER"/AOSiP* /home/kronic/builds/"$DEVICE"/ 18 | rm -rfv /tmp/"$BUILD_NUMBER" 19 | 20 | popd || exit 21 | -------------------------------------------------------------------------------- /github/push-all-repos-git.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # A github script to push all repositories from a manifest 4 | 5 | # This again, will have to be adapted based on your setup. 6 | 7 | cwd=$PWD 8 | PROJECTS="$(grep 'aosip' .repo/manifests/aosip.xml | awk '{print $2}' | awk -F'"' '{print $2}' | uniq | grep -v caf)" 9 | for project in ${PROJECTS}; do 10 | cd "$project" || exit 11 | git push git@github.com:AOSIP/"$(git remote -v | head -n1 | awk '{print $2}' | sed 's/.*\///' | sed 's/\.git//')".git HEAD:refs/heads/nougat-mr2 12 | cd - || exit 13 | done 14 | cd "$cwd" || exit 15 | -------------------------------------------------------------------------------- /aosip/crowdin-merge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to merge translations on Gerrit 4 | # We assume sanely that's there only 1 patchset per commit 5 | # And that they're all under topic:translations 6 | 7 | GERRIT_HOST="review.aosip.dev" 8 | QUERY="topic:translations status:open" 9 | PORT="29418" 10 | # shellcheck disable=SC2029 11 | COMMITS=$(ssh -p${PORT} ${GERRIT_HOST} gerrit query "${QUERY}" | grep number | 12 | cut -d: -f2) 13 | for COMMIT in ${COMMITS}; do 14 | ssh -p29418 ${GERRIT_HOST} gerrit review "${COMMIT}",1 --code-review=+2 \ 15 | --verified=+1 --submit 16 | done 17 | -------------------------------------------------------------------------------- /gerrit/push-all-repos.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # A gerrit script to push all repositories from a manifest 4 | 5 | # This again, will have to be adapted based on your setup. 6 | 7 | cwd=$PWD 8 | cd ~/nougat || exit 9 | PROJECTS="$(grep 'aosip' .repo/manifests/snippets/aosip.xml | awk '{print $2}' | awk -F'"' '{print $2}' | uniq | grep -v caf)" 10 | for project in ${PROJECTS}; do 11 | cd "$project" || exit 12 | git push "$(git remote -v | head -1 | awk '{print $2}' | sed -e 's/https:\/\/github.com\/AOSiP/ssh:\/\/localhost:29418\/AOSIP/')" HEAD:refs/heads/nougat-mr2 13 | cd - || exit 14 | done 15 | cd "$cwd" || exit 16 | -------------------------------------------------------------------------------- /github/create-project.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # List of repositories. Add them manually, or adjust the following command 4 | REPOS=$(curl -s -L https://github.com/AOSiP/platform_manifest/raw/oreo-mr1/snippets/aosip.xml | grep " "${ZIP}".md5sum 9 | changelog=${ZIP/.zip/-changelog.txt} 10 | sudo mkdir -pv /home/maintainers/downloads.resurrectionremix.com/"${DEVICE}" 11 | cp -v "${ZIP}" /home/maintainers/downloads.resurrectionremix.com/"${DEVICE}"/ 12 | cp -v "${ZIP}".md5sum /home/maintainers/downloads.resurrectionremix.com/"${DEVICE}"/ 13 | cp -v "${changelog}" /home/maintainers/downloads.resurrectionremix.com/"${DEVICE}"/ 14 | git -C ~/api push git@github.com:ResurrectionRemix-Devices/api 15 | -------------------------------------------------------------------------------- /github/change-default-branch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # The branch you want to change to 4 | BRANCH="pie" 5 | 6 | # The organizations whose repositories you want to change default branch of 7 | ORG="AOSiP" 8 | 9 | # The name of your manifest repository 10 | MANIFEST="platform_manifest" 11 | 12 | # List of repositories. Add them manually, or adjust the following command 13 | REPOS=$(curl -s -L https://github.com/${ORG}/${MANIFEST}/raw/${BRANCH}/snippets/aosip.xml | grep " 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | 6 | trap 'rm -rf /tmp/tools.zip 2>/dev/null' INT TERM EXIT 7 | 8 | CUR_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)" 9 | CUR_DIR="${CUR_DIR/setup/}" 10 | SDK_TOOLS=commandlinetools-linux-7583922_latest.zip 11 | 12 | function setup_android_sdk() { 13 | echo "Installing Android SDK" 14 | SDK_DIR="${HOME:?}/Android/Sdk" 15 | mkdir -p "${SDK_DIR}" 16 | if [ ! -f "${SDK_TOOLS}" ]; then 17 | wget https://dl.google.com/android/repository/"${SDK_TOOLS}" -O /tmp/tools.zip 18 | fi 19 | unzip -qo /tmp/tools.zip -d "${SDK_DIR}" 20 | while read -r package; do 21 | yes | "${SDK_DIR}"/cmdline-tools/bin/sdkmanager --sdk_root="${SDK_DIR}" "${package:?}" 22 | done < "${CUR_DIR}"/setup/android-sdk-minimal.txt 23 | rm /tmp/tools.zip 24 | cd - || exit 25 | } 26 | 27 | setup_android_sdk 28 | -------------------------------------------------------------------------------- /random-html/generate-index.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Random script that outputs an index.html with a table containing the files in the current dir 4 | 5 | file="index.html" 6 | [[ -f ${file} ]] && echo "${file} already exists, please rename/remove" && exit 1 7 | touch ${file} 8 | echo " 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | " >> ${file} 20 | count=1 21 | for f in ./*; do 22 | if [ -f "${f}" ]; then 23 | filename=${f} 24 | filesize=$(du -sh "${f}" | awk '{print $1}') 25 | filemd5=$(md5sum "${f}" | cut -d ' ' -f 1) 26 | echo " 27 | 28 | 29 | 31 | 32 | 33 | " >> ${file} 34 | count=$(("$count" + 1)) 35 | fi 36 | done 37 | echo " 38 | 39 |
Sr. No.Name [Click To Download]md5sumSize
${count}${filename} 30 | ${filemd5}${filesize}
40 | " >> ${file} 41 | echo "Done :)" 42 | -------------------------------------------------------------------------------- /github/org-size.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from humanize import naturalsize 4 | from requests import get 5 | from os import getenv 6 | 7 | GITHUB_OAUTH_TOKEN = getenv("GITHUB_OAUTH_TOKEN") 8 | 9 | if GITHUB_OAUTH_TOKEN is None: 10 | GITHUB_OAUTH_TOKEN = input( 11 | "Enter your Github API token or try without one, which may result in you getting rate-limited soon: " 12 | ) 13 | 14 | headers = {"Authorization": "token " + GITHUB_OAUTH_TOKEN} 15 | 16 | org = input("Enter organization name: ") 17 | 18 | org_size = [] 19 | repo_count = 0 20 | response = get(f"https://api.github.com/orgs/{org}/repos", headers=headers) 21 | while True: 22 | for repo in response.json(): 23 | org_size.append(int(repo["size"])) 24 | repo_count += 1 25 | try: 26 | response = get(response.links["next"]["url"], headers=headers) 27 | except KeyError: 28 | break 29 | 30 | total = sum(org_size * 1024) 31 | print(f'{org} has {repo_count} repositories which sum up to {naturalsize(total)}') 32 | -------------------------------------------------------------------------------- /files: -------------------------------------------------------------------------------- 1 | aliases 2 | aosip/build-gsi.sh 3 | aosip/build.sh 4 | aosip/create-project.sh 5 | aosip/crowdin-merge.sh 6 | aosip/crowdin.sh 7 | aosip/merge.sh 8 | aosip/push.sh 9 | aosip/rebase.sh 10 | aosip/release.sh 11 | aosip/sign.sh 12 | build-kernel 13 | functions 14 | gerrit/change-merge-type.sh 15 | gerrit/create-projects.sh 16 | gerrit/push-all-repos.sh 17 | github/change-default-branch.sh 18 | github/create-project.sh 19 | gitlab/list-repos.sh 20 | gitlab/make-project-public.sh 21 | misc/extract_and_push.sh 22 | misc/ssh-copy-id-github.sh 23 | personal-setup/arch-setup.sh 24 | personal-setup/deb-setup.sh 25 | random-html/generate-index.sh 26 | release-kernel 27 | rr/build.sh 28 | rr/channel.sh 29 | rr/crowdin.sh 30 | rr/copy_ftp.sh 31 | rr/push_json.sh 32 | setup/acpi_call.sh 33 | setup/android_build_env.sh 34 | setup/arch-manjaro.sh 35 | setup/ccache.sh 36 | setup/create_user.sh 37 | setup/crowdin-cli.sh 38 | setup/fedora.sh 39 | setup/git.sh 40 | setup/hub.sh 41 | setup/install_android_sdk.sh 42 | setup/make.sh 43 | setup/solus.sh 44 | zsh/setup.sh 45 | -------------------------------------------------------------------------------- /aosip/create-project.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | # Clone the repository 6 | git clone "${REPO_LINK}" -b "${REPO_BRANCH}" --verbose --progress "${REPO_NAME}" 7 | 8 | # Change directory 9 | cd "${REPO_NAME}" 10 | 11 | # Checkout to the desired branch 12 | git checkout "${REPO_BRANCH}" 13 | 14 | # Create the repository on Gerrit if it doesn't already exist 15 | if ! ssh -p29418 review.aosip.dev gerrit ls-projects | grep -q "${REPO_NAME}"; then 16 | ssh -p29418 review.aosip.dev gerrit create-project "${ORG}/${REPO_NAME}" -p "${PARENT-All-Projects}" 17 | fi 18 | 19 | # Create the repository on GitHub if it doesn't already exist 20 | if ! curl --silent --header --fail --output /dev/null "Authorization: ${GITHUB_OAUTH_TOKEN:?}" https://api.github.com/repos/"$ORG"/"$REPO_NAME"; then 21 | curl --silent -H "Authorization: GITHUB_OAUTH_TOKEN" -d '{ "name": "'"${REPO_NAME}"'" }' "https://api.github.com/orgs/${ORG}/repos" 22 | fi 23 | 24 | git push ssh://review.aosip.dev:29418/"${ORG}"/"${REPO_NAME}" HEAD:refs/heads/"${BRANCH}" --verbose --progress --force 25 | -------------------------------------------------------------------------------- /random-py/sort_apn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from pathlib import Path 5 | from xml.etree import ElementTree 6 | 7 | # ./sort_apn.py apns-conf.xml 8 | # If no arguments are provided, the user will be prompted to enter the file paths 9 | 10 | if len(sys.argv) < 2: 11 | apns = input("Enter the apns-conf XML path: ") 12 | else: 13 | apns = sys.argv[1] 14 | 15 | apns_path = Path(apns) 16 | 17 | if not apns_path.exists(): 18 | print("Please ensure that the files exist") 19 | sys.exit(1) 20 | 21 | def sort_apns(apns_path): 22 | # Parse the XML file into an ElementTree 23 | tree = ElementTree.parse(apns_path) 24 | root = tree.getroot() 25 | 26 | # Sort the children of the root by 'mcc' and 'mnc' 27 | root[:] = sorted(root, key=lambda child: (child.attrib.get('mcc', ''), child.attrib.get('mnc', ''))) 28 | 29 | # Write the sorted ElementTree back into the XML file 30 | with open(apns_path, 'wb') as f: 31 | f.write(ElementTree.tostring(root, encoding='utf-8')) 32 | 33 | # Call the function with the XML file path 34 | sort_apns(apns_path) 35 | -------------------------------------------------------------------------------- /setup/clear.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2020 Alexander Koskovich 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | 6 | # Master is the only supported branch for now due to the forced removal 7 | # of Python 2 from the repository, this will change once Android 11 releases. 8 | 9 | # Build dependencies. 10 | sudo swupd bundle-add AOSP-dev git 11 | 12 | # UDEV 13 | echo "Setting up ADB UDEV rules..." 14 | sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L https://raw.githubusercontent.com/M0Rf30/android-udev-rules/master/51-android.rules 15 | sudo chmod 644 /etc/udev/rules.d/51-android.rules 16 | sudo chown root /etc/udev/rules.d/51-android.rules 17 | sudo udevadm control --reload-rules 18 | 19 | # REPO 20 | echo "Setting up Repo..." 21 | sudo curl --create-dirs -L -o /usr/local/bin/repo -O -L https://storage.googleapis.com/git-repo-downloads/repo 22 | sudo chmod a+rx /usr/local/bin/repo 23 | 24 | echo "You're now ready to start contributing to AOSP!" 25 | 26 | echo "Please note, Clear Linux does not have ADB in their repos" 27 | echo "so you will need to download yourself and append to PATH." 28 | -------------------------------------------------------------------------------- /gerrit/change-merge-type.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # A gerrit script to change the merge type of all repositories 4 | 5 | # Just change these 4 variables 6 | 7 | # If you're pushing from the server where Gerrit is hosted, let it be as it is 8 | # Else point to the Gerrit server, the IP, or probably review/gerrit.domain.tld 9 | # If your gerrit username is not the user you're running this script as, then prefix this with gerritusername@ 10 | GERRIT_HOST="localhost" 11 | 12 | # The port on which Gerrit is running [the port you filled in the the sshd listen address while setting up] 13 | GERRIT_PORT="29418" 14 | 15 | GERRIT_PROJECT_NAMES="$(ssh -p${GERRIT_PORT} ${GERRIT_HOST} gerrit ls-projects)" 16 | 17 | # Must be one of FAST_FORWARD_ONLY|MERGE_IF_NECESSARY|REBASE_IF_NECESSARY|MERGE_ALWAYS|CHERRY_PICK 18 | # Check your gerritsite/Documentation/project-configuration.html#submit_type to decide which 19 | SUBMIT_TYPE="REBASE_IF_NECESSARY" 20 | 21 | # Do it! 22 | for PROJECT_NAME in ${GERRIT_PROJECT_NAMES}; do 23 | echo "Changing ${PROJECT_NAME} submit type to ${SUBMIT_TYPE}" 24 | ssh -p${GERRIT_PORT} ${GERRIT_HOST} gerrit set-project "${PROJECT_NAME}" -t ${SUBMIT_TYPE} 25 | done 26 | -------------------------------------------------------------------------------- /setup/solus.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2019 ZVNexus 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | 6 | # Script to setup an AOSP build environment on Solus 7 | 8 | sudo eopkg it -c system.devel 9 | sudo eopkg it openjdk-8-devel curl-devel git gnupg gperf libgcc-32bit libxslt-devel lzop ncurses-32bit-devel ncurses-devel readline-32bit-devel rsync schedtool sdl1-devel squashfs-tools unzip wxwidgets-devel zip zlib-32bit-devel lzip 10 | 11 | # ADB/Fastboot 12 | sudo eopkg bi --ignore-safety https://raw.githubusercontent.com/solus-project/3rd-party/master/programming/tools/android-tools/pspec.xml 13 | sudo eopkg it android-tools*.eopkg 14 | sudo rm android-tools*.eopkg 15 | 16 | # udev rules 17 | echo "Setting up udev rules for adb!" 18 | sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L https://raw.githubusercontent.com/M0Rf30/android-udev-rules/master/51-android.rules 19 | sudo chmod 644 /etc/udev/rules.d/51-android.rules 20 | sudo chown root /etc/udev/rules.d/51-android.rules 21 | sudo usysconf run -f 22 | 23 | echo "Installing repo" 24 | sudo curl --create-dirs -L -o /usr/local/bin/repo -O -L https://storage.googleapis.com/git-repo-downloads/repo 25 | sudo chmod a+x /usr/local/bin/repo 26 | 27 | echo "You are now ready to build Android!" 28 | -------------------------------------------------------------------------------- /README.mkdn: -------------------------------------------------------------------------------- 1 | 2 | ## To setup build environment 3 | 4 | Firstly, install [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) , using the package manager in your distro. 5 | 6 | Then, run these commands 7 | 8 | ```bash 9 | $ git clone https://github.com/akhilnarang/scripts 10 | $ cd scripts 11 | $ bash setup/ 12 | ``` 13 | 14 | `android_build_env.sh` is for Ubuntu/Linux Mint/other distributions using the `apt` package manager. 15 | The rest are named as per the distro. 16 | 17 | Please run the correct script depending on the distro you have installed! 18 | 19 | Enjoy! 20 | 21 | ### Brief explanation of stuff in here 22 | 23 | aosip-> some scripts I use for AOSiP. 24 | 25 | gerrit -> useful for setting up gerrit and stuff. 26 | 27 | github -> some actions on github. 28 | 29 | gitlab -> some actions on gitlab. 30 | 31 | misc -> stuff. 32 | 33 | personal-setup -> scripts to setup git credentials and functions after fresh installation. 34 | 35 | push -> scripts to push multiple repos at once if you don't wanna do it manually. 36 | 37 | random-html -> generates an index.html with a table with the list of files in current directory. 38 | 39 | rr -> some scripts for ResurrectionRemix. 40 | 41 | setup -> setup Android Build Environment / Android SDK. 42 | -------------------------------------------------------------------------------- /gerrit/create-projects.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # A gerrit script to create projects based on ROMs manifest 4 | 5 | # Just change these 4 variables 6 | 7 | # If you're pushing from the server where Gerrit is hosted, let it be as it is 8 | # Else point to the Gerrit server, the IP, or probably review/gerrit.domain.tld 9 | # If your gerrit username is not the user you're running this script as, then prefix this with gerritusername@ 10 | GERRIT_HOST="localhost" 11 | 12 | # The port on which Gerrit is running [the port you filled in the the sshd listen address while setting up] 13 | GERRIT_PORT="29418" 14 | 15 | # Incase your repo name and names in manifest are different 16 | 17 | GERRIT_PROJECT_PREFIX="AOSIP/" 18 | 19 | # Might need slight modifications 20 | # For AOSiP the format is . 21 | # Depending on yours the path and the awks will have to be ajusted. 22 | GERRIT_PROJECT_NAMES="$(grep 'aosip' ~/nougat-mr2/.repo/manifests/snippets/aosip.xml | awk '{print $3}' | awk -F'"' '{print $2}' | uniq)" 23 | 24 | # Push everything! 25 | for PROJECT_NAME in ${GERRIT_PROJECT_NAMES}; do 26 | echo "Creating ${GERRIT_PROJECT_PREFIX}${PROJECT_NAME}" 27 | ssh -p${GERRIT_PORT} ${GERRIT_HOST} gerrit create-project ${GERRIT_PROJECT_PREFIX}"${PROJECT_NAME}" 28 | done 29 | -------------------------------------------------------------------------------- /zsh/setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check whether zsh is installed or not 4 | command -v zsh > /dev/null || { 5 | echo "Please install zsh yourself before running this script!" 6 | exit 1 7 | } 8 | 9 | # Install oh-my-zsh in unattended mode - no prompts to change shell, or open a zsh prompt after it completes 10 | echo "Installing oh-my-zsh" 11 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended 12 | 13 | # Clone in powerlevel10k 14 | git clone https://github.com/romkatv/powerlevel10k.git "$HOME"/.oh-my-zsh/custom/themes/powerlevel10k 15 | 16 | # Change oh-my-zsh theme to powerlevel10k 17 | echo "Changing default powerlevel10k theme from 'robbyrussell' to 'powerlevel10k/powerlevel10k'" 18 | sed -i -e 's|ZSH_THEME="robbyrussell"|ZSH_THEME="powerlevel10k/powerlevel10k"|' "$HOME"/.zshrc 19 | 20 | # Copy p10k config 21 | echo "Copying powerlevel10k configuration" 22 | cp -v "$(dirname "$0")"/.p10k.zsh "$HOME"/ 23 | 24 | # Ensure p10k config is included 25 | echo "[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh" >> "$HOME/.zshrc" 26 | 27 | # Warn user about fonts 28 | echo "Please ensure the recommended fonts from https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k are installed, and your terminal is using 'MesloLGS NF'" 29 | -------------------------------------------------------------------------------- /setup/arch-manjaro.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to setup an android build environment on Arch Linux and derivative distributions 4 | 5 | clear 6 | echo 'Starting Arch-based Android build setup' 7 | # Uncomment the multilib repo, incase it was commented out 8 | echo '[1/4] Enabling multilib repo' 9 | sudo sed -i "/\[multilib\]/,/Include/"'s/^#//' /etc/pacman.conf 10 | # Sync, update, and prepare system 11 | echo '[2/4] Syncing repositories and updating system packages' 12 | sudo pacman -Syyu --noconfirm --needed git git-lfs multilib-devel fontconfig ttf-droid python-pyelftools 13 | # Install android build prerequisites 14 | echo '[3/4] Installing Android building prerequisites' 15 | packages="ncurses5-compat-libs lib32-ncurses5-compat-libs aosp-devel xml2 lineageos-devel" 16 | if command -v paru 2>&1 >/dev/null 17 | then 18 | paru -S --noconfirm --needed $packages 19 | elif command -v yay 2>&1 >/dev/null 20 | then 21 | yay -S --noconfirm --needed $packages 22 | else 23 | for package in $packages; do 24 | echo "Installing $package" 25 | git clone https://aur.archlinux.org/"$package" 26 | cd "$package" || exit 27 | makepkg -si --skippgpcheck --noconfirm --needed 28 | cd - || exit 29 | rm -rf "$package" 30 | done 31 | fi 32 | # Install adb and associated udev rules 33 | echo '[4/4] Installing adb convenience tools' 34 | sudo pacman -S --noconfirm --needed android-tools android-udev 35 | 36 | echo 'Setup completed, enjoy' 37 | -------------------------------------------------------------------------------- /rr/channel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | [[ -z ${API_KEY} ]] && echo "API_KEY not defined, exiting!" && exit 1 3 | CHAT_ID="-1001185331716" 4 | curl -s "https://api.telegram.org/bot${API_KEY}/sendmessage" --data "text=$BUILD_URL&chat_id=$CHAT_ID&parse_mode=HTML" 5 | CHAT_ID="@ResurrectionRemixChannel" 6 | for device in $(git diff HEAD@\{1\}..HEAD --name-only); do 7 | d=${device/.json/} 8 | CHAT_ID="-1001185331716" 9 | authors="$(git log HEAD@\{1\}..HEAD --pretty=format:"%an")" 10 | newhash="$(git rev-parse HEAD)" 11 | oldhash="$(git rev-parse HEAD@\{1\})" 12 | text="$device - https://github.com/ResurrectionRemix-Devices/api/compare/$oldhash...$newhash - $authors" 13 | curl -s "https://api.telegram.org/bot${API_KEY}/sendmessage" --data "text=$text&chat_id=$CHAT_ID&parse_mode=HTML" 14 | CHAT_ID="@ResurrectionRemixChannel" 15 | msg=$(mktemp) 16 | zip=$(jq -r .response[].filename "${device}") 17 | filesize=$(($(($(jq -r .response[].size "${device}") / 1024)) / 1024)) 18 | sha=$(jq -r .response[].id "${device}") 19 | { 20 | echo "New Build for ${d} available" 21 | echo "${zip}" 22 | echo 23 | echo "FileSize: $filesize MB" 24 | echo "SHA256: $sha" 25 | } > "${msg}" 26 | MESSAGE=$(cat "$msg") 27 | curl -s "https://api.telegram.org/bot${API_KEY}/sendmessage" --data "text=$MESSAGE&chat_id=$CHAT_ID&parse_mode=HTML" 28 | done 29 | -------------------------------------------------------------------------------- /gerrit/parsepicks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import json 3 | import os 4 | import sys 5 | 6 | import requests 7 | 8 | DOGBIN = 'https://del.dog' 9 | DOGBIN_API = os.path.join(DOGBIN, 'documents') 10 | GERRIT = 'https://review.aosip.dev' 11 | GERRIT_API = os.path.join(GERRIT, 'changes/?q=') 12 | 13 | 14 | def query_changes(query): 15 | changes = requests.get(GERRIT_API+query).text[5:] 16 | ret = "" 17 | for line in json.loads(changes): 18 | ret += line['subject'] + '\n' 19 | return ret 20 | 21 | def main(): 22 | if len(sys.argv) != 2: 23 | print('No picks included') 24 | exit(1) 25 | 26 | picks = sys.argv[1].split('|') 27 | commits = "" 28 | 29 | for i in picks: 30 | if i.strip().split(' ')[0] == '-t': 31 | for j in i.split(' '): 32 | if j not in ('', '-t', 'sysserv-pie'): 33 | commits += query_changes('status:open topic:{}'.format(j)) 34 | else: 35 | for j in i.strip().split(' '): 36 | if '-' in j: 37 | commitrange = j.split('-') 38 | try: 39 | changes = range(int(commitrange[0]), int(commitrange[1])) 40 | except ValueError: 41 | continue 42 | for change in changes: 43 | commits += query_changes(str(change)) 44 | else: 45 | commits += query_changes(str(j)) 46 | 47 | print("{}/{}".format(DOGBIN, json.loads(requests.post(DOGBIN_API, commits).content.decode())['key'])) 48 | 49 | if __name__ == '__main__': 50 | main() 51 | -------------------------------------------------------------------------------- /random-py/apn-copy-tag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from pathlib import Path 5 | from xml.etree import ElementTree 6 | 7 | # ./apn.py source.xml destination.xml 8 | # If no arguments are provided, the user will be prompted to enter the file paths 9 | 10 | if len(sys.argv) < 3: 11 | source = input("Enter the source XML path: ") 12 | destination = input("Enter the destination XML path: ") 13 | else: 14 | source = sys.argv[1] 15 | destination = sys.argv[2] 16 | 17 | source_path = Path(source) 18 | destination_path = Path(destination) 19 | 20 | if not source_path.exists() or not destination_path.exists(): 21 | print("Please ensure that both the files exist") 22 | sys.exit(1) 23 | 24 | source_apn_xml = ElementTree.parse(source_path) 25 | destination_apn_xml = ElementTree.parse(destination_path) 26 | 27 | tags_to_match = ("apn", "mcc", "mnc") 28 | tags_to_copy = ("network_type_bitmask", "type") 29 | required_tags = tags_to_match + tags_to_copy 30 | 31 | mapping = {} 32 | 33 | for child in source_apn_xml.getroot(): 34 | if not all(tag in child.attrib for tag in required_tags): 35 | continue 36 | mapping["|".join([child.attrib[tag] for tag in tags_to_match])] = { 37 | tag: child.attrib[tag] for tag in tags_to_copy 38 | } 39 | 40 | 41 | for child in destination_apn_xml.getroot(): 42 | if not all(tag in child.attrib for tag in tags_to_match): 43 | continue 44 | key = "|".join([child.attrib[tag] for tag in tags_to_match]) 45 | if key in mapping: 46 | for tag in tags_to_copy: 47 | child.attrib[tag] = mapping[key][tag] 48 | 49 | destination_apn_xml.write(destination, encoding="utf-8") 50 | -------------------------------------------------------------------------------- /random-py/apn-copy-entries.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | from pathlib import Path 5 | from xml.etree import ElementTree 6 | 7 | # ./apn-copy-entries.py source.xml destination.xml 8 | # If no arguments are provided, the user will be prompted to enter the file paths 9 | 10 | if len(sys.argv) < 3: 11 | source = input("Enter the source XML path: ") 12 | destination = input("Enter the destination XML path: ") 13 | else: 14 | source = sys.argv[1] 15 | destination = sys.argv[2] 16 | 17 | source_path = Path(source) 18 | destination_path = Path(destination) 19 | 20 | if not source_path.exists() or not destination_path.exists(): 21 | print("Please ensure that both the files exist") 22 | sys.exit(1) 23 | 24 | source_apn_xml = ElementTree.parse(source_path) 25 | destination_apn_xml = ElementTree.parse(destination_path) 26 | 27 | tags_to_match = ("mcc", "mnc") 28 | tags_to_copy = ("apn") 29 | 30 | destination_root = destination_apn_xml.getroot() 31 | 32 | combinations = set() 33 | 34 | # Define a function to check if a child element is already in the destination root 35 | def is_in_destination(child, destination_root): 36 | for dest_child in destination_root: 37 | if child.attrib == dest_child.attrib: 38 | return True 39 | return False 40 | 41 | # Modify the loop that appends children from the source to the destination 42 | for child in source_apn_xml.getroot(): 43 | # Only consider children with apn='ims' 44 | if child.attrib.get('apn') == 'ims': 45 | # Only append the child if it is not already in the destination 46 | if not is_in_destination(child, destination_root): 47 | destination_root.append(child) 48 | 49 | destination_apn_xml.write(destination, encoding="utf-8") 50 | -------------------------------------------------------------------------------- /aosip/build-gsi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018-19 Akhil Narang 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | # AOSiP Build Script 6 | # shellcheck disable=SC1090,SC1091 7 | # SC1090: Can't follow non-constant source. Use a directive to specify location. 8 | # SC1091: Not following: (error message here) 9 | 10 | export PARSE_MODE="html" 11 | 12 | set -e 13 | source ~/scripts/functions 14 | export TZ=UTC 15 | export PATH=~/bin:$PATH 16 | rm -fv .repo/local_manifests/* 17 | wget https://raw.githubusercontent.com/AOSiP-Devices/device_phh_treble/pie/gsi.xml -O .repo/local_manifests/gsi.xml 18 | repo init -u https://github.com/AOSiP/platform_manifest.git -b pie --no-tags --no-clone-bundle --current-branch --repo-url https://github.com/akhilnarang/repo --repo-branch master --no-repo-verify 19 | repo forall -j"$(nproc)" -c "git reset --hard m/pie && git clean -fdx" 20 | time repo sync -j"$(nproc)" --current-branch --no-tags --no-clone-bundle --force-sync 21 | . build/envsetup.sh 22 | export AOSIP_BUILDTYPE=GSI 23 | lunch treble_"${ARCH}"_"${SYSTEMTYPE}"vN-userdebug 24 | m -j clean 25 | repopick -t dnm-gsi -f 26 | repopick_stuff 27 | export USE_CCACHE=1 28 | export CCACHE_DIR="${HOME}/.ccache" 29 | ccache -M 500G 30 | time m -j systemimage 31 | set +e 32 | cout && ls system.img || exit 1 33 | case ${SYSTEMTYPE} in 34 | "a") type="aonly" ;; 35 | "b") type="ab" ;; 36 | *) type="${SYSTEMTYPE}" ;; 37 | esac 38 | NAME="AOSiP-9.0-GSI-${ARCH}_${type}-$(date +%Y%m%d).img" 39 | cp -v "$OUT"/system.img /var/www/html/"$NAME" 40 | sendAOSiP "${ARCH}_${type} GSI build done on $(hostname)!" 41 | url="https://$(hostname)/$NAME" 42 | sendAOSiP "$url" 43 | if [[ ${RELEASE} == "yes" ]]; then 44 | rsync -av --progress "$OUT"/system.img kronic@illusion.aosip.dev:/mnt/builds/GSI/"$NAME" 45 | url="https://get.aosip.dev/GSI/$NAME" 46 | sendAOSiP "$url" 47 | else 48 | sendAOSiP "$(python3 ~/scripts/gerrit/parsepicks.py "$REPOPICK_LIST")" 49 | rsync -av --progress "$OUT"/system.img akhil@illusion.aosip.dev:/var/www/html/ 50 | url="https://build.aosip.dev/$NAME" 51 | sendAOSiP "$url" 52 | fi 53 | -------------------------------------------------------------------------------- /setup/fedora.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # SPDX-License-Identifier: GPL-3.0-only 4 | # 5 | # Script to setup an Android 10+ build 6 | # environment for Fedora 37 / Rawhide. 7 | 8 | # Packages 9 | sudo dnf install \ 10 | android-tools \ 11 | autoconf213 \ 12 | bison \ 13 | bzip2 \ 14 | ccache \ 15 | clang \ 16 | curl \ 17 | flex \ 18 | gawk \ 19 | gcc-c++ \ 20 | git \ 21 | git-lfs \ 22 | glibc-devel \ 23 | glibc-static \ 24 | libstdc++-static \ 25 | libX11-devel \ 26 | make \ 27 | mesa-libGL-devel \ 28 | ncurses-devel \ 29 | openssl \ 30 | patch \ 31 | zlib-devel \ 32 | ncurses-devel.i686 \ 33 | readline-devel.i686 \ 34 | zlib-devel.i686 \ 35 | libX11-devel.i686 \ 36 | mesa-libGL-devel.i686 \ 37 | glibc-devel.i686 \ 38 | libstdc++.i686 \ 39 | libXrandr.i686 \ 40 | zip \ 41 | perl-Digest-SHA \ 42 | python2 \ 43 | python3-pyelftools \ 44 | wget \ 45 | lzop \ 46 | openssl-devel \ 47 | openssl-devel-engine \ 48 | java-1.8.0-openjdk-devel \ 49 | ImageMagick \ 50 | schedtool \ 51 | lzip \ 52 | vboot-utils \ 53 | vim \ 54 | libxcrypt-compat 55 | 56 | # The package libncurses5 is not available, so we need to hack our way by symlinking the required library. 57 | sudo ln -s /usr/lib/libncurses.so.6 /usr/lib/libncurses.so.5 58 | sudo ln -s /usr/lib/libncurses.so.6 /usr/lib/libtinfo.so.5 59 | sudo ln -s /usr/lib64/libncurses.so.6 /usr/lib64/libncurses.so.5 60 | sudo ln -s /usr/lib64/libncurses.so.6 /usr/lib64/libtinfo.so.5 61 | 62 | # Repo 63 | echo "Installing Git Repository Tool" 64 | sudo curl --create-dirs -L -o /usr/local/bin/repo -O -L https://storage.googleapis.com/git-repo-downloads/repo 65 | sudo chmod a+rx /usr/local/bin/repo 66 | 67 | echo -e "Setting up udev rules for ADB!" 68 | sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L https://raw.githubusercontent.com/M0Rf30/android-udev-rules/master/51-android.rules 69 | sudo chmod 644 /etc/udev/rules.d/51-android.rules 70 | sudo chown root /etc/udev/rules.d/51-android.rules 71 | sudo udevadm control --reload-rules 72 | -------------------------------------------------------------------------------- /release-kernel: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018 Akhil Narang 4 | # Copyright (C) 2018 Harsh Shandilya 5 | # SPDX-License-Identifier: GPL-3.0-only 6 | # Kernel release script 7 | 8 | # shellcheck disable=SC1090,SC2029 9 | # SC1090: Can't follow non-constant source. Use a directive to specify location. 10 | # SC2029: Note that, unescaped, this expands on the client side. 11 | 12 | source ~/scripts/functions 13 | 14 | [[ -z ${DEVICE} ]] && { [[ "$(pwd)" =~ "beryllium" ]] || [[ $* =~ "beryllium" ]]; } && DEVICE=beryllium 15 | [[ -z ${DEVICE} ]] && DEVICE=beryllium 16 | 17 | function tg() { 18 | case "${DEVICE}" in 19 | "beryllium") 20 | sendKernelBeryllium "${@:?}" 21 | ;; 22 | esac 23 | } 24 | 25 | SERVER="ssh.packet.resurrectionremix.com" 26 | DOWNLOAD_HOST="https://downloads.akhilnarang.dev" 27 | MIRROR_HOST="https://mirror.akhilnarang.dev" 28 | KERNEL_PATH="kernel/${DEVICE}" 29 | NAME=$(ssh "${SERVER}" ls mirror/"${KERNEL_PATH}"/Test/*.zip | tail -1) 30 | ILLUSIONVERSION="${1:?}" 31 | TAG="Illusion-v${ILLUSIONVERSION}" 32 | RELEASE_ZIPNAME="${TAG}.zip" 33 | CHANGELOG="${2}" 34 | 35 | tg "Releasing Illusion v$ILLUSIONVERSION" 36 | tg "Illusion v$ILLUSIONVERSION is up, grab it [here](${DOWNLOAD_HOST}/${KERNEL_PATH}/Stable/${RELEASE_ZIPNAME}) or [here](${MIRROR_HOST}/${KERNEL_PATH}/Stable/${RELEASE_ZIPNAME})" 37 | ssh "${SERVER}" "cp -v ${NAME} mirror/${KERNEL_PATH}/Stable/${RELEASE_ZIPNAME}; cd mirror/${KERNEL_PATH}/Stable; md5sum ${RELEASE_ZIPNAME} > ${RELEASE_ZIPNAME}.md5sum" 38 | ssh "${SERVER}" ./bin/mirrorsync 39 | tg "Changelog: 40 | \`\`\` 41 | ${CHANGELOG} 42 | \`\`\`" 43 | 44 | cd "${KERNELDIR}/${DEVICE}" || exit 1 45 | git tag -as "${TAG}" -m "${CHANGELOG}" 46 | git p origin "${TAG}" 47 | cd /tmp || exit 1 48 | wget "${DOWNLOAD_HOST}/${KERNEL_PATH}/Stable/${RELEASE_ZIPNAME}" 49 | wget "${DOWNLOAD_HOST}/${KERNEL_PATH}/Stable/${RELEASE_ZIPNAME}.md5sum" 50 | cd - || exit 1 51 | hub release create "${TAG}" -a "/tmp/${RELEASE_ZIPNAME}" -a "/tmp/${RELEASE_ZIPNAME}.md5sum" -m "Illusion v${1} release" 52 | rm "/tmp/${RELEASE_ZIPNAME}" "/tmp/${RELEASE_ZIPNAME}.md5sum" 53 | tg "${TAG} released!" 54 | -------------------------------------------------------------------------------- /rr/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck disable=SC1091,SC2029 4 | # SC1091: Not following: build/envsetup.sh: openBinaryFile: does not exist (No such file or directory) 5 | # SC2029: Note that, unescaped, this expands on the client side 6 | 7 | # Repopicks a | delimited set of commits 8 | function repopick_stuff() { 9 | export oldifs=$IFS 10 | export IFS="|" 11 | for f in ${REPOPICK_LIST}; do 12 | echo "Picking: $f" 13 | eval repopick "${f}" || return 14 | done 15 | export IFS=$oldifs 16 | } 17 | 18 | [[ -z ${API_KEY} ]] && echo "API_KEY not defined, exiting!" && exit 1 19 | function sendTG() { 20 | curl -s "https://api.telegram.org/bot${API_KEY}/sendmessage" --data "text=${*}&chat_id=-1001185331716&parse_mode=Markdown" > /dev/null 21 | } 22 | rm -fv .repo/local_manifests/* 23 | export days_to_log=${DAY} 24 | source ~/.bashrc 25 | repo sync --force-sync -j64 26 | . build/envsetup.sh 27 | if ! breakfast "${DEVICE:?}"; then 28 | sendTG "Lunching [$DEVICE]($BUILD_URL) failed on $NODE_NAME" 29 | exit 1 30 | fi 31 | repopick_stuff 32 | export USE_CCACHE=1 33 | ccache -M 200G 34 | mka "${CLOBBER:?}" 35 | rm -rfv "${OUT}/{RR*,system,vendor}" 36 | sendTG "Starting build for [$DEVICE]($BUILD_URL) on $NODE_NAME" 37 | if ! mka bacon; then 38 | sendTG "[$DEVICE]($BUILD_URL) Build failed on $NODE_NAME" 39 | exit 1 40 | fi 41 | cout 42 | ZIP=$(ls RR*.zip) 43 | ssh jenkins@ssh.packet.resurrectionremix.com "rm -rf /home/acar/ua/.hidden/${DEVICE:?}" 44 | ssh jenkins@ssh.packet.resurrectionremix.com "mkdir /home/acar/ua/.hidden/$DEVICE -p" 45 | scp "${ZIP}" "jenkins@ssh.packet.resurrectionremix.com:/home/acar/ua/.hidden/${DEVICE}"/ 46 | scp "${DEVICE}".json "jenkins@ssh.packet.resurrectionremix.com:/home/acar/ua/.hidden/${DEVICE}"/ 47 | cd - || exit 48 | scp CHANGELOG.mkdn "jenkins@ssh.packet.resurrectionremix.com:/home/acar/ua/.hidden/${DEVICE}/${ZIP/.zip/-changelog.txt}" 49 | DEVICE_C="$(echo "$DEVICE" | tr '[:upper:]' '[:lower:]')" 50 | sendTG "$DEVICE_C build is done on $NODE_NAME. It's private. Test it then publish it." 51 | sendTG "[$ZIP](https://rr.umutcanacar.me/.hidden/$DEVICE/$ZIP)" 52 | sendTG "[Changelog](https://rr.umutcanacar.me/.hidden/$DEVICE/${ZIP/.zip/-changelog.txt})" 53 | -------------------------------------------------------------------------------- /setup/hub.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) Harsh Shandilya 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | 6 | function get_release_assets() { 7 | local REPOSITORY RELEASE_TAG RELEASE_ID TMP_FILE 8 | REPOSITORY="${1:?}" 9 | RELEASE_TAG="${2:-latest}" 10 | TMP_FILE="$(mktemp)" 11 | if [ "${RELEASE_TAG}" == "latest" ]; then 12 | RELEASE_ID=$(curl --silent "https://api.github.com/repos/${1:?}/releases/latest" | # Get the latest release from GitHub API 13 | jq -r .id) 14 | else 15 | curl --silent "https://api.github.com/repos/${REPOSITORY}/releases" | jq '.[] | {id: .id, name: .tag_name}' > "${TMP_FILE}" 16 | RELEASE_ID=$(jq -r '"\(.id) \(.name)"' "${TMP_FILE}" | grep "${RELEASE_TAG}" | awk '{print $1}') 17 | fi 18 | curl --silent "https://api.github.com/repos/${REPOSITORY}/releases/${RELEASE_ID}" | jq -r .assets[].browser_download_url 19 | [ -f "${TMP_FILE}" ] && rm -f "${TMP_FILE}" 20 | } 21 | 22 | function get_latest_release() { 23 | curl --silent "https://api.github.com/repos/${1:?}/releases/latest" | # Get latest release from GitHub API 24 | jq -r .tag_name # Get tag line 25 | } 26 | 27 | function install_hub() { 28 | local INSTALLED_VERSION HUB HUB_ARCH CL_YLW CL_RST 29 | CL_YLW='\033[01;33m' 30 | CL_RST='\033[0m' 31 | echo "Checking and installing hub" 32 | HUB="$(command -v hub)" 33 | HUB_ARCH=linux-amd64 34 | if [ -z "${HUB}" ]; then 35 | aria2c "$(get_release_assets github/hub | grep ${HUB_ARCH})" -o hub.tgz || wget "$(get_release_assets github/hub | grep ${HUB_ARCH})" -O hub.tgz 36 | mkdir -p hub 37 | tar -xf hub.tgz -C hub 38 | sudo ./hub/*/install --prefix=/usr/local/ 39 | rm -rf hub/ hub.tgz 40 | else 41 | INSTALLED_VERSION="v$(hub --version | tail -n1 | awk '{print $3}')" 42 | LATEST_VERSION="$(get_latest_release github/hub)" 43 | if [ "${INSTALLED_VERSION}" != "${LATEST_VERSION}" ]; then 44 | echo -e "${CL_YLW} Outdated version of hub detected, upgrading${CL_RST}" 45 | wget "$(get_release_assets github/hub | grep ${HUB_ARCH})" -O=hub.tgz 46 | mkdir -p hub 47 | tar -xf hub.tgz -C hub 48 | sudo ./hub/*/install --prefix=/usr/local/ 49 | rm -rf hub/ hub.tgz 50 | else 51 | echo -e "${CL_YLW}hub ${INSTALLED_VERSION} is already installed!${CL_RST}" 52 | fi 53 | fi 54 | } 55 | 56 | [[ $(command -v jq) ]] && install_hub || echo "Please install jq" 57 | -------------------------------------------------------------------------------- /setup/opensuse.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Script to setup an android build environment for openSUSE. 4 | 5 | # openSUSE Mirrors (https://github.com/Firstyear/mirrorsorcerer) 6 | sudo zypper in mirrorsorcerer 7 | sudo systemctl enable --now mirrorsorcerer 8 | 9 | # Packages 10 | sudo zypper install \ 11 | android-tools \ 12 | autoconf213 \ 13 | bc \ 14 | bison \ 15 | bzip2 \ 16 | ccache \ 17 | clang \ 18 | curl \ 19 | flex \ 20 | gawk \ 21 | gpg2 \ 22 | gperf \ 23 | gcc-c++ \ 24 | git \ 25 | git-lfs \ 26 | glibc-devel \ 27 | ImageMagick \ 28 | java-11-openjdk \ 29 | java-1_8_0-openjdk \ 30 | java-1_8_0-openjdk-devel \ 31 | liblz4-1 \ 32 | libncurses5 \ 33 | libncurses6 \ 34 | libpopt0 \ 35 | libressl-devel \ 36 | libstdc++6\ 37 | libX11-6 \ 38 | libxml2-tools \ 39 | libxslt1 \ 40 | libX11-devel \ 41 | libXrandr2 \ 42 | lzip \ 43 | lzop \ 44 | kernel-devel \ 45 | maven \ 46 | make \ 47 | megatools \ 48 | Mesa-libGL1 \ 49 | Mesa-libGL-devel \ 50 | mokutil \ 51 | nano \ 52 | neofetch \ 53 | ncurses5-devel \ 54 | ncurses-devel \ 55 | openssl \ 56 | opi \ 57 | patch \ 58 | perl-Digest-SHA1 \ 59 | python \ 60 | python-rpm-generators \ 61 | python3-pyelftools \ 62 | readline-devel \ 63 | schedtool \ 64 | screenfetch \ 65 | sha3sum \ 66 | squashfs \ 67 | vim \ 68 | wget \ 69 | wireguard-tools \ 70 | xf86-video-intel \ 71 | zip \ 72 | zlib-devel 73 | 74 | # Devel Basis on OpenSUSE (https://darryldias.me/2020/devel-basis-on-opensuse-sle/) 75 | sudo zypper install -t pattern devel_basis 76 | 77 | # The package libncurses5 is not available, so we need to hack our way by symlinking the required library. 78 | sudo ln -s /usr/lib/libncurses.so.6 /usr/lib/libncurses.so.5 79 | sudo ln -s /usr/lib/libncurses.so.6 /usr/lib/libtinfo.so.5 80 | sudo ln -s /usr/lib64/libncurses.so.6 /usr/lib64/libncurses.so.5 81 | sudo ln -s /usr/lib64/libncurses.so.6 /usr/lib64/libtinfo.so.5 82 | 83 | # Repo 84 | echo "Installing Git Repository Tool" 85 | sudo curl --create-dirs -L -o /usr/local/bin/repo -O -L https://storage.googleapis.com/git-repo-downloads/repo 86 | sudo chmod a+rx /usr/local/bin/repo 87 | 88 | echo -e "Setting up udev rules for ADB!" 89 | sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L https://raw.githubusercontent.com/M0Rf30/android-udev-rules/master/51-android.rules 90 | sudo chmod 644 /etc/udev/rules.d/51-android.rules 91 | sudo chown root /etc/udev/rules.d/51-android.rules 92 | sudo udevadm control --reload-rules 93 | 94 | # Set default editor 95 | git config --global core.editor "nano" 96 | -------------------------------------------------------------------------------- /aosip/merge.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | AOSIP_PATH=$PWD 4 | TAG="android-10.0.0_r${1:?}" 5 | SRC="ten" 6 | 7 | do_not_merge="vendor/aosip manifest updater packages/apps/OmniSwitch packages/apps/OmniStyle \ 8 | packages/apps/OwlsNest external/google packages/apps/Launcher3 hardware/qcom/power \ 9 | packages/apps/Gallery2 device/qcom/common device/qcom/sepolicy device/aosip/sepolicy \ 10 | external/DUtils packages/apps/DUI packages/apps/Updater packages/apps/FMRadio \ 11 | packages/apps/SlimRecents packages/services/OmniJaws packages/apps/LockClock \ 12 | packages/apps/CalendarWidget hardware/qcom/fm external/ant-wireless/ant_native \ 13 | external/ant-wireless/ant_service external/ant-wireless/antradio-library external/bash \ 14 | external/brctl external/chromium-webview external/connectivity external/busybox external/htop \ 15 | external/fuse external/exfat external/ebtables external/ffmpeg external/gson vendor/codeaurora/telephony \ 16 | external/json-c external/libncurses external/libnetfilter_conntrack prebuilts/build-tools prebuilts/clang/host/linux-x86 \ 17 | system/qcom external/libnfnetlink external/libnfc-nxp external/nano external/ntfs-3g vendor/qcom/opensource/cryptfs_hw \ 18 | vendor/qcom/opensource/dataservices vendor/qcom/opensource/interfaces vendor/qcom/opensource/rcs-service packages/apps/MusicFX" 19 | 20 | AOSP="https://android.googlesource.com" 21 | 22 | for filess in failed success notaosp; do 23 | rm $filess 2> /dev/null 24 | touch $filess 25 | done 26 | 27 | . build/envsetup.sh || exit 1 28 | repo sync --detach --quiet 29 | 30 | # AOSiP manifest is setup with repo path first, then repo name, so the path attribute is after 2 spaces, and the path itself within "" in it 31 | while read -r repos; do 32 | echo -e "" 33 | # shellcheck disable=SC2076,SC2154 34 | if [[ ${do_not_merge} =~ ${repos} ]]; then 35 | echo -e "${repos} is not to be merged" 36 | else 37 | echo "$blu Merging $repos $end" 38 | echo -e "" 39 | cd "$repos" || continue 40 | if [[ $repos == "build/make" ]]; then 41 | repos="build" 42 | fi 43 | git branch -D $SRC 44 | git checkout -b $SRC m/$SRC 45 | git remote rm aosp 2> /dev/null 46 | git remote add aosp "${AOSP}/platform/$repos" 47 | if ! git fetch aosp --quiet --tags; then 48 | echo "$repos" >> "${AOSIP_PATH}"/notaosp 49 | else 50 | if ! git merge "${TAG}" --no-edit; then 51 | echo "$repos" >> "${AOSIP_PATH}"/failed 52 | echo "$red $repos failed :( $end" 53 | else 54 | if [[ "$(git rev-parse HEAD)" != "$(git rev-parse aosip/${SRC})" ]]; then 55 | echo "$repos" >> "${AOSIP_PATH}"/success 56 | git commit --signoff --date="$(date)" --amend --no-edit 57 | echo "$grn $repos succeeded $end" 58 | echo "Pushing!" 59 | gerrit 60 | git push gerrit $SRC 61 | else 62 | echo "$repos - unchanged" 63 | fi 64 | fi 65 | fi 66 | echo -e "" 67 | cd "${AOSIP_PATH}" || exit 1 68 | fi 69 | done < <(grep 'remote="aosip"' "${AOSIP_PATH}"/.repo/manifests/snippets/aosip.xml | awk '{print $2}' | awk -F '"' '{print $2}' | grep -v caf) 70 | 71 | echo "Repos that failed are - " 72 | cat "$AOSIP_PATH"/failed 73 | -------------------------------------------------------------------------------- /aosip/rebase.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | AOSIP_PATH=$PWD 4 | TAG="android-10.0.0_r${1:?}" 5 | SRC="ten" 6 | 7 | do_not_merge="vendor/aosip manifest updater packages/apps/OmniSwitch packages/apps/OmniStyle \ 8 | packages/apps/OwlsNest external/google packages/apps/Launcher3 hardware/qcom/power \ 9 | packages/apps/Gallery2 device/qcom/common device/qcom/sepolicy device/aosip/sepolicy \ 10 | external/DUtils packages/apps/DUI packages/apps/Updater packages/apps/FMRadio \ 11 | packages/apps/SlimRecents packages/services/OmniJaws packages/apps/LockClock \ 12 | packages/apps/CalendarWidget hardware/qcom/fm external/ant-wireless/ant_native \ 13 | external/ant-wireless/ant_service external/ant-wireless/antradio-library external/bash \ 14 | external/brctl external/chromium-webview external/connectivity external/busybox external/htop \ 15 | external/fuse external/exfat external/ebtables external/ffmpeg external/gson vendor/codeaurora/telephony \ 16 | external/json-c external/libncurses external/libnetfilter_conntrack prebuilts/build-tools prebuilts/clang/host/linux-x86 \ 17 | system/qcom external/libnfnetlink external/libnfc-nxp external/nano external/ntfs-3g vendor/qcom/opensource/cryptfs_hw \ 18 | vendor/qcom/opensource/dataservices vendor/qcom/opensource/interfaces vendor/qcom/opensource/rcs-service packages/apps/MusicFX" 19 | 20 | AOSP="https://android.googlesource.com" 21 | 22 | for filess in failed success notaosp; do 23 | rm $filess 2> /dev/null 24 | touch $filess 25 | done 26 | 27 | repo sync --detach --quiet 28 | 29 | # AOSiP manifest is setup with repo path first, then repo name, so the path attribute is after 2 spaces, and the path itself within "" in it 30 | while read -r repos; do 31 | echo -e "" 32 | # shellcheck disable=SC2076,SC2154 33 | if [[ ${do_not_merge} =~ ${repos} ]]; then 34 | echo -e "${repos} is not to be merged" 35 | else 36 | echo "$blu Merging $repos $end" 37 | echo -e "" 38 | cd "$repos" || continue 39 | if [[ $repos == "build/make" ]]; then 40 | repos="build" 41 | fi 42 | git branch -D $SRC 43 | git checkout -b $SRC m/$SRC 44 | git remote rm aosp 2> /dev/null 45 | git remote add aosp "${AOSP}/platform/$repos" 46 | if ! git fetch aosp --quiet --tags; then 47 | echo "$repos" >> "${AOSIP_PATH}"/notaosp 48 | else 49 | if ! git rebase "${TAG}"; then 50 | echo "$repos" >> "${AOSIP_PATH}"/failed 51 | echo "$red $repos failed :( $end" 52 | else 53 | echo "$repos" >> "${AOSIP_PATH}"/success 54 | echo "$grn $repos succeeded $end" 55 | echo "Pushing!" 56 | r=$(git rv | grep github.com.AOSiP | awk '{print $2}' | head -1 | sed 's/AOSiP/kronic-staging/') 57 | n=$(git rv | grep github.com.AOSiP | awk '{print $2}' | head -1 | awk -F'/' '{print $NF}') 58 | curl -s -X POST -H "Authorization: token ${GITHUB_API_TOKEN}" -d '{ "name": "'"$n"'" }' "https://api.github.com/orgs/kronic-staging/repos" 59 | git push "$r" HEAD:refs/heads/"$TAG-$SRC" 60 | fi 61 | fi 62 | echo -e "" 63 | cd "${AOSIP_PATH}" || exit 1 64 | fi 65 | done < <(grep 'remote="aosip"' "${AOSIP_PATH}"/.repo/manifests/snippets/aosip.xml | awk '{print $2}' | awk -F '"' '{print $2}' | grep -v caf) 66 | 67 | FAILED=$(cat "$AOSIP_PATH"/failed) 68 | export FAILED 69 | -------------------------------------------------------------------------------- /setup/android_build_env.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018 Harsh 'MSF Jarvis' Shandilya 4 | # Copyright (C) 2018 Akhil Narang 5 | # SPDX-License-Identifier: GPL-3.0-only 6 | 7 | # Script to setup an AOSP Build environment on Ubuntu and Linux Mint 8 | 9 | LATEST_MAKE_VERSION="4.3" 10 | UBUNTU_16_PACKAGES="libesd0-dev" 11 | UBUNTU_20_PACKAGES="libncurses5 curl python-is-python3" 12 | DEBIAN_10_PACKAGES="libncurses5" 13 | DEBIAN_11_PACKAGES="libncurses5" 14 | PACKAGES="" 15 | 16 | sudo apt install software-properties-common -y 17 | sudo apt update 18 | 19 | # Install lsb-core packages 20 | sudo apt install lsb-core -y 21 | 22 | LSB_RELEASE="$(lsb_release -d | cut -d ':' -f 2 | sed -e 's/^[[:space:]]*//')" 23 | 24 | if [[ ${LSB_RELEASE} =~ "Mint 18" || ${LSB_RELEASE} =~ "Ubuntu 16" ]]; then 25 | PACKAGES="${UBUNTU_16_PACKAGES}" 26 | elif [[ ${LSB_RELEASE} =~ "Ubuntu 20" || ${LSB_RELEASE} =~ "Ubuntu 21" || ${LSB_RELEASE} =~ "Ubuntu 22" || ${LSB_RELEASE} =~ 'Pop!_OS 2' ]]; then 27 | PACKAGES="${UBUNTU_20_PACKAGES}" 28 | elif [[ ${LSB_RELEASE} =~ "Debian GNU/Linux 10" ]]; then 29 | PACKAGES="${DEBIAN_10_PACKAGES}" 30 | elif [[ ${LSB_RELEASE} =~ "Debian GNU/Linux 11" ]]; then 31 | PACKAGES="${DEBIAN_11_PACKAGES}" 32 | fi 33 | 34 | sudo DEBIAN_FRONTEND=noninteractive \ 35 | apt install \ 36 | adb autoconf automake axel bc bison build-essential \ 37 | ccache clang cmake curl expat fastboot flex g++ \ 38 | g++-multilib gawk gcc gcc-multilib git git-lfs gnupg gperf \ 39 | htop imagemagick lib32ncurses5-dev lib32z1-dev libtinfo5 libc6-dev libcap-dev \ 40 | libexpat1-dev libgmp-dev '^liblz4-.*' '^liblzma.*' libmpc-dev libmpfr-dev libncurses5-dev \ 41 | libsdl1.2-dev libssl-dev libtool libxml2 libxml2-utils '^lzma.*' lzop \ 42 | maven ncftp ncurses-dev patch patchelf pkg-config pngcrush \ 43 | pngquant python2.7 python3-pyelftools python-all-dev re2c schedtool squashfs-tools subversion \ 44 | texinfo unzip w3m xsltproc zip zlib1g-dev lzip \ 45 | libxml-simple-perl libswitch-perl apt-utils rsync \ 46 | ${PACKAGES} -y 47 | 48 | echo -e "Installing GitHub CLI" 49 | curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 50 | sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg 51 | echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null 52 | sudo apt update 53 | sudo apt install -y gh 54 | 55 | echo -e "Setting up udev rules for adb!" 56 | sudo curl --create-dirs -L -o /etc/udev/rules.d/51-android.rules -O -L https://raw.githubusercontent.com/M0Rf30/android-udev-rules/master/51-android.rules 57 | sudo chmod 644 /etc/udev/rules.d/51-android.rules 58 | sudo chown root /etc/udev/rules.d/51-android.rules 59 | sudo systemctl restart udev 60 | 61 | if [[ "$(command -v make)" ]]; then 62 | makeversion="$(make -v | head -1 | awk '{print $3}')" 63 | if [[ ${makeversion} != "${LATEST_MAKE_VERSION}" ]]; then 64 | echo "Installing make ${LATEST_MAKE_VERSION} instead of ${makeversion}" 65 | bash "$(dirname "$0")"/make.sh "${LATEST_MAKE_VERSION}" 66 | fi 67 | fi 68 | 69 | echo "Installing repo" 70 | sudo curl --create-dirs -L -o /usr/local/bin/repo -O -L https://storage.googleapis.com/git-repo-downloads/repo 71 | sudo chmod a+rx /usr/local/bin/repo 72 | -------------------------------------------------------------------------------- /misc/ssh-copy-id-github.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copy a ssh key to Github 3 | # Copyright (C) 2015 Christoph "criztovyl" Schulz 4 | # Copyright (C) 2018 Harsh "msfjarvis" Shandilya 5 | # SDPX-License-Identifier: WTFPL 6 | 7 | # Help 8 | [ "$1" == "--help" ] || [ "$1" == "-h" ] || [ "$1" == "help" ] && 9 | { 10 | echo "Usage: ./ssh-copy-id-github [username]" 11 | echo "Adds .ssh/id_ed25519.pub to your Github's SSH keys." 12 | 13 | echo "Usage: ./ssh-copy-id-github [username] [pub_key_file]" 14 | echo "Adds specified Public Key File to your Github's SSH keys." 15 | 16 | echo "With confirmation, non-exiting Public Key File kicks off ssh-keygen" 17 | exit 18 | } 19 | 20 | ### 21 | # Constants 22 | TRUE=0 23 | FALSE=1 24 | XGH="X-GitHub-OTP: required; " # Git Hub OTP Header 25 | DEFAULT_KEY="$HOME/.ssh/id_ed25519.pub" 26 | 27 | ### 28 | # Function 29 | # Args: username 30 | # username: Github username 31 | # ssh_key : SSH key file, default: $HOME/.ssh/id_ed25519.pub 32 | function ssh_copy_id_github() { 33 | 34 | local username key_file otp type 35 | username="${1}" 36 | key_file="${2}" 37 | 38 | [ -z "$key_file" ] && { key_file="$DEFAULT_KEY"; } 39 | 40 | if [ ! -e "$key_file" ]; then 41 | 42 | read -rp "SSH key file doesn't exist: $key_file, do you want to generate a $key_file (y/n)?: " 43 | echo 44 | 45 | if [[ $REPLY =~ ^[Yy]$ ]]; then 46 | ssh-keygen -t ed25519 -f "${key_file%.pub}" 47 | else 48 | echo "Need SSH key file to upload, e.g. $DEFAULT_KEY" 49 | exit 1 50 | fi 51 | fi 52 | 53 | key=$(cat "$key_file") 54 | 55 | [ -z "$username" ] && read -rp "GitHub username: " username || username="$username" 56 | echo "Username: $username" 57 | 58 | read -rsp "GitHub password: " password && echo 59 | 60 | response=$( 61 | curl -is https://api.github.com/user/keys -X POST -u "$username:$password" -H "application/json" \ 62 | -d "{\"title\": \"$USER@$HOSTNAME\", \"key\": \"$key\"}" | 63 | grep 'Status: [45][0-9]\{2\}\|X-GitHub-OTP: required; .\+\|message' | tr -d "\r" 64 | ) 65 | 66 | otp_required "$response" otp 67 | otp_type "$response" type # app or sms 68 | 69 | [ "$(echo "$response" | grep -c 'Status: 401\|Bad credentials')" -eq 2 ] && { 70 | echo "Wrong password." 71 | exit 5 72 | } 73 | 74 | [ "$(echo "$response" | grep -c 'Status: 422\|key is already in use')" -eq 2 ] && { 75 | echo "Key is already uploaded." 76 | exit 5 77 | } 78 | 79 | # Display raw response for unkown 400 messages 80 | [ "$(echo "$response" | grep -c 'Status: 4[0-9][0-9]')" -eq 1 ] && echo "$response" 81 | exit 1 82 | 83 | if [ "$otp" == "$TRUE" ]; then 84 | read -rsp "Enter your OTP code (check your $type): " code && echo 85 | 86 | response=$(curl -si https://api.github.com/user/keys -X POST -u "$username:$password" -H "X-GitHub-OTP: $code" -H "application/json" -d "{\"title\": \"$USER@$HOSTNAME\", \"key\": \"$key\"}" | grep 'Status: [45][0-9]\{2\}\|X-GitHub-OTP: required; .\+\|message\|key' | tr -d "\r") 87 | 88 | otp_required "$response" otp 89 | [ "$otp" == "$TRUE" ] && { 90 | echo "Wrong OTP." 91 | exit 10 92 | } 93 | [ "$(echo "$response" | grep -c "key")" -gt 0 ] && echo "Success." 94 | fi 95 | } 96 | 97 | function otp_required() { 98 | local filteredResponse resultVar _otp 99 | filteredResponse="$1" 100 | resultVar="$2" 101 | _otp=$(echo "$filteredResponse" | grep -c "$XGH") 102 | if [ "$_otp" -eq 1 ]; then 103 | eval "$resultVar"="$TRUE" 104 | else 105 | eval "$resultVar"="$FALSE" 106 | fi 107 | } 108 | 109 | function otp_type() { 110 | local filteredResponse resultVar _type 111 | filteredResponse="$1" 112 | resultVar="$2" 113 | _type=$(echo "$filteredResponse" | grep "$XGH" | sed "s/.\+$XGH\(\w\+\).\+/\1/") 114 | eval "$resultVar"="$_type" 115 | } 116 | 117 | # Execute. 118 | ssh_copy_id_github "$1" "$2" 119 | -------------------------------------------------------------------------------- /aosip/sign.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018-20 Akhil Narang 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | # AOSiP upload script 6 | 7 | # shellcheck disable=SC2086,SC2029 8 | # SC2086: Double quote to prevent globbing and word splitting 9 | # SC2029: Note that, unescaped, this expands on the client side. 10 | 11 | case "${BRANCH}" in 12 | "ten") 13 | VERSION=10 14 | ;; 15 | "eleven") 16 | VERSION=11 17 | ;; 18 | esac 19 | 20 | source ~/scripts/functions 21 | 22 | function notify() { 23 | if [[ ! $AOSIP_BUILDTYPE =~ ^(Official|Gapps)$ ]]; then 24 | sendAOSiP "$@" 25 | fi 26 | } 27 | 28 | export TZ=UTC 29 | DATE="$(date +%Y%m%d)" 30 | AOSIP_VERSION="AOSiP-${VERSION}-${AOSIP_BUILDTYPE}-${DEVICE}-${DATE}" 31 | SIGNED_OTAPACKAGE="${AOSIP_VERSION}.zip" 32 | BOOTIMAGE="${AOSIP_VERSION}-boot.img" 33 | RECOVERYIMAGE="${AOSIP_VERSION}-recovery.img" 34 | SIGNED_TARGET_FILES="signed-target_files.zip" 35 | SIGNED_IMAGE_PACKAGE="${AOSIP_VERSION}-img.zip" 36 | OUT="./out/target/product/$DEVICE" 37 | UPLOAD="./upload_assets" 38 | UPDATER_JSON="$DEVICE-$AOSIP_BUILDTYPE".json 39 | mkdir -pv "$UPLOAD" 40 | BACKUPTOOL="--backup=true" 41 | if [[ $WITH_GAPPS == "true" ]]; then 42 | SIGNING_FLAGS="-e CronetDynamite.apk= -e DynamiteLoader.apk= -e DynamiteModulesA.apk= -e AdsDynamite.apk= -e DynamiteModulesC.apk= -e MapsDynamite.apk= -e GoogleCertificates.apk= -e AndroidPlatformServices.apk=" 43 | BACKUPTOOL="--backup=false" 44 | fi 45 | 46 | echo "Signing target_files APKs" 47 | python2 ./build/make/tools/releasetools/sign_target_files_apks -p out/host/linux-x86/ -o -d ~/.android-certs $SIGNING_FLAGS "$OUT"/obj/PACKAGING/target_files_intermediates/aosip_"$DEVICE"-target_files-"$BUILD_NUMBER".zip "$UPLOAD/$SIGNED_TARGET_FILES" || exit 1 48 | 49 | echo "Generating signed otapackage" 50 | python2 ./build/make/tools/releasetools/ota_from_target_files -p out/host/linux-x86/ -k ~/.android-certs/releasekey "$BACKUPTOOL" "$UPLOAD/$SIGNED_TARGET_FILES" "$UPLOAD/$SIGNED_OTAPACKAGE" || exit 1 51 | 52 | echo "Generating signed images package" 53 | python2 ./build/make/tools/releasetools/img_from_target_files -p out/soong/host/linux-x86/ "$UPLOAD/$SIGNED_TARGET_FILES" "$UPLOAD/$SIGNED_IMAGE_PACKAGE" || exit 1 54 | 55 | echo "Extracting build.prop to get build timestamp" 56 | BUILD_TIMESTAMP=$(grep -oP "(?<=ro.build.date.utc=).*" "$OUT"/system/build.prop) 57 | 58 | echo "Generating JSON for updater" 59 | ~/api/generate_json.py "$UPLOAD/$SIGNED_OTAPACKAGE" "$BUILD_TIMESTAMP" > "$UPDATER_JSON" 60 | 61 | echo "Extracting signed boot image" 62 | 7z e "$UPLOAD/$SIGNED_TARGET_FILES" IMAGES/boot.img -so > "$UPLOAD/$BOOTIMAGE" 63 | 64 | echo "Extracting signed recovery image" 65 | 7z e "$UPLOAD/$SIGNED_TARGET_FILES" IMAGES/recovery.img -so > "$UPLOAD/$RECOVERYIMAGE" 66 | 67 | echo "Generating MD5 checksums" 68 | md5sum "$UPLOAD/$SIGNED_OTAPACKAGE" > "$UPLOAD/$SIGNED_OTAPACKAGE".md5sum 69 | md5sum "$UPLOAD/$SIGNED_IMAGE_PACKAGE" > "$UPLOAD/$SIGNED_IMAGE_PACKAGE".md5sum 70 | 71 | # Create an archive out of everything 72 | cd $UPLOAD || exit 73 | tar -cvf ~/nginx/"$BUILD_NUMBER".tar AOSiP* 74 | cd - || exit 75 | rm -rfv $UPLOAD 76 | 77 | # Mirror the archive 78 | ssh Illusion "mkdir /tmp/$BUILD_NUMBER; curl -Ls https://$(hostname)/$BUILD_NUMBER.tar | tar xv -C /tmp/$BUILD_NUMBER; rclone copy -P --drive-chunk-size 256M /tmp/$BUILD_NUMBER/ aosip-jenkins:$BUILD_NUMBER" 79 | rm -fv ~/nginx/$BUILD_NUMBER.tar 80 | 81 | if [[ $AOSIP_BUILDTYPE =~ ^(CI|CI_Gapps|Quiche|Quiche_Gapps|Ravioli|Ravioli_Gapps)$ ]]; then 82 | ssh Illusion "rm -rfv /tmp/$BUILD_NUMBER" 83 | scp "$UPDATER_JSON" Illusion:/tmp/ 84 | ssh Illusion "rclone copy /tmp/$UPDATER_JSON aosip-jenkins:; rm -fv /tmp/$UPDATER_JSON" 85 | FOLDER_LINK="$(ssh Illusion rclone link aosip-jenkins:"$BUILD_NUMBER")" 86 | export PARSE_MODE="html" 87 | notify "Build $BUILD_NUMBER - $DEVICE $AOSIP_BUILDTYPE" 88 | notify "Direct link for $DEVICE $AOSIP_BUILDTYPE" 89 | notify "$(./jenkins/message_testers.py "${DEVICE}")" 90 | if [[ -n $REPOPICK_LIST ]]; then 91 | notify "$(python3 ~/scripts/gerrit/parsepicks.py "${REPOPICK_LIST}")" 92 | fi 93 | elif [[ $AOSIP_BUILDTYPE =~ ^(Official|Gapps)$ ]]; then 94 | ssh Illusion "bash ~/scripts/aosip/release.sh $DEVICE $BUILD_NUMBER $AOSIP_BUILDTYPE" 95 | python3 ~/api/post_device.py "$DEVICE" "$AOSIP_BUILDTYPE" 96 | fi 97 | rm -fv "$DEVICE-$AOSIP_BUILDTYPE".json 98 | -------------------------------------------------------------------------------- /aosip/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018-20 Akhil Narang 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | # AOSiP build script 6 | # shellcheck disable=SC1090,SC1091,SC2029 7 | # SC1090: Can't follow non-constant source. Use a directive to specify location. 8 | # SC1091: Not following: (error message here) 9 | # SC2029: Note that, unescaped, this expands on the client side. 10 | 11 | source ~/scripts/functions 12 | 13 | function notify() { 14 | if [[ ! $AOSIP_BUILDTYPE =~ ^(Official|Gapps)$ ]]; then 15 | sendAOSiP "$@" 16 | fi 17 | } 18 | 19 | function getAbort() { 20 | sendAOSiP "Build $BUILD_NUMBER has been aborted" 21 | } 22 | 23 | trap 'tag_aborted' SIGTERM 24 | 25 | export TZ=UTC 26 | 27 | curl --silent --fail --location https://review.aosip.dev > /dev/null || { 28 | notify "$DEVICE $AOSIP_BUILDTYPE is being aborted because gerrit is down!" 29 | exit 1 30 | } 31 | 32 | # Set some variables based on the buildtype 33 | if [[ $AOSIP_BUILDTYPE =~ ^(Official|Gapps|CI|CI_Gapps|Quiche|Quiche_Gapps|Ravioli|Ravioli_Gapps)$ ]]; then 34 | TARGET="otatools target-files-package" 35 | if [[ $AOSIP_BUILDTYPE =~ ^(CI|CI_Gapps|Quiche|Quiche_Gapps|Ravioli|Ravioli_Gapps)$ ]]; then 36 | export OVERRIDE_OTA_CHANNEL="${BASE_URL}/${DEVICE}-${AOSIP_BUILDTYPE}.json" 37 | fi 38 | else 39 | TARGET="kronic" 40 | fi 41 | 42 | function repo_init() { 43 | repo init -u https://github.com/AOSiP/platform_manifest.git -b "$BRANCH" --no-tags --no-clone-bundle --current-branch 44 | } 45 | 46 | function repo_sync() { 47 | time repo sync -j"$(nproc)" --current-branch --no-tags --no-clone-bundle --force-sync --quiet 48 | } 49 | 50 | function clean_repo() { 51 | repo forall --ignore-missing -j"$(nproc)" -c "git reset --quiet --hard m/$BRANCH && git clean -fdxq" 52 | } 53 | 54 | set -e 55 | notify "${START_MESSAGE}" 56 | export PATH=~/bin:$PATH 57 | PARSE_MODE="html" notify "Starting ${DEVICE} ${AOSIP_BUILDTYPE} $BRANCH build on $NODE_NAME, check progress here!" 58 | 59 | [[ -d "vendor/aosip" ]] || { 60 | repo_init 61 | repo_sync 62 | } 63 | 64 | . build/envsetup.sh 65 | if [[ ${SYNC} == "yes" ]]; then 66 | [[ -d ".repo/local_manifests" ]] && rm -rf .repo/local_manifests 67 | git -C .repo/manifests reset --hard 68 | clean_repo 69 | rm -rf .repo/repo .repo/manifests 70 | repo_init 71 | if [[ -n ${LOCAL_MANIFEST} ]]; then 72 | curl --create-dirs -s -L "${LOCAL_MANIFEST}" -o .repo/local_manifests/aosip_manifest.xml 73 | fi 74 | if [[ -f "jenkins/${DEVICE}-presync" ]]; then 75 | if [[ -z $PRE_SYNC_PICKS ]]; then 76 | PRE_SYNC_PICKS="$(cat jenkins/"${DEVICE}-presync")" 77 | else 78 | PRE_SYNC_PICKS+=" | $(cat jenkins/"${DEVICE}-presync")" 79 | fi 80 | fi 81 | if [[ -n ${PRE_SYNC_PICKS} ]]; then 82 | echo "Trying to pick $PRE_SYNC_PICKS before syncing!" 83 | REPOPICK_LIST="$PRE_SYNC_PICKS" repopick_stuff || { 84 | notify "Pre-sync picks failed" 85 | clean_repo 86 | exit 1 87 | } 88 | fi 89 | repo_sync 90 | fi 91 | 92 | set +e 93 | echo "Lunching $BUILDVARIANT for $DEVICE!" 94 | lunch aosip_"${DEVICE}"-"${BUILDVARIANT}" 95 | if [[ $AOSIP_BUILD != "$DEVICE" ]]; then 96 | notify "Lunching failed!" 97 | exit 1 98 | fi 99 | set -e 100 | 101 | if [[ ${CLEAN} =~ ^(clean|deviceclean|installclean)$ ]]; then 102 | m "${CLEAN}" 103 | else 104 | rm -rf "${OUT}"/AOSiP* 105 | fi 106 | 107 | if [[ -f "jenkins/${DEVICE}" ]]; then 108 | if [[ -z $REPOPICK_LIST ]]; then 109 | REPOPICK_LIST="$(cat jenkins/"${DEVICE}")" 110 | else 111 | REPOPICK_LIST+=" | $(cat jenkins/"${DEVICE}")" 112 | fi 113 | fi 114 | 115 | echo "Trying to pick $REPOPICK_LIST!" 116 | start=$(date +%s) 117 | repopick_stuff || { 118 | notify "Picks failed" 119 | clean_repo 120 | exit 1 121 | } 122 | echo "Took $(($(date +%s) - start)) seconds to pick!" 123 | 124 | USE_CCACHE=1 125 | CCACHE_DIR="${HOME}/.ccache" 126 | CCACHE_EXEC="$(command -v ccache)" 127 | export USE_CCACHE CCACHE_DIR CCACHE_EXEC 128 | ccache -M 500G 129 | if ! m "$TARGET"; then 130 | notify "[$BRANCH build failed for ${DEVICE}](${BUILD_URL})" 131 | notify "$(./jenkins/tag_maintainer.py "$DEVICE")" 132 | exit 1 133 | fi 134 | 135 | notify "${DEVICE} build is done, check [jenkins](${BUILD_URL}) for details!" 136 | notify "${END_MESSAGE}" 137 | 138 | if [[ $TARGET == "kronic" ]]; then 139 | ZIP="AOSiP-$(get_build_var AOSIP_VERSION).zip" 140 | [[ -f "$OUT/$ZIP" ]] || ZIP="AOSiP-$(grep ro.aosip.version "$OUT"/system/etc/prop.default | cut -d= -f2).zip" 141 | cp -v "$OUT/$ZIP" ~/nginx 142 | ssh Illusion "cd /tmp; axel -n8 -q http://$(hostname)/$ZIP; rclone copy -P $ZIP aosip-jenkins:$BUILD_NUMBER; rm -fv $ZIP" 143 | rm -fv ~/nginx/"$ZIP" 144 | FOLDER_LINK="$(ssh Illusion rclone link aosip-jenkins:"$BUILD_NUMBER")" 145 | notify "Build artifacts for job $BUILD_NUMBER can be found [here]($FOLDER_LINK)" 146 | notify "$(./jenkins/message_testers.py "${DEVICE}")" 147 | if [[ -n $REPOPICK_LIST ]]; then 148 | notify "$(python3 ~/scripts/gerrit/parsepicks.py "${REPOPICK_LIST}")" 149 | fi 150 | else 151 | notify "Wait a few minutes for a signed zip to be generated!" 152 | fi 153 | -------------------------------------------------------------------------------- /functions: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (C) 2018-19 Akhil Narang 4 | # SPDX-License-Identifier: GPL-3.0-only 5 | 6 | # Script defining various functions used in the scripts across this repository 7 | 8 | # shellcheck disable=SC1090,SC1091 9 | # SC1090: Can't follow non-constant source. Use a directive to specify location. 10 | 11 | source ~/scripts/aliases 12 | 13 | # Builds a package from the Arch User Repository 14 | function aur() { 15 | git clone https://aur.archlinux.org/"${1}" 16 | cd "${1}" || return 17 | makepkg -si "${2}" 18 | cd - || return 19 | rm -rf "${1}" 20 | } 21 | 22 | # Repopicks a | delimited set of commits 23 | function repopick_stuff() { 24 | export oldifs=$IFS 25 | export IFS="|" 26 | for f in ${REPOPICK_LIST}; do 27 | echo "Picking: $f" 28 | eval repopick "${f}" || return 1 29 | done 30 | export IFS=$oldifs 31 | } 32 | 33 | # Uploads a given file to transfer.sh 34 | function transfer() { 35 | file="${1}" 36 | zipname=$(echo "${file}" | awk -F '/' '{print $NF}') 37 | destination="$2" 38 | url=$(curl -# -T "${file}" https://transfer.sh/"${destination}") 39 | printf '\n' 40 | echo -e "Download $zipname at $url" 41 | } 42 | 43 | # Repo sync with various flags I'm lazy to type each time 44 | function syncc() { 45 | time repo sync --force-sync --no-clone-bundle --current-branch --no-tags "$@" 46 | } 47 | 48 | # Some git aliases for an easier workflow 49 | function gitalias() { 50 | git config --global alias.s 'status' 51 | git config --global alias.p 'push' 52 | git config --global alias.pl 'pull' 53 | git config --global alias.f 'fetch' 54 | git config --global alias.r 'remote' 55 | git config --global alias.rv 'remote --verbose' 56 | git config --global alias.ru 'remote update' 57 | git config --global alias.rrm 'remote remove' 58 | git config --global alias.rsu 'remote set-url' 59 | git config --global alias.ra 'remote add' 60 | git config --global alias.rev 'revert' 61 | git config --global alias.re 'reset' 62 | git config --global alias.cp 'cherry-pick' 63 | git config --global alias.cpc 'cherry-pick --continue' 64 | git config --global alias.cpa 'cherry-pick --abort' 65 | git config --global alias.cps 'cherry-pick --skip' 66 | git config --global alias.rh 'reset --hard' 67 | git config --global alias.rs 'reset --soft' 68 | git config --global alias.rb 'rebase' 69 | git config --global alias.rbi 'rebase --interactive' 70 | git config --global alias.rbc 'rebase --continue' 71 | git config --global alias.rba 'rebase --abort' 72 | git config --global alias.rbs 'rebase --skip' 73 | git config --global alias.d 'diff' 74 | git config --global alias.dc 'diff --cached' 75 | git config --global alias.b 'bisect' 76 | git config --global alias.c 'commit' 77 | git config --global alias.cs 'commit --signoff' 78 | git config --global alias.ca 'commit --amend' 79 | git config --global alias.cn 'commit --no-edit' 80 | git config --global alias.gerrit 'push gerrit HEAD:refs/for/pie' 81 | git config --global alias.add-change-id "!EDITOR='sed -i -re s/^pick/e/' sh -c 'git rebase -i \$1 && while test -f .git/rebase-merge/interactive; do git commit --amend --no-edit && git rebase --continue; done' -" 82 | } 83 | 84 | # Function to display uptime of a system. All credits to the original author. 85 | function upinfo() { 86 | echo -ne "${green}$(hostname) ${red}uptime is ${cyan} \\t " 87 | uptime | awk /'up/ {print $3,$4,$5,$6,$7,$8,$9,$10,$11}' 88 | } 89 | 90 | # Function run on login to display some stuff and set my custom PS1 91 | function onLogin() { 92 | # Colors 93 | green='\e[0;32m' 94 | cyan='\e[0;36m' 95 | red='\e[0;31m' 96 | lightgray='\e[0;37m' 97 | 98 | export GIT_PS1_SHOWDIRTYSTATE=1 99 | export GIT_PS1_SHOWSTASHSTATE=1 100 | export GIT_PS1_SHOWUNTRACKEDFILES=1 101 | export GIT_PS1_SHOWUPSTREAM=auto 102 | export GIT_PS1_SHOWCOLORHINTS=1 103 | unset PS1 104 | #PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' 105 | if [[ -f "${HOME}/git-prompt.sh" ]]; then 106 | source ~/git-prompt.sh 107 | PS1='| \h (\w)$(__git_ps1 " {%s}") |-> ' 108 | else 109 | PS1='| \h (\w) |-> ' 110 | fi 111 | clear 112 | HOST=$(hostname) 113 | if [[ ${#HOST} -lt 14 ]]; then 114 | echo -e "${lightgray}" 115 | figlet -c "$(hostname)" 116 | fi 117 | echo "" 118 | echo -ne "${red}Today is:\\t\\t${cyan} $(date)" 119 | echo "" 120 | echo -e "${red}Kernel Information: \\t${cyan} $(uname -smr)" 121 | echo -ne "${cyan}" 122 | upinfo 123 | echo "" 124 | echo -e "Welcome to $(hostname), $(whoami)!" 125 | echo -e 126 | fortune 127 | } 128 | 129 | # Sends messages to Telegram to a specified chat via the desired bot 130 | function sendTG() { 131 | local bot chat parse_mode msg 132 | bot="${BOT:-kronic}" 133 | chat="${1:-me}" 134 | parse_mode="${PARSE_MODE:-md}" 135 | shift 136 | msg=${*:?} 137 | case "${bot}" in 138 | "ts") BOT_API_KEY="$(cat ~/.tskey)" ;; 139 | "kronic") BOT_API_KEY="$(cat ~/.kronickey)" ;; 140 | "rr") BOT_API_KEY="$(cat ~/.rrkey)" ;; 141 | *) 142 | echo -e "Invalid bot, must be one of ts|kronic|rr!" 143 | return 144 | ;; 145 | esac 146 | 147 | case "${chat}" in 148 | "me") CHAT_ID="92027269" ;; 149 | "kernelberyllium") CHAT_ID="-1001297323361" ;; 150 | "aosip") CHAT_ID="-1001055786180" ;; 151 | *) CHAT_ID="${chat}" ;; 152 | esac 153 | 154 | case "${parse_mode}" in 155 | "md") parse_mode="Markdown" ;; 156 | "html") parse_mode="HTML" ;; 157 | *) 158 | echo -e "Invalid parse mode, must be one of Markdown|HTML!" 159 | return 160 | ;; 161 | esac 162 | curl -s "https://api.telegram.org/bot${BOT_API_KEY}/sendMessage" --data "text=${msg}&chat_id=${CHAT_ID}&parse_mode=${parse_mode}" 1> /dev/null 163 | echo 164 | } 165 | 166 | # Sends a message to my beryllium kernel chat 167 | function sendKernelBeryllium() { 168 | sendTG kernelberyllium "${@}" 169 | } 170 | 171 | # Sends a message to AOSiP Testers group 172 | function sendAOSiP() { 173 | if [[ ${QUIET:-no} == "no" ]]; then 174 | sendTG aosip "${@}" 175 | fi 176 | } 177 | 178 | # Sends me a message on telegram 179 | function tgm() { 180 | sendTG me "${@}" 181 | } 182 | 183 | # Download a file given the Google Drive URL 184 | function gdrivedl() { 185 | local CONFIRM FILE_ID URL 186 | URL="${1}" 187 | shift 188 | if [[ ${URL:?} =~ folders ]]; then 189 | FILE_ID="$(echo "${URL}" | sed -r -e 's/https.*folders\/(.*)/\1/' -e 's/(.*)\?usp=sharing/\1/')" 190 | else 191 | FILE_ID="$(echo "${URL:?}" | sed -r -e 's/(.*)&export.*/\1/' -e 's/https.*id=(.*)/\1/' -e 's/https.*\/d\/(.*)\/view/\1/')" 192 | fi 193 | CONFIRM=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate "https://docs.google.com/uc?export=download&id=$FILE_ID" -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p') 194 | aria2c --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$CONFIRM&id=$FILE_ID" 195 | rm -rf /tmp/cookies.txt 196 | } 197 | 198 | # Upload to GDrive 199 | function gdriveul() { 200 | local FILE MD5 ZIP_SIZE GDRIVE_UPLOAD_URL GDRIVE_UPLOAD_ID UPLOAD_INFO PARENT 201 | FILE="${1}" 202 | [ -f "${FILE:?}" ] || { 203 | echo "Specified file doesn't exist" 204 | return 205 | } 206 | PARENT="${2}" 207 | if [[ -n ${PARENT} ]]; then 208 | PARENT="-p ${PARENT}" 209 | fi 210 | ZIP_SIZE="$(du -h "${FILE}" | awk '{print $1}')" 211 | MD5="$(md5sum "${FILE}" | awk '{print $1}')" 212 | while [ -z "${GDRIVE_UPLOAD_URL}" ]; do 213 | GDRIVE_UPLOAD_URL="$(eval gdrive upload --share "${FILE}" "${PARENT}" | awk '/https/ {print $7}')" 214 | done 215 | GDRIVE_UPLOAD_ID="$(echo "${GDRIVE_UPLOAD_URL}" | sed -r -e 's/(.*)&export.*/\1/' -e 's/https.*id=(.*)/\1/' -e 's/https.*\/d\/(.*)\/view/\1/')" 216 | UPLOAD_INFO=" 217 | File: [$(basename "${FILE}")](${GDRIVE_UPLOAD_URL}) 218 | Size: ${ZIP_SIZE} 219 | MD5: \`${MD5}\` 220 | GDrive ID: \`${GDRIVE_UPLOAD_ID}\` 221 | " 222 | tgm "${UPLOAD_INFO}" 223 | echo "Get the file with ${GDRIVE_UPLOAD_ID}" 224 | } 225 | 226 | # Paste content to katb.in 227 | function katbin() { 228 | local content 229 | if [[ -z "$1" ]]; then 230 | if [[ -t 0 ]]; then 231 | echo "Error: No content provided. Provide as argument or pipe in." 232 | return 1 233 | else 234 | content=$(cat) 235 | fi 236 | else 237 | content="$1" 238 | fi 239 | curl -sL 'https://katb.in/api/paste' --json '{"paste":{"content":"'"$content"'"}}' | jq -r '"https://katb.in/\(.id)"' 240 | } 241 | -------------------------------------------------------------------------------- /misc/extract_and_push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | [[ -z ${API_KEY} ]] && echo "API_KEY not defined, exiting!" && exit 1 4 | [[ -z ${GITLAB_SERVER} ]] && GITLAB_SERVER="dumps.tadiphone.dev" 5 | [[ -z ${PUSH_HOST} ]] && PUSH_HOST="dumps" 6 | [[ -z $ORG ]] && ORG="dumps" 7 | 8 | CHAT_ID="-1001412293127" 9 | 10 | # usage: normal - sendTg normal "message to send" 11 | # reply - sendTg reply message_id "reply to send" 12 | # edit - sendTg edit message_id "new message" ( new message must be different ) 13 | # Uses global var API_KEY 14 | sendTG() { 15 | local mode="${1:?Error: Missing mode}" && shift 16 | local api_url="https://api.telegram.org/bot${API_KEY:?}" 17 | if [[ ${mode} =~ normal ]]; then 18 | curl --compressed -s "${api_url}/sendmessage" --data "text=$(urlEncode "${*:?Error: Missing message text.}")&chat_id=${CHAT_ID:?}&parse_mode=HTML" 19 | elif [[ ${mode} =~ reply ]]; then 20 | local message_id="${1:?Error: Missing message id for reply.}" && shift 21 | curl --compressed -s "${api_url}/sendmessage" --data "text=$(urlEncode "${*:?Error: Missing message text.}")&chat_id=${CHAT_ID:?}&parse_mode=HTML&reply_to_message_id=${message_id}" 22 | elif [[ ${mode} =~ edit ]]; then 23 | local message_id="${1:?Error: Missing message id for edit.}" && shift 24 | curl --compressed -s "${api_url}/editMessageText" --data "text=$(urlEncode "${*:?Error: Missing message text.}")&chat_id=${CHAT_ID:?}&parse_mode=HTML&message_id=${message_id}" 25 | fi 26 | } 27 | 28 | # usage: temporary - To just edit the last message sent but the new content will be overwritten when this function is used again 29 | # sendTG_edit_wrapper temporary "${MESSAGE_ID}" new message 30 | # permanent - To edit the last message sent but also store it permanently, new content will be appended when this function is used again 31 | # sendTG_edit_wrapper permanent "${MESSAGE_ID}" new message 32 | # Uses global var MESSAGE for all message contents 33 | sendTG_edit_wrapper() { 34 | local mode="${1:?Error: Missing mode}" && shift 35 | local message_id="${1:?Error: Missing message id variable}" && shift 36 | case "${mode}" in 37 | temporary) sendTG edit "${message_id}" "${*:?}" > /dev/null ;; 38 | permanent) 39 | MESSAGE="${*:?}" 40 | sendTG edit "${message_id}" "${MESSAGE}" > /dev/null 41 | ;; 42 | esac 43 | } 44 | 45 | # reply to the initial message sent to the group with "Job Done" or "Job Failed!" accordingly 46 | # 1st arg should be either 1 ( error ) or 0 ( success ) 47 | terminate() { 48 | if [[ ${1:?} == "0" ]]; then 49 | local string="Done" 50 | else 51 | local string="Failed!" 52 | fi 53 | sendTG reply "${MESSAGE_ID}" "Job ${string}" 54 | exit "${1:?}" 55 | } 56 | 57 | # https://github.com/dylanaraps/pure-bash-bible#percent-encode-a-string 58 | urlEncode() { 59 | declare LC_ALL=C 60 | for ((i = 0; i < ${#1}; i++)); do 61 | : "${1:i:1}" 62 | case "${_}" in 63 | [a-zA-Z0-9.~_-]) 64 | printf '%s' "${_}" 65 | ;; 66 | *) 67 | printf '%%%02X' "'${_}" 68 | ;; 69 | esac 70 | done 2>| /dev/null 71 | printf '\n' 72 | } 73 | 74 | curl --compressed --fail --silent --location "https://$GITLAB_SERVER" > /dev/null || { 75 | sendTG normal "Can't access $GITLAB_SERVER, cancelling job!" 76 | exit 1 77 | } 78 | 79 | if [[ -f $URL ]]; then 80 | cp -v "$URL" . 81 | MESSAGE="Found file locally." 82 | if _json="$(sendTG normal "${MESSAGE}")"; then 83 | # grab initial message id 84 | MESSAGE_ID="$(jq ".result.message_id" <<< "${_json}")" 85 | else 86 | # disable sendTG and sendTG_edit_wrapper if wasn't able to send initial message 87 | sendTG() { :; } && sendTG_edit_wrapper() { :; } 88 | fi 89 | else 90 | MESSAGE="Started dump" 91 | if _json="$(sendTG normal "${MESSAGE}")"; then 92 | # grab initial message id 93 | MESSAGE_ID="$(jq ".result.message_id" <<< "${_json}")" 94 | else 95 | # disable sendTG and sendTG_edit_wrapper if wasn't able to send initial message 96 | sendTG() { :; } && sendTG_edit_wrapper() { :; } 97 | fi 98 | 99 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Downloading the file.." > /dev/null 100 | downloadError() { 101 | echo "Download failed. Exiting." 102 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Failed to download the file." > /dev/null 103 | terminate 1 104 | } 105 | if [[ $URL =~ drive.google.com ]]; then 106 | echo "Google Drive URL detected" 107 | FILE_ID="$(echo "${URL:?}" | sed -r 's/.*([0-9a-zA-Z_-]{33}).*/\1/')" 108 | echo "File ID is ${FILE_ID}" 109 | CONFIRM=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate "https://docs.google.com/uc?export=download&id=$FILE_ID" -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p') 110 | aria2c --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?export=download&confirm=$CONFIRM&id=$FILE_ID" || downloadError 111 | rm /tmp/cookies.txt 112 | elif [[ $URL =~ mega.nz ]]; then 113 | megadl "'$URL'" || downloadError 114 | else 115 | if [[ $URL =~ ^https://1drv.ms.+$ ]]; then 116 | URL=${URL/ms/ws} 117 | fi 118 | # Try to download certain URLs with axel first 119 | if [[ $URL =~ ^.+(ota\.d\.miui\.com|otafsg|h2os|oxygenos\.oneplus\.net|dl.google|android.googleapis|ozip)(.+)?$ ]]; then 120 | axel -q -a -n64 "$URL" || { 121 | # Try to download with aria, else wget. Clean the directory each time. 122 | aria2c -q -s16 -x16 "${URL}" || { 123 | rm -fv ./* 124 | wget "${URL}" || downloadError 125 | } 126 | } 127 | else 128 | # Try to download with aria, else wget. Clean the directory each time. 129 | aria2c -q -s16 -x16 --check-certificate=false "${URL}" || { 130 | rm -fv ./* 131 | wget --no-check-certificate "${URL}" || downloadError 132 | } 133 | fi 134 | fi 135 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Downloaded the file." > /dev/null 136 | fi 137 | 138 | # Clean query strings if any from URL 139 | oldifs=$IFS 140 | IFS="?" 141 | read -ra CLEANED <<< "${URL}" 142 | URL=${CLEANED[0]} 143 | IFS=$oldifs 144 | 145 | FILE=${URL##*/} 146 | EXTENSION=${URL##*.} 147 | UNZIP_DIR=${FILE/.$EXTENSION/} 148 | export UNZIP_DIR 149 | 150 | if [[ ! -f ${FILE} ]]; then 151 | FILE="$(find . -type f)" 152 | if [[ "$(wc -l <<< "${FILE}")" != 1 ]]; then 153 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Can't seem to find downloaded file!" > /dev/null 154 | terminate 1 155 | fi 156 | fi 157 | 158 | EXTERNAL_TOOLS=( 159 | https://github.com/AndroidDumps/Firmware_extractor 160 | https://github.com/xiaolu/mkbootimg_tools 161 | https://github.com/marin-m/vmlinux-to-elf 162 | ) 163 | 164 | for tool_url in "${EXTERNAL_TOOLS[@]}"; do 165 | tool_path="${HOME}/${tool_url##*/}" 166 | if ! [[ -d ${tool_path} ]]; then 167 | git clone -q "${tool_url}" "${tool_path}" 168 | else 169 | git -C "${tool_path}" pull 170 | fi 171 | done 172 | 173 | sendTG_edit_wrapper temporary "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Extracting firmware.." > /dev/null 174 | bash ~/Firmware_extractor/extractor.sh "${FILE}" "${PWD}" || { 175 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Extraction failed!" > /dev/null 176 | terminate 1 177 | } 178 | 179 | rm -fv "$FILE" 180 | 181 | PARTITIONS=(system systemex system_ext system_other 182 | vendor cust odm oem factory product modem 183 | xrom oppo_product opproduct reserve india 184 | my_preload my_odm my_stock my_operator my_country my_product my_company my_engineering my_heytap 185 | ) 186 | 187 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Extracting partitions .." > /dev/null 188 | # Extract the images 189 | for p in "${PARTITIONS[@]}"; do 190 | if [[ -f $p.img ]]; then 191 | sendTG_edit_wrapper temporary "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Partition Name: ${p}" > /dev/null 192 | mkdir "$p" || rm -rf "${p:?}"/* 193 | 7z x "$p".img -y -o"$p"/ || { 194 | sudo mount -o loop "$p".img "$p" 195 | mkdir "${p}_" 196 | sudo cp -rf "${p}/*" "${p}_" 197 | sudo umount "${p}" 198 | sudo mv "${p}_" "${p}" 199 | } 200 | rm -fv "$p".img 201 | fi 202 | done 203 | 204 | # clear the last partition status 205 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}" > /dev/null 206 | 207 | # Bail out right now if no system build.prop 208 | ls system/build*.prop 2> /dev/null || ls system/system/build*.prop 2> /dev/null || { 209 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"No system build*.prop found, pushing cancelled!" > /dev/null 210 | terminate 1 211 | } 212 | 213 | for image in boot.img dtbo.img; do 214 | if [[ ! -f ${image} ]]; then 215 | x=$(find . -type f -name "${image}") 216 | if [[ -n $x ]]; then 217 | mv -v "$x" "${image}" 218 | else 219 | echo "${image} not found!" 220 | fi 221 | fi 222 | done 223 | 224 | # Extract bootimage and dtbo 225 | if [[ -f "boot.img" ]]; then 226 | mkdir -v bootdts 227 | ~/mkbootimg_tools/mkboot ./boot.img ./bootimg > /dev/null 228 | extract-dtb ./boot.img -o ./bootimg > /dev/null 229 | find bootimg/ -name '*.dtb' -type f -exec dtc -q -I dtb -O dts {} -o bootdts/"$(echo {} | sed 's/\.dtb/.dts/')" \; 230 | # Extract ikconfig 231 | if [[ "$(command -v extract-ikconfig)" ]]; then 232 | extract-ikconfig boot.img > ikconfig 233 | fi 234 | # Kallsyms 235 | python3 ~/vmlinux-to-elf/kallsyms-finder ./bootimg/kernel > kallsyms.txt 236 | # ELF 237 | python3 ~/vmlinux-to-elf/vmlinux-to-elf ./bootimg/kernel boot.elf 238 | fi 239 | if [[ -f "dtbo.img" ]]; then 240 | mkdir -v dtbodts 241 | extract-dtb ./dtbo.img -o ./dtbo > /dev/null 242 | find dtbo/ -name '*.dtb' -type f -exec dtc -I dtb -O dts {} -o dtbodts/"$(echo {} | sed 's/\.dtb/.dts/')" \; > /dev/null 2>&1 243 | fi 244 | 245 | # Oppo/Realme devices have some images in a euclid folder in their vendor, extract those for props 246 | for dir in "vendor/euclid" "system/system/euclid"; do 247 | [[ -d ${dir} ]] && { 248 | pushd "${dir}" || terminate 1 249 | for f in *.img; do 250 | [[ -f $f ]] || continue 251 | sendTG_edit_wrapper temporary "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Partition Name: ${p}" > /dev/null 252 | 7z x "$f" -o"${f/.img/}" 253 | rm -fv "$f" 254 | done 255 | popd || terminate 1 256 | } 257 | done 258 | 259 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"All partitions extracted." > /dev/null 260 | 261 | # board-info.txt 262 | find ./modem -type f -exec strings {} \; | grep "QC_IMAGE_VERSION_STRING=MPSS." | sed "s|QC_IMAGE_VERSION_STRING=MPSS.||g" | cut -c 4- | sed -e 's/^/require version-baseband=/' >> ./board-info.txt 263 | find ./tz* -type f -exec strings {} \; | grep "QC_IMAGE_VERSION_STRING" | sed "s|QC_IMAGE_VERSION_STRING|require version-trustzone|g" >> ./board-info.txt 264 | if [ -f ./vendor/build.prop ]; then 265 | strings ./vendor/build.prop | grep "ro.vendor.build.date.utc" | sed "s|ro.vendor.build.date.utc|require version-vendor|g" >> ./board-info.txt 266 | fi 267 | sort -u -o ./board-info.txt ./board-info.txt 268 | 269 | # Prop extraction 270 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Extracting props.." > /dev/null 271 | 272 | flavor=$(grep -m1 -oP "(?<=^ro.build.flavor=).*" -hs {vendor,system,system/system}/build.prop) 273 | [[ -z ${flavor} ]] && flavor=$(grep -m1 -oP "(?<=^ro.vendor.build.flavor=).*" -hs vendor/build*.prop) 274 | [[ -z ${flavor} ]] && flavor=$(grep -m1 -oP "(?<=^ro.build.flavor=).*" -hs {vendor,system,system/system}/build*.prop) 275 | [[ -z ${flavor} ]] && flavor=$(grep -m1 -oP "(?<=^ro.system.build.flavor=).*" -hs {system,system/system}/build*.prop) 276 | [[ -z ${flavor} ]] && flavor=$(grep -m1 -oP "(?<=^ro.build.type=).*" -hs {system,system/system}/build*.prop) 277 | 278 | release=$(grep -m1 -oP "(?<=^ro.build.version.release=).*" -hs {vendor,system,system/system}/build*.prop) 279 | [[ -z ${release} ]] && release=$(grep -m1 -oP "(?<=^ro.vendor.build.version.release=).*" -hs vendor/build*.prop) 280 | [[ -z ${release} ]] && release=$(grep -m1 -oP "(?<=^ro.system.build.version.release=).*" -hs {system,system/system}/build*.prop) 281 | release=$(echo "$release" | head -1) 282 | 283 | id=$(grep -m1 -oP "(?<=^ro.build.id=).*" -hs {vendor,system,system/system}/build*.prop) 284 | [[ -z ${id} ]] && id=$(grep -m1 -oP "(?<=^ro.vendor.build.id=).*" -hs vendor/build*.prop) 285 | [[ -z ${id} ]] && id=$(grep -m1 -oP "(?<=^ro.system.build.id=).*" -hs {system,system/system}/build*.prop) 286 | id=$(echo "$id" | head -1) 287 | 288 | incremental=$(grep -m1 -oP "(?<=^ro.build.version.incremental=).*" -hs {vendor,system,system/system}/build*.prop | head -1) 289 | [[ -z ${incremental} ]] && incremental=$(grep -m1 -oP "(?<=^ro.vendor.build.version.incremental=).*" -hs vendor/build*.prop) 290 | [[ -z ${incremental} ]] && incremental=$(grep -m1 -oP "(?<=^ro.system.build.version.incremental=).*" -hs {system,system/system}/build*.prop | head -1) 291 | [[ -z ${incremental} ]] && incremental=$(grep -m1 -oP "(?<=^ro.build.version.incremental=).*" -hs my_product/build*.prop) 292 | [[ -z ${incremental} ]] && incremental=$(grep -m1 -oP "(?<=^ro.system.build.version.incremental=).*" -hs my_product/build*.prop) 293 | [[ -z ${incremental} ]] && incremental=$(grep -m1 -oP "(?<=^ro.vendor.build.version.incremental=).*" -hs my_product/build*.prop) 294 | incremental=$(echo "$incremental" | head -1) 295 | 296 | tags=$(grep -m1 -oP "(?<=^ro.build.tags=).*" -hs {vendor,system,system/system}/build*.prop) 297 | [[ -z ${tags} ]] && tags=$(grep -m1 -oP "(?<=^ro.vendor.build.tags=).*" -hs vendor/build*.prop) 298 | [[ -z ${tags} ]] && tags=$(grep -m1 -oP "(?<=^ro.system.build.tags=).*" -hs {system,system/system}/build*.prop) 299 | tags=$(echo "$tags" | head -1) 300 | 301 | platform=$(grep -m1 -oP "(?<=^ro.board.platform=).*" -hs {vendor,system,system/system}/build*.prop | head -1) 302 | [[ -z ${platform} ]] && platform=$(grep -m1 -oP "(?<=^ro.vendor.board.platform=).*" -hs vendor/build*.prop) 303 | [[ -z ${platform} ]] && platform=$(grep -m1 -oP rg"(?<=^ro.system.board.platform=).*" -hs {system,system/system}/build*.prop) 304 | platform=$(echo "$platform" | head -1) 305 | 306 | manufacturer=$(grep -m1 -oP "(?<=^ro.product.manufacturer=).*" -hs odm/etc/fingerprint/build.default.prop) 307 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.manufacturer=).*" -hs my_product/build*.prop) 308 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.manufacturer=).*" -hs {vendor,system,system/system}/build*.prop | head -1) 309 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.brand.sub=).*" -hs my_product/build*.prop) 310 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.brand.sub=).*" -hs system/system/euclid/my_product/build*.prop) 311 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.vendor.product.manufacturer=).*" -hs vendor/build*.prop) 312 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.vendor.manufacturer=).*" -hs vendor/build*.prop) 313 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.system.product.manufacturer=).*" -hs {system,system/system}/build*.prop) 314 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.system.manufacturer=).*" -hs {system,system/system}/build*.prop) 315 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.odm.manufacturer=).*" -hs vendor/odm/etc/build*.prop) 316 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.manufacturer=).*" -hs {oppo_product,my_product}/build*.prop | head -1) 317 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.manufacturer=).*" -hs vendor/euclid/*/build.prop) 318 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.system.product.manufacturer=).*" -hs vendor/euclid/*/build.prop) 319 | [[ -z ${manufacturer} ]] && manufacturer=$(grep -m1 -oP "(?<=^ro.product.product.manufacturer=).*" -hs vendor/euclid/product/build*.prop) 320 | manufacturer=$(echo "$manufacturer" | head -1) 321 | 322 | fingerprint=$(grep -m1 -oP "(?<=^ro.vendor.build.fingerprint=).*" -hs odm/etc/fingerprint/build.default.prop) 323 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.vendor.build.fingerprint=).*" -hs vendor/build.prop) 324 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.build.fingerprint=).*" -hs {system,system/system}/build*.prop) 325 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.product.build.fingerprint=).*" -hs product/build*.prop) 326 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.system.build.fingerprint=).*" -hs {system,system/system}/build*.prop) 327 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.build.fingerprint=).*" -hs my_product/build.prop) 328 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.system.build.fingerprint=).*" -hs my_product/build.prop) 329 | [[ -z ${fingerprint} ]] && fingerprint=$(grep -m1 -oP "(?<=^ro.vendor.build.fingerprint=).*" -hs my_product/build.prop) 330 | fingerprint=$(echo "$fingerprint" | head -1) 331 | 332 | brand=$(grep -m1 -oP "(?<=^ro.product.brand=).*" -hs odm/etc/fingerprint/build.default.prop) 333 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.brand=).*" -hs my_product/build*.prop) 334 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.brand=).*" -hs {vendor,system,system/system}/build*.prop | head -1) 335 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.brand.sub=).*" -hs my_product/build*.prop) 336 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.brand.sub=).*" -hs system/system/euclid/my_product/build*.prop) 337 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.vendor.brand=).*" -hs vendor/build*.prop | head -1) 338 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.vendor.product.brand=).*" -hs vendor/build*.prop | head -1) 339 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.system.brand=).*" -hs {system,system/system}/build*.prop | head -1) 340 | [[ -z ${brand} || ${brand} == "OPPO" ]] && brand=$(grep -m1 -oP "(?<=^ro.product.system.brand=).*" -hs vendor/euclid/*/build.prop | head -1) 341 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.product.brand=).*" -hs vendor/euclid/product/build*.prop) 342 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.odm.brand=).*" -hs vendor/odm/etc/build*.prop) 343 | [[ -z ${brand} ]] && brand=$(grep -m1 -oP "(?<=^ro.product.brand=).*" -hs {oppo_product,my_product}/build*.prop | head -1) 344 | [[ -z ${brand} ]] && brand=$(echo "$fingerprint" | cut -d / -f1) 345 | 346 | codename=$(grep -m1 -oP "(?<=^ro.product.device=).*" -hs odm/etc/fingerprint/build.default.prop) 347 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.device=).*" -hs {vendor,system,system/system}/build*.prop | head -1) 348 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.vendor.product.device.oem=).*" -hs odm/build.prop | head -1) 349 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.vendor.product.device.oem=).*" -hs vendor/euclid/odm/build.prop | head -1) 350 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.vendor.device=).*" -hs vendor/build*.prop | head -1) 351 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.vendor.product.device=).*" -hs vendor/build*.prop | head -1) 352 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.system.device=).*" -hs {system,system/system}/build*.prop | head -1) 353 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.system.device=).*" -hs vendor/euclid/*/build.prop | head -1) 354 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.product.device=).*" -hs vendor/euclid/*/build.prop | head -1) 355 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.product.model=).*" -hs vendor/euclid/*/build.prop | head -1) 356 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.device=).*" -hs {oppo_product,my_product}/build*.prop | head -1) 357 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.product.device=).*" -hs oppo_product/build*.prop) 358 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.system.device=).*" -hs my_product/build*.prop) 359 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.product.vendor.device=).*" -hs my_product/build*.prop) 360 | [[ -z ${codename} ]] && codename=$(grep -m1 -oP "(?<=^ro.build.fota.version=).*" -hs {system,system/system}/build*.prop | cut -d - -f1 | head -1) 361 | [[ -z ${codename} ]] && codename=$(echo "$fingerprint" | cut -d / -f3 | cut -d : -f1) 362 | [[ -z $codename ]] && { 363 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Codename not detected! Aborting!" > /dev/null 364 | terminate 1 365 | } 366 | 367 | description=$(grep -m1 -oP "(?<=^ro.build.description=).*" -hs {system,system/system}/build.prop) 368 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.build.description=).*" -hs {system,system/system}/build*.prop) 369 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.vendor.build.description=).*" -hs vendor/build.prop) 370 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.vendor.build.description=).*" -hs vendor/build*.prop) 371 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.product.build.description=).*" -hs product/build.prop) 372 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.product.build.description=).*" -hs product/build*.prop) 373 | [[ -z ${description} ]] && description=$(grep -m1 -oP "(?<=^ro.system.build.description=).*" -hs {system,system/system}/build*.prop) 374 | [[ -z ${description} ]] && description="$flavor $release $id $incremental $tags" 375 | 376 | is_ab=$(grep -m1 -oP "(?<=^ro.build.ab_update=).*" -hs {system,system/system,vendor}/build*.prop) 377 | is_ab=$(echo "$is_ab" | head -1) 378 | [[ -z ${is_ab} ]] && is_ab="false" 379 | 380 | codename=$(echo "$codename" | tr ' ' '_') 381 | branch=$(echo "$description" | head -1 | tr ' ' '-') 382 | repo_subgroup=$(echo "$brand" | tr '[:upper:]' '[:lower:]') 383 | [[ -z $repo_subgroup ]] && repo_subgroup=$(echo "$manufacturer" | tr '[:upper:]' '[:lower:]') 384 | repo_name=$(echo "$codename" | tr '[:upper:]' '[:lower:]') 385 | repo="$repo_subgroup/$repo_name" 386 | platform=$(echo "$platform" | tr '[:upper:]' '[:lower:]' | tr -dc '[:print:]' | tr '_' '-' | cut -c 1-35) 387 | top_codename=$(echo "$codename" | tr '[:upper:]' '[:lower:]' | tr -dc '[:print:]' | tr '_' '-' | cut -c 1-35) 388 | manufacturer=$(echo "$manufacturer" | tr '[:upper:]' '[:lower:]' | tr -dc '[:print:]' | tr '_' '-' | cut -c 1-35) 389 | 390 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"All props extracted." > /dev/null 391 | 392 | printf "%s\n" "flavor: ${flavor} 393 | release: ${release} 394 | id: ${id} 395 | incremental: ${incremental} 396 | tags: ${tags} 397 | fingerprint: ${fingerprint} 398 | brand: ${brand} 399 | codename: ${codename} 400 | description: ${description} 401 | branch: ${branch} 402 | repo: ${repo} 403 | manufacturer: ${manufacturer} 404 | platform: ${platform} 405 | top_codename: ${top_codename} 406 | is_ab: ${is_ab}" 407 | 408 | if [[ -f "recovery.img" ]]; then 409 | twrpimg=recovery.img 410 | else 411 | twrpimg=boot.img 412 | fi 413 | 414 | if [[ -f $twrpimg ]]; then 415 | echo "Detected $twrpimg! Generating twrp device tree" 416 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Detected $twrpimg! Generating twrp device tree" > /dev/null 417 | if python3 -m twrpdtgen "$twrpimg" --output ./twrp-device-tree -v --no-git; then 418 | if [[ ! -f "working/twrp-device-tree/README.md" ]]; then 419 | curl --compressed https://raw.githubusercontent.com/wiki/SebaUbuntu/TWRP-device-tree-generator/4.-Build-TWRP-from-source.md > twrp-device-tree/README.md 420 | fi 421 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"TWRP device tree successfully generated." > /dev/null 422 | else 423 | echo "Failed to generate twrp tree!" 424 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Failed to generate twrp tree!" > /dev/null 425 | fi 426 | else 427 | echo "Failed to find $twrpimg!" 428 | fi 429 | 430 | # Fix permissions 431 | sudo chown "$(whoami)" ./* -R 432 | sudo chmod -R u+rwX ./* 433 | 434 | # Generate all_files.txt 435 | find . -type f -printf '%P\n' | sort | grep -v ".git/" > ./all_files.txt 436 | 437 | # Check whether the subgroup exists or not 438 | if ! group_id_json="$(curl --compressed -s -H "Authorization: Bearer $DUMPER_TOKEN" "https://$GITLAB_SERVER/api/v4/groups/$ORG%2f$repo_subgroup" -s --fail)"; then 439 | if ! group_id_json="$(curl --compressed -H "Authorization: Bearer $DUMPER_TOKEN" "https://$GITLAB_SERVER/api/v4/groups" -X POST -F name="${repo_subgroup^}" -F parent_id=3 -F path="${repo_subgroup}" -F visibility=public --silent --fail)"; then 440 | echo "Creating subgroup for $repo_subgroup failed" 441 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Creating subgroup for $repo_subgroup failed!" > /dev/null 442 | terminate 1 443 | fi 444 | fi 445 | 446 | if ! group_id="$(jq '.id' -e <<< "${group_id_json}")"; then 447 | echo "Unable to get gitlab group id" 448 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Unable to get gitlab group id!" > /dev/null 449 | terminate 1 450 | fi 451 | 452 | # Create the repo if it doesn't exist 453 | project_id_json="$(curl --compressed --silent -H "Authorization: bearer ${DUMPER_TOKEN}" "https://$GITLAB_SERVER/api/v4/projects/$ORG%2f$repo_subgroup%2f$repo_name")" 454 | if ! project_id="$(jq .id -e <<< "${project_id_json}")"; then 455 | project_id_json="$(curl --compressed --silent -H "Authorization: bearer ${DUMPER_TOKEN}" "https://$GITLAB_SERVER/api/v4/projects" -X POST -F namespace_id="$group_id" -F name="$repo_name" -F visibility=public)" 456 | if ! project_id="$(jq .id -e <<< "${project_id_json}")"; then 457 | echo "Could get get project id" 458 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Could not get project id!" > /dev/null 459 | terminate 1 460 | fi 461 | fi 462 | 463 | branch_json="$(curl --compressed --silent -H "Authorization: bearer ${DUMPER_TOKEN}" "https://$GITLAB_SERVER/api/v4/projects/$project_id/repository/branches/$branch")" 464 | [[ "$(jq -r '.name' -e <<< "${branch_json}")" == "$branch" ]] && { 465 | echo "$branch already exists in $repo" 466 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"$branch already exists in $repo!" > /dev/null 467 | terminate 0 468 | } 469 | 470 | # Add, commit, and push after filtering out certain files 471 | git init 472 | git config user.name "dumper" 473 | git config user.email "dumper@$GITLAB_SERVER" 474 | git checkout -b "$branch" 475 | # find . -size +97M -printf '%P\n' -o -name '*sensetime*' -printf '%P\n' -o -iname '*Megvii*' -printf '%P\n' -o -name '*.lic' -printf '%P\n' -o -name '*zookhrs*' -printf '%P\n' > .gitignore 476 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Committing.." > /dev/null 477 | git add -A 478 | git commit --quiet --signoff --message="$description" 479 | 480 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Pushing.." > /dev/null 481 | git push "$PUSH_HOST:$ORG/$repo.git" HEAD:refs/heads/"$branch" || { 482 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Pushing failed!" > /dev/null 483 | echo "Pushing failed!" 484 | terminate 1 485 | } 486 | 487 | # Set default branch to the newly pushed branch 488 | curl --compressed -s -H "Authorization: bearer ${DUMPER_TOKEN}" "https://$GITLAB_SERVER/api/v4/projects/$project_id" -X PUT -F default_branch="$branch" > /dev/null 489 | 490 | # Send message to Telegram group 491 | sendTG_edit_wrapper permanent "${MESSAGE_ID}" "${MESSAGE}"$'\n'"Pushed $description" > /dev/null 492 | 493 | # Prepare message to be sent to Telegram channel 494 | commit_head=$(git rev-parse HEAD) 495 | commit_link="https://$GITLAB_SERVER/$ORG/$repo/commit/$commit_head" 496 | echo -e "Sending telegram notification" 497 | tg_html_text="Brand: $brand 498 | Device: $codename 499 | Version: $release 500 | Fingerprint: $fingerprint 501 | Git link: 502 | Commit 503 | $codename" 504 | 505 | # Send message to Telegram channel 506 | curl --compressed -s "https://api.telegram.org/bot${API_KEY}/sendmessage" --data "text=${tg_html_text}&chat_id=@android_dumps&parse_mode=HTML&disable_web_page_preview=True" > /dev/null 507 | 508 | terminate 0 509 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | {project} Copyright (C) {year} {fullname} 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------