Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9121b54fb3 | |||
| bb4ddb0ea5 | |||
| c6fd78e76f |
3 changed files with 86 additions and 27 deletions
|
|
@ -16,15 +16,17 @@ jobs:
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
apt-get update -qq
|
apt-get update
|
||||||
apt-get install -y -qq make git wget unzip
|
apt-get install -y -qq make git wget
|
||||||
|
|
||||||
- name: Install Godot
|
- name: Install Godot
|
||||||
run: |
|
run: |
|
||||||
wget -q https://github.com/godotengine/godot/releases/download/4.4.1-stable/Godot_v4.4.1-stable_linux.x86_64.zip
|
wget -q https://github.com/godotengine/godot/releases/download/4.4.1-stable/Godot_v4.4.1-stable_linux.x86_64.zip
|
||||||
unzip -q Godot_v4.4.1-stable_linux.x86_64.zip
|
# python3 instead of unzip: the runner's apt index goes stale and the
|
||||||
|
# pinned unzip deb 404s in the security pool.
|
||||||
|
python3 -m zipfile -e Godot_v4.4.1-stable_linux.x86_64.zip godot-dir
|
||||||
mkdir -p "$HOME/.local/bin"
|
mkdir -p "$HOME/.local/bin"
|
||||||
mv Godot_v4.4.1-stable_linux.x86_64 "$HOME/.local/bin/godot"
|
mv godot-dir/Godot_v4.4.1-stable_linux.x86_64 "$HOME/.local/bin/godot"
|
||||||
chmod +x "$HOME/.local/bin/godot"
|
chmod +x "$HOME/.local/bin/godot"
|
||||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
|
@ -41,21 +43,32 @@ jobs:
|
||||||
TAG="${GITHUB_REF_NAME}"
|
TAG="${GITHUB_REF_NAME}"
|
||||||
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
API="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
||||||
|
|
||||||
# Create the release
|
# Create the release. `curl -sf` hid the reason a tag build could not
|
||||||
curl -sf -X POST "${API}/releases" \
|
# publish, which left devices on the previous release with no clue,
|
||||||
|
# so report the status code and the API answer.
|
||||||
|
HTTP=$(curl -sS -o /tmp/release.json -w "%{http_code}" -X POST "${API}/releases" \
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\"}" \
|
-d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\"}")
|
||||||
-o /tmp/release.json
|
if [ "${HTTP}" != "201" ] && [ "${HTTP}" != "200" ]; then
|
||||||
|
echo "Release creation for ${TAG} failed with HTTP ${HTTP}:"
|
||||||
|
cat /tmp/release.json
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
RELEASE_ID=$(python3 -c "import json; print(json.load(open('/tmp/release.json'))['id'])")
|
RELEASE_ID=$(python3 -c "import json; print(json.load(open('/tmp/release.json'))['id'])")
|
||||||
|
|
||||||
# Upload assets
|
# Upload assets
|
||||||
for FILE in dist/itch.zip dist/itch.zip.sha256.txt; do
|
for FILE in dist/itch.zip dist/itch.zip.sha256.txt; do
|
||||||
NAME=$(basename "$FILE")
|
NAME=$(basename "$FILE")
|
||||||
curl -sf -X POST \
|
HTTP=$(curl -sS -o /tmp/asset.json -w "%{http_code}" -X POST \
|
||||||
"${API}/releases/${RELEASE_ID}/assets?name=${NAME}" \
|
"${API}/releases/${RELEASE_ID}/assets?name=${NAME}" \
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
-H "Authorization: token ${GITHUB_TOKEN}" \
|
||||||
-H "Content-Type: application/octet-stream" \
|
-H "Content-Type: application/octet-stream" \
|
||||||
--data-binary "@${FILE}"
|
--data-binary "@${FILE}")
|
||||||
|
if [ "${HTTP}" != "201" ] && [ "${HTTP}" != "200" ]; then
|
||||||
|
echo "Asset upload of ${NAME} failed with HTTP ${HTTP}:"
|
||||||
|
cat /tmp/asset.json
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,8 @@ func _ready() -> void:
|
||||||
bootstrap()
|
bootstrap()
|
||||||
|
|
||||||
|
|
||||||
## Bootstraps the butler binary if it isn't present, then spawns butlerd.
|
## Bootstraps the butler binary (downloading it when missing or outdated), then
|
||||||
|
## spawns butlerd.
|
||||||
func bootstrap() -> void:
|
func bootstrap() -> void:
|
||||||
var butler_dir_global := ProjectSettings.globalize_path(butler_dir)
|
var butler_dir_global := ProjectSettings.globalize_path(butler_dir)
|
||||||
_migrate_butler(butler_dir_global)
|
_migrate_butler(butler_dir_global)
|
||||||
|
|
@ -96,6 +97,12 @@ func bootstrap() -> void:
|
||||||
bootstrap_finished.emit()
|
bootstrap_finished.emit()
|
||||||
return
|
return
|
||||||
logger.info("Successfully installed butler")
|
logger.info("Successfully installed butler")
|
||||||
|
elif await _butler_is_outdated(butler_bin):
|
||||||
|
logger.info("Updating the butler binary to " + str(await _fetch_latest_butler_version()) + ".")
|
||||||
|
var success := await _install_butler()
|
||||||
|
if not success:
|
||||||
|
# Not fatal: the installed butler still works, it is just behind.
|
||||||
|
logger.warn("Unable to update butler, keeping the installed one.")
|
||||||
|
|
||||||
var dbpath := "/".join([butler_dir_global, "butler.db"])
|
var dbpath := "/".join([butler_dir_global, "butler.db"])
|
||||||
var args := [
|
var args := [
|
||||||
|
|
@ -139,9 +146,8 @@ func _migrate_butler(dest_dir: String) -> void:
|
||||||
logger.info("Migrated butler from " + old_dir + " to " + dest_dir)
|
logger.info("Migrated butler from " + old_dir + " to " + dest_dir)
|
||||||
|
|
||||||
|
|
||||||
## Downloads a butler binary for this platform from itch's broth distribution
|
## broth's slug for the platform we are running on, e.g. "linux-amd64".
|
||||||
## channel (the same one the official itch.io app uses to self-update).
|
func _butler_platform_slug() -> String:
|
||||||
func _install_butler() -> bool:
|
|
||||||
var goos := "linux"
|
var goos := "linux"
|
||||||
var goarch := "amd64"
|
var goarch := "amd64"
|
||||||
if OS.get_name() == "Windows":
|
if OS.get_name() == "Windows":
|
||||||
|
|
@ -155,10 +161,13 @@ func _install_butler() -> bool:
|
||||||
var arch: String = Engine.get_architecture_name()
|
var arch: String = Engine.get_architecture_name()
|
||||||
if "arm64" in arch or "aarch64" in arch:
|
if "arm64" in arch or "aarch64" in arch:
|
||||||
goarch = "arm64"
|
goarch = "arm64"
|
||||||
|
return goos + "-" + goarch
|
||||||
|
|
||||||
var platform_slug := goos + "-" + goarch
|
|
||||||
var latest_url := "/".join([broth_base, platform_slug, "LATEST"])
|
|
||||||
|
|
||||||
|
## Asks itch's broth channel which butler version is current. Returns "" when
|
||||||
|
## the channel can't be reached, so callers can tell "unknown" from "current".
|
||||||
|
func _fetch_latest_butler_version() -> String:
|
||||||
|
var latest_url := "/".join([broth_base, _butler_platform_slug(), "LATEST"])
|
||||||
var http := HTTPRequest.new()
|
var http := HTTPRequest.new()
|
||||||
add_child.call_deferred(http)
|
add_child.call_deferred(http)
|
||||||
await http.ready
|
await http.ready
|
||||||
|
|
@ -166,28 +175,65 @@ func _install_butler() -> bool:
|
||||||
logger.error("Error fetching latest butler version: " + latest_url)
|
logger.error("Error fetching latest butler version: " + latest_url)
|
||||||
remove_child(http)
|
remove_child(http)
|
||||||
http.queue_free()
|
http.queue_free()
|
||||||
return false
|
return ""
|
||||||
var args: Array = await http.request_completed
|
var args: Array = await http.request_completed
|
||||||
var result: int = args[0]
|
var result: int = args[0]
|
||||||
var response_code: int = args[1]
|
var response_code: int = args[1]
|
||||||
var body: PackedByteArray = args[3]
|
var body: PackedByteArray = args[3]
|
||||||
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
|
||||||
logger.error("Unable to determine latest butler version for " + platform_slug)
|
|
||||||
remove_child(http)
|
remove_child(http)
|
||||||
http.queue_free()
|
http.queue_free()
|
||||||
return false
|
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
||||||
var version := body.get_string_from_utf8().strip_edges()
|
logger.error("Unable to determine the latest butler version")
|
||||||
|
return ""
|
||||||
|
return body.get_string_from_utf8().strip_edges()
|
||||||
|
|
||||||
|
|
||||||
|
## Reads the version of an installed butler binary, e.g. "15.30.0" out of
|
||||||
|
## "v15.30.0, built on Jul 27 2026". Returns "" when the binary can't be run.
|
||||||
|
func _butler_installed_version(butler_bin: String) -> String:
|
||||||
|
var out := []
|
||||||
|
if OS.execute(butler_bin, ["version"], out) != OK or out.is_empty():
|
||||||
|
return ""
|
||||||
|
var reported: String = (out[0] as String).strip_edges().get_slice(",", 0)
|
||||||
|
return reported.trim_prefix("v").strip_edges()
|
||||||
|
|
||||||
|
|
||||||
|
## True when the installed butler is behind broth's current version. The
|
||||||
|
## binary used to be downloaded only when missing, so it silently rotted for
|
||||||
|
## months and missed fixes. Unknown version (channel unreachable, binary not
|
||||||
|
## runnable) counts as up to date: never replace a working butler on a guess.
|
||||||
|
func _butler_is_outdated(butler_bin: String) -> bool:
|
||||||
|
var latest := await _fetch_latest_butler_version()
|
||||||
|
if latest == "":
|
||||||
|
return false
|
||||||
|
var installed := _butler_installed_version(butler_bin)
|
||||||
|
if installed == "" or installed == latest:
|
||||||
|
return false
|
||||||
|
logger.info("butler " + installed + " is behind " + latest + ". Updating it.")
|
||||||
|
return true
|
||||||
|
|
||||||
|
|
||||||
|
## Downloads a butler binary for this platform from itch's broth distribution
|
||||||
|
## channel (the same one the official itch.io app uses to self-update).
|
||||||
|
func _install_butler() -> bool:
|
||||||
|
var platform_slug := _butler_platform_slug()
|
||||||
|
var version := await _fetch_latest_butler_version()
|
||||||
|
if version == "":
|
||||||
|
return false
|
||||||
|
|
||||||
|
var http := HTTPRequest.new()
|
||||||
|
add_child.call_deferred(http)
|
||||||
|
await http.ready
|
||||||
var archive_url := "/".join([broth_base, platform_slug, version, "archive", "default"])
|
var archive_url := "/".join([broth_base, platform_slug, version, "archive", "default"])
|
||||||
if http.request(archive_url) != OK:
|
if http.request(archive_url) != OK:
|
||||||
logger.error("Error downloading butler: " + archive_url)
|
logger.error("Error downloading butler: " + archive_url)
|
||||||
remove_child(http)
|
remove_child(http)
|
||||||
http.queue_free()
|
http.queue_free()
|
||||||
return false
|
return false
|
||||||
args = await http.request_completed
|
var args: Array = await http.request_completed
|
||||||
result = args[0]
|
var result: int = args[0]
|
||||||
response_code = args[1]
|
var response_code: int = args[1]
|
||||||
body = args[3]
|
var body: PackedByteArray = args[3]
|
||||||
remove_child(http)
|
remove_child(http)
|
||||||
http.queue_free()
|
http.queue_free()
|
||||||
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
if result != HTTPRequest.RESULT_SUCCESS or response_code != 200:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"plugin.id": "itch",
|
"plugin.id": "itch",
|
||||||
"plugin.name": "itch.io",
|
"plugin.name": "itch.io",
|
||||||
"plugin.version": "0.1.41",
|
"plugin.version": "0.1.43",
|
||||||
"plugin.min-api-version": "1.1.0",
|
"plugin.min-api-version": "1.1.0",
|
||||||
"plugin.link": "https://forge.thergic.ar/jose/itchio-opengamepadui-plugin",
|
"plugin.link": "https://forge.thergic.ar/jose/itchio-opengamepadui-plugin",
|
||||||
"plugin.source": "https://forge.thergic.ar/jose/itchio-opengamepadui-plugin",
|
"plugin.source": "https://forge.thergic.ar/jose/itchio-opengamepadui-plugin",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue