Add SourceForge release mirror
This commit is contained in:
@@ -109,3 +109,233 @@ jobs:
|
||||
tag_name: ${{ needs.preparation.outputs.version }}
|
||||
target_commitish: ${{ needs.preparation.outputs.commitish }}
|
||||
body: ${{ inputs.release_notes }}
|
||||
|
||||
- name: Prepare SourceForge release
|
||||
shell: bash
|
||||
env:
|
||||
VERSION: ${{ needs.preparation.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
release_dir="$PWD/filtered-bin/release"
|
||||
web_dir="$PWD/filtered-bin/sourceforge-web"
|
||||
mkdir -p "$web_dir/releases"
|
||||
|
||||
expected_files=(
|
||||
"forkop_${VERSION}.ipk"
|
||||
"forkop_${VERSION}.apk"
|
||||
"luci-app-forkop_${VERSION}.ipk"
|
||||
"luci-app-forkop_${VERSION}.apk"
|
||||
"luci-i18n-forkop-ru_${VERSION}.ipk"
|
||||
"luci-i18n-forkop-ru_${VERSION}.apk"
|
||||
)
|
||||
for file_name in "${expected_files[@]}"; do
|
||||
test -s "$release_dir/$file_name"
|
||||
done
|
||||
test "$(find "$release_dir" -maxdepth 1 -type f | wc -l)" -eq "${#expected_files[@]}"
|
||||
|
||||
python3 - install.sh "$web_dir/install.sh" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
source_path = pathlib.Path(sys.argv[1])
|
||||
output_path = pathlib.Path(sys.argv[2])
|
||||
data = source_path.read_bytes()
|
||||
|
||||
def replace_once(old, new):
|
||||
global data
|
||||
if data.count(old) != 1:
|
||||
raise SystemExit(f"expected exactly one installer fragment: {old!r}")
|
||||
data = data.replace(old, new, 1)
|
||||
|
||||
replace_once(
|
||||
b'https://api.github.com/repos/${owner}/${repo}/releases/latest',
|
||||
b'https://forkop.sourceforge.io/releases/latest.json',
|
||||
)
|
||||
replace_once(b'\nSING_BOX_INSTALL_VARIANT=""\n', b'\n')
|
||||
replace_once(
|
||||
b'\nCan also install or switch sing-box variant:\n'
|
||||
b' - stable sing-box from OpenWrt feeds\n'
|
||||
b' - sing-box-extended from GitHub OpenWrt packages (for xHTTP support)\n',
|
||||
b'',
|
||||
)
|
||||
|
||||
translation_keys = (
|
||||
b'sing_box_prompt)',
|
||||
b'sing_box_stable)',
|
||||
b'sing_box_extended)',
|
||||
b'sing_box_skip_msg)',
|
||||
)
|
||||
lines = data.splitlines(keepends=True)
|
||||
for key in translation_keys:
|
||||
if sum(line.lstrip().startswith(key) for line in lines) != 2:
|
||||
raise SystemExit(f"unexpected installer translation count: {key!r}")
|
||||
data = b''.join(
|
||||
line for line in lines
|
||||
if not any(line.lstrip().startswith(key) for key in translation_keys)
|
||||
)
|
||||
|
||||
start_marker = b'\nsing_box_is_present() {\n'
|
||||
end_marker = b'\ncleanup_legacy_installation() {\n'
|
||||
if data.count(start_marker) != 1 or data.count(end_marker) != 1:
|
||||
raise SystemExit("unexpected sing-box installer function boundaries")
|
||||
start = data.index(start_marker)
|
||||
end = data.index(end_marker, start)
|
||||
data = data[:start] + data[end:]
|
||||
|
||||
replace_once(b' select_sing_box_installation\n', b'')
|
||||
replace_once(b' install_selected_sing_box\n', b'')
|
||||
|
||||
forbidden = (
|
||||
b'SING_BOX_INSTALL_VARIANT',
|
||||
b'select_sing_box_installation',
|
||||
b'install_selected_sing_box',
|
||||
b'sing_box_extended',
|
||||
b'sing-box-extended',
|
||||
b'component_action sing_box',
|
||||
)
|
||||
for fragment in forbidden:
|
||||
if fragment in data:
|
||||
raise SystemExit(f"SourceForge installer retains sing-box selection code: {fragment!r}")
|
||||
|
||||
output_path.write_bytes(data)
|
||||
PY
|
||||
sh -n "$web_dir/install.sh"
|
||||
|
||||
python3 - "$VERSION" "$release_dir" "$web_dir/releases/latest.json" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
version = sys.argv[1]
|
||||
release_dir = pathlib.Path(sys.argv[2])
|
||||
output_path = pathlib.Path(sys.argv[3])
|
||||
base_url = f"https://downloads.sourceforge.net/project/forkop/releases/{version}"
|
||||
assets = []
|
||||
for path in sorted(release_dir.iterdir(), key=lambda item: item.name):
|
||||
assets.append({
|
||||
"name": path.name,
|
||||
"browser_download_url": f"{base_url}/{path.name}",
|
||||
"sha256": hashlib.sha256(path.read_bytes()).hexdigest(),
|
||||
})
|
||||
output_path.write_text(
|
||||
json.dumps({"tag_name": version, "assets": assets}, indent=2) + "\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
PY
|
||||
|
||||
- name: Configure SourceForge SSH
|
||||
shell: bash
|
||||
env:
|
||||
SOURCEFORGE_SSH_PRIVATE_KEY: ${{ secrets.SOURCEFORGE_SSH_PRIVATE_KEY }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
test -n "$SOURCEFORGE_SSH_PRIVATE_KEY"
|
||||
install -d -m 0700 "$HOME/.ssh"
|
||||
printf '%s\n' "$SOURCEFORGE_SSH_PRIVATE_KEY" > "$HOME/.ssh/sourceforge"
|
||||
chmod 0600 "$HOME/.ssh/sourceforge"
|
||||
|
||||
ssh-keyscan -t ed25519 frs.sourceforge.net web.sourceforge.net > "$HOME/.ssh/known_hosts"
|
||||
fingerprints="$(ssh-keygen -lf "$HOME/.ssh/known_hosts" -E sha256 | awk '{print $2}')"
|
||||
test "$(printf '%s\n' "$fingerprints" | grep -c .)" -ge 2
|
||||
if printf '%s\n' "$fingerprints" | grep -vxF 'SHA256:209BDmH3jsRyO9UeGPPgLWPSegKmYCBIya0nR/AWWCY'; then
|
||||
echo "Unexpected SourceForge SSH host fingerprint" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload SourceForge packages
|
||||
shell: bash
|
||||
env:
|
||||
VERSION: ${{ needs.preparation.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
sftp -i "$HOME/.ssh/sourceforge" -b - ushan0v@frs.sourceforge.net <<EOF
|
||||
-mkdir /home/frs/project/forkop/releases
|
||||
-mkdir /home/frs/project/forkop/releases/${VERSION}
|
||||
put $PWD/filtered-bin/release/* /home/frs/project/forkop/releases/${VERSION}/
|
||||
EOF
|
||||
|
||||
- name: Verify SourceForge package downloads
|
||||
shell: bash
|
||||
env:
|
||||
VERSION: ${{ needs.preparation.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
for package_path in "$PWD"/filtered-bin/release/*; do
|
||||
package_name="$(basename "$package_path")"
|
||||
package_url="https://downloads.sourceforge.net/project/forkop/releases/${VERSION}/${package_name}"
|
||||
download_path="$(mktemp)"
|
||||
verified=0
|
||||
for attempt in $(seq 1 12); do
|
||||
if curl --connect-timeout 15 --max-time 120 -fsSL \
|
||||
"${package_url}?run=${GITHUB_RUN_ID}&attempt=${attempt}" \
|
||||
-o "$download_path" && cmp -s "$package_path" "$download_path"; then
|
||||
verified=1
|
||||
break
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
rm -f "$download_path"
|
||||
if [ "$verified" -ne 1 ]; then
|
||||
echo "SourceForge package verification failed: $package_name" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Publish SourceForge installer metadata
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
web_dir="$PWD/filtered-bin/sourceforge-web"
|
||||
sftp -i "$HOME/.ssh/sourceforge" -b - ushan0v@web.sourceforge.net <<EOF
|
||||
-mkdir /home/project-web/forkop/htdocs/releases
|
||||
put ${web_dir}/install.sh /home/project-web/forkop/htdocs/install.sh.new
|
||||
rename /home/project-web/forkop/htdocs/install.sh.new /home/project-web/forkop/htdocs/install.sh
|
||||
put ${web_dir}/releases/latest.json /home/project-web/forkop/htdocs/releases/latest.json.new
|
||||
rename /home/project-web/forkop/htdocs/releases/latest.json.new /home/project-web/forkop/htdocs/releases/latest.json
|
||||
EOF
|
||||
|
||||
- name: Verify SourceForge installer metadata
|
||||
shell: bash
|
||||
env:
|
||||
VERSION: ${{ needs.preparation.outputs.version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
web_dir="$PWD/filtered-bin/sourceforge-web"
|
||||
cache_buster="version=${VERSION}&run=${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
||||
|
||||
verify_public_file() {
|
||||
url="$1"
|
||||
expected_path="$2"
|
||||
downloaded_path="$3"
|
||||
|
||||
for attempt in $(seq 1 12); do
|
||||
if curl --connect-timeout 15 --max-time 120 -fsSL \
|
||||
"${url}?${cache_buster}&attempt=${attempt}" \
|
||||
-o "$downloaded_path" && cmp -s "$expected_path" "$downloaded_path"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
verify_public_file \
|
||||
"https://forkop.sourceforge.io/install.sh" \
|
||||
"$web_dir/install.sh" \
|
||||
"$web_dir/published-install.sh"
|
||||
verify_public_file \
|
||||
"https://forkop.sourceforge.io/releases/latest.json" \
|
||||
"$web_dir/releases/latest.json" \
|
||||
"$web_dir/releases/published-latest.json"
|
||||
|
||||
- name: Remove SourceForge SSH key
|
||||
if: ${{ always() }}
|
||||
shell: bash
|
||||
run: rm -f "$HOME/.ssh/sourceforge"
|
||||
|
||||
@@ -13,6 +13,15 @@
|
||||
sh <(wget -O - https://raw.githubusercontent.com/ushan0v/forkop/main/install.sh)
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><sub>Альтернативный способ установки</sub></summary>
|
||||
|
||||
```sh
|
||||
sh <(wget -O - https://forkop.sourceforge.io/install.sh)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Что нового в этом форке
|
||||
|
||||
* Поддержка подписок.
|
||||
|
||||
Reference in New Issue
Block a user