src/DownloadsData.hx
import haxe.Json;
import haxe.io.Path;
import sys.io.*;
using StringTools;
using Lambda;
typedef Download = {
title : String,
filename : String,
url : String
}
typedef DownloadList = {
osx : DownloadType,
windows : DownloadType,
linux : DownloadType,
all : Array<Download>
}
typedef DownloadType = {
installers : Array<Download>,
archives : Array<Download>
}
typedef Version = {
var version : String;
var tag : String;
var date : String;
@:optional var api : String;
@:optional var next : Version;
@:optional var prev : Version;
@:optional var downloads : DownloadList;
}
typedef Data = {
current : String,
versions : Array<Version>
}
typedef GithubUser = {
login : String,
id : Int,
avatar_url : String,
gravatar_id : String,
url : String,
html_url : String,
followers_url : String,
following_url : String,
gists_url : String,
starred_url : String,
subscriptions_url : String,
organizations_url : String,
repos_url : String,
events_url : String,
received_events_url : String,
type : String,
site_admin : String
};
typedef GithubAsset = {
url : String,
id : Int,
name : String,
label : String,
uploader : GithubUser,
content_type : String,
state : String,
size : Int,
download_count : Int,
created_at : String,
updated_at : String,
browser_download_url : String
};
typedef GithubRelease = {
url : String,
assets_url : String,
upload_url : String,
html_url : String,
id : Int,
tag_name : String,
target_commitish : String,
name : String,
draft : Bool,
author : GithubUser,
prerelease : Bool,
created_at : String,
published_at : String,
assets : Array<GithubAsset>,
tarball_url : String,
zipball_url : String,
body : String
};
class DownloadsData {
static var githubReleases(get, null):Array<GithubRelease>;
static function get_githubReleases():Array<GithubRelease> return githubReleases != null ? githubReleases : githubReleases = {
// Get data from github api
//TODO: for now uses curl, haxe.Http in https doesn't work in --interp, and in neko it doesn't work "ssl@ssl_recv"
var authArgs = switch (Sys.getEnv("GITHUB_AUTH")) {
case null:
[];
case githubAuth: //format is username:token
["-u", githubAuth];
}
#if nodejs
var data = js.node.ChildProcess.spawnSync("curl", authArgs.concat(["https://api.github.com/repos/haxefoundation/haxe/releases?per_page=100"])).stdout;
var releases:Array<GithubRelease> = Json.parse(data);
#else
var data = new Process("curl", authArgs.concat(["https://api.github.com/repos/haxefoundation/haxe/releases?per_page=100"]));
var releases:Array<GithubRelease> = Json.parse(data.stdout.readAll().toString());
data.close();
#end
// Github API will return an object instead when there is an error (rate limit, etc.)
Std.is(releases, Array) ? releases : [];
}
static function getDownloadInfo (version:Version) {
var downloads = {
"osx": { installers: [], archives: [] },
"windows": { installers: [], archives: [] },
"linux": { installers: [], archives: [] },
"all": []
};
function getInfo (title:String, url:String) : Download {
return { title: title, url:url, filename: Path.withoutDirectory(url) };
}
var downloadUrls = [];
var githubRelease = githubReleases.find(function(r) return r.tag_name == version.tag);
if (githubRelease != null) {
downloadUrls = githubRelease.assets.map(function(a) return a.browser_download_url);
} else {
if (Sys.getEnv("GIT_BRANCH") != "master") {
trace('Warning: failed to retrieve download links for version ${version.tag}; skipping assets for this build.');
} else {
throw 'missing github release for version ${version.tag}';
}
}
//TODO: make something a little less horrible here
for (url in downloadUrls) {
var filename = Path.withoutDirectory(url);
var current;
if (filename.endsWith("-linux32.tar.gz") || filename.endsWith("-linux.tar.gz")) {
downloads.linux.archives.unshift(current = getInfo("Linux 32-bit Binaries", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-linux64.tar.gz")) {
downloads.linux.archives.push(current = getInfo("Linux 64-bit Binaries", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-raspi.tar.gz")) {
downloads.linux.archives.push(current = getInfo("Raspberry Pi", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-osx-installer.pkg") || filename.endsWith("-osx-installer.dmg")) {
downloads.osx.installers.unshift(current = getInfo("OS X Installer", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-osx.tar.gz")) {
downloads.osx.archives.push(current = getInfo("OS X Binaries", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-win.exe")) {
downloads.windows.installers.push(current = getInfo("Windows 32-bit Installer", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-win.zip")) {
downloads.windows.archives.push(current = getInfo("Windows 32-bit Binaries", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-win64.exe")) {
downloads.windows.installers.unshift(current = getInfo("Windows 64-bit Installer", url));
downloads.all.unshift(current);
} else if (filename.endsWith("-win64.zip")) {
downloads.windows.archives.unshift(current = getInfo("Windows 64-bit Binaries", url));
downloads.all.unshift(current);
} else if (filename == 'api-${version.version}.zip') {
// Ignored, as we link to api docs instead
} else {
throw('Unknown download type for "$filename"');
}
}
version.downloads = downloads;
}
public static function getData():Data {
var data:Data = Json.parse(File.getContent(Path.join([Config.downloadsPath, "versions.json"])));
var versions = data.versions;
versions.reverse();
// Annotate data
var next = null;
for (version in versions) {
version.next = next;
if (next != null) {
next.prev = version;
}
next = version;
getDownloadInfo(version);
}
return data;
}
}