Skip to content

Commit

Permalink
move location of the index.json file
Browse files Browse the repository at this point in the history
  • Loading branch information
Techatrix committed Nov 4, 2024
1 parent 848d4fa commit 9bd5b10
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 239 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- run: npm run lint
- run: npm run format -- --check
- run: npm run coverage

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,18 @@ This error only occurs on tagged releases of Zig.

## /v1/zls/index.json

The response body imitates Zig's [index.json](https://ziglang.org/download/index.json) except that there is no field for `master`. Development builds of ZLS should be queried by supplying the Zig version that is being used.
> [!CAUTION]
> This request has been moved to [index.json](https://builds.zigtools.org/index.json)
## index.json

The [index.json](https://builds.zigtools.org/index.json) imitates Zig's [index.json](https://ziglang.org/download/index.json) except that there is no field for `master`. Development builds of ZLS should be queried by supplying the Zig version that is being used.

<details>
<summary>Show Example</summary>

```bash
curl "https://releases.zigtools.org/v1/zls/index.json"
curl "https://builds.zigtools.org/index.json"
```

```json
Expand Down
5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Env } from "./env";
import { handlePublish } from "./publish";
import { handleSelectVersion, handleZLSIndex } from "./select-zls-version";
import { handleSelectVersion } from "./select-zls-version";

export default {
async fetch(request, env, _ctx) {
Expand All @@ -13,8 +13,7 @@ export default {
response = await handleSelectVersion(request, env);
break;
case "/v1/zls/index.json":
response = await handleZLSIndex(request, env);
break;
return Response.redirect(`${env.R2_PUBLIC_URL}/index.json`, 301);
case "/v1/zls/publish":
response = await handlePublish(request, env);
break;
Expand Down
49 changes: 38 additions & 11 deletions src/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
Extension,
ReleaseArtifact,
VersionCompatibility,
ZLSIndex,
artifactsToRecord,
getMagicNumberOfExtension,
} from "./shared";
import { SemanticVersion } from "./semantic-version";
Expand Down Expand Up @@ -476,16 +478,22 @@ export async function handlePublish(
}
}

let skipArtifactUpload;
const taggedReleases = await env.ZIGTOOLS_DB.prepare(
// update the "explain query plan when searching all tagged releases" test when modifying the query
"SELECT ZLSVersion, JsonData FROM ZLSReleases WHERE IsRelease = 1 ORDER BY ZLSVersionMajor DESC, ZLSVersionMinor DESC, ZLSVersionPatch DESC",
).all<{ ZLSVersion: string; JsonData: string }>();

let artifactsAlreadyExist: boolean;
if (zlsVersion.isRelease) {
const result = await env.ZIGTOOLS_DB.prepare(
"SELECT ZLSVersion,JsonData FROM ZLSReleases WHERE ZLSVersion = ?1",
)
.bind(zlsVersionString)
.first<{ ZLSVersion: string }>();

skipArtifactUpload = result !== null;
artifactsAlreadyExist = taggedReleases.results
.map(({ ZLSVersion }) => ZLSVersion)
.includes(zlsVersionString);
if (!artifactsAlreadyExist) {
taggedReleases.results.push({
ZLSVersion: zlsVersionString,
JsonData: JSON.stringify(newEntryValue),
});
}
} else {
assert(zlsVersion.commitHeight !== undefined);
const result = await env.ZIGTOOLS_DB.prepare(
Expand All @@ -499,7 +507,7 @@ export async function handlePublish(
)
.first<{ ZLSVersion: string }>();

skipArtifactUpload = result !== null;
artifactsAlreadyExist = result !== null;

if (result !== null && zlsVersionString !== result.ZLSVersion) {
return new Response(
Expand Down Expand Up @@ -535,9 +543,28 @@ export async function handlePublish(
),
]);

if (skipArtifactUpload) return new Response();
if (artifactsAlreadyExist) return new Response();

const promises: Promise<unknown>[] = [];

const promises: Promise<R2Object>[] = [];
{
const index: ZLSIndex = {};

for (const entry of taggedReleases.results) {
const jsonData = JSON.parse(entry.JsonData) as D2JsonData;
index[jsonData.zlsVersion] = {
date: new Date(jsonData.date).toISOString().slice(0, 10),
...artifactsToRecord(env.R2_PUBLIC_URL, jsonData.artifacts),
};
}

promises.push(
env.ZIGTOOLS_BUILDS.put(
"index.json",
JSON.stringify(index, undefined, 2),
),
);
}

for (let i = 0; i < artifacts.length; i++) {
const artifact = artifacts[i];
Expand Down
104 changes: 15 additions & 89 deletions src/select-zls-version.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import assert from "node:assert";
import { Env } from "./env";
import { Order, SemanticVersion } from "./semantic-version";
import { D2JsonData, ReleaseArtifact, VersionCompatibility } from "./shared";
import {
ArtifactEntry,
D2JsonData,
VersionCompatibility,
artifactsToRecord,
} from "./shared";

/**
* Similar to https://ziglang.org/download/index.json
Expand Down Expand Up @@ -81,52 +86,6 @@ function selectZLSVersionFailureCodeToString(
}
}

/**
* Similar to https://ziglang.org/download/index.json
*/
export type ZLSIndexResponse = Record<
string,
{
/** `YYYY-MM-DD` */
date: string;
[artifact: string]: ArtifactEntry | string | undefined;
}
>;

export interface ArtifactEntry {
/** A download URL */
tarball: string;
/** A SHA256 hash of the tarball */
shasum: string;
/** Size of the tarball in bytes */
size: string;
}

function artifactsToRecord(
env: Env,
artifacts: ReleaseArtifact[],
): Record<string, ArtifactEntry> {
assert(artifacts.length !== 0);
const targets: Record<string, ArtifactEntry> = {};
for (const artifact of artifacts) {
switch (artifact.extension) {
case "tar.gz":
continue;
case "tar.xz":
case "zip":
break;
}
assert(!(`${artifact.arch}-${artifact.os}` in targets));
assert.strictEqual(artifact.fileShasum.length, 64);
targets[`${artifact.arch}-${artifact.os}`] = {
tarball: `${env.R2_PUBLIC_URL}/zls-${artifact.os}-${artifact.arch}-${artifact.version}.${artifact.extension}`,
shasum: artifact.fileShasum,
size: artifact.fileSize.toString(),
};
}
return targets;
}

function failure(status: number, message: string): Response {
return Response.json(
{
Expand All @@ -138,41 +97,6 @@ function failure(status: number, message: string): Response {
);
}

/** `${ENDPOINT}/zls/index.json` */
export async function handleZLSIndex(
request: Request,
env: Env,
): Promise<Response> {
if (request.method !== "GET") {
return failure(405, "method must be 'GET'"); // Method Not Allowed
}

if (typeof env.R2_PUBLIC_URL !== "string" || !env.R2_PUBLIC_URL) {
return failure(500, "Internal Server Error"); // Internal Server Error
}

const releases = await env.ZIGTOOLS_DB.prepare(
// update the "explain query plan when searching all tagged releases" test when modifying the query
"SELECT JsonData FROM ZLSReleases WHERE IsRelease = 1 ORDER BY ZLSVersionMajor DESC, ZLSVersionMinor DESC, ZLSVersionPatch DESC",
).all<{ JsonData: string }>();

const response: ZLSIndexResponse = {};

for (const entry of releases.results) {
const jsonData = JSON.parse(entry.JsonData) as D2JsonData;
response[jsonData.zlsVersion] = {
date: new Date(jsonData.date).toISOString().slice(0, 10),
...artifactsToRecord(env, jsonData.artifacts),
};
}

return Response.json(response, {
headers: {
"cache-control": "public, max-age=3600", // 1 hour
},
});
}

/** `${ENDPOINT}/zls/select-version?zig_version=0.12.0&compatibility=full` */
export async function handleSelectVersion(
request: Request,
Expand Down Expand Up @@ -238,7 +162,7 @@ export async function handleSelectVersion(
response = {
version: selectedVersion.zlsVersion,
date: new Date(selectedVersion.date).toISOString().slice(0, 10),
...artifactsToRecord(env, selectedVersion.artifacts),
...artifactsToRecord(env.R2_PUBLIC_URL, selectedVersion.artifacts),
};
}

Expand Down Expand Up @@ -366,9 +290,11 @@ async function selectOnDevelopmentBuild(
const developmentReleases = await env.ZIGTOOLS_DB.prepare(
// update the "explain query plan when searching on development built" test when modifying the query
"SELECT JsonData FROM ZLSReleases WHERE IsRelease = 0 AND ZLSVersionMajor = ?1 AND ZLSVersionMinor = ?2 ORDER BY ZLSVersionBuildID ASC",
).bind(zigVersion.major, zigVersion.minor).all<{ JsonData: string; }>();
)
.bind(zigVersion.major, zigVersion.minor)
.all<{ JsonData: string }>();

let releases: { JsonData: string; }[] = [];
let releases: { JsonData: string }[] = [];
if (developmentReleases.results.length !== 0) {
releases = developmentReleases.results;
} else {
Expand All @@ -378,16 +304,16 @@ async function selectOnDevelopmentBuild(
// 3. ZLS has tagged a new release (e.g `0.13.0`)
// 4. but no ZLS development builds have come out!
//
// Querying with `0.13.0-dev.1+aaaaaaa` should return `0.13.0`. This
// should only happen for the latest tagged release while previous
// Querying with `0.13.0-dev.1+aaaaaaa` should return `0.13.0`. This
// should only happen for the latest tagged release while previous
// releases will report 'unsupported'.
//
// This is why only the latest tagged release is selected.
const latestTaggedRelease = await env.ZIGTOOLS_DB.prepare(
// update the "explain query plan when searching all tagged releases" test when modifying the query
"SELECT JsonData FROM ZLSReleases WHERE IsRelease = 1 ORDER BY ZLSVersionMajor DESC, ZLSVersionMinor DESC, ZLSVersionPatch DESC",
).first<{ JsonData: string; }>();
releases = (latestTaggedRelease != null) ? [latestTaggedRelease] : [];
).first<{ JsonData: string }>();
releases = latestTaggedRelease != null ? [latestTaggedRelease] : [];
}

if (releases.length == 0) {
Expand Down
47 changes: 47 additions & 0 deletions src/shared.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Buffer } from "node:buffer";
import assert from "node:assert";

export const xzMagicNumber = Buffer.from("FD377A585A00", "hex");
export const gzipMagicNumber = Buffer.from("1F8B", "hex");
Expand Down Expand Up @@ -40,6 +41,27 @@ export interface ReleaseArtifact {

export type Extension = "tar.xz" | "tar.gz" | "zip";

/**
* Similar to https://ziglang.org/download/index.json
*/
export type ZLSIndex = Record<
string,
{
/** `YYYY-MM-DD` */
date: string;
[artifact: string]: ArtifactEntry | string | undefined;
}
>;

export interface ArtifactEntry {
/** A download URL */
tarball: string;
/** A SHA256 hash of the tarball */
shasum: string;
/** Size of the tarball in bytes */
size: string;
}

export interface SQLiteQueryPlanRow {
id: number;
parent: number;
Expand All @@ -57,3 +79,28 @@ export function getMagicNumberOfExtension(extension: Extension): Buffer {
return zipMagicNumber;
}
}

export function artifactsToRecord(
R2_PUBLIC_URL: string,
artifacts: ReleaseArtifact[],
): Record<string, ArtifactEntry> {
assert(artifacts.length !== 0);
const targets: Record<string, ArtifactEntry> = {};
for (const artifact of artifacts) {
switch (artifact.extension) {
case "tar.gz":
continue;
case "tar.xz":
case "zip":
break;
}
assert(!(`${artifact.arch}-${artifact.os}` in targets));
assert.strictEqual(artifact.fileShasum.length, 64);
targets[`${artifact.arch}-${artifact.os}`] = {
tarball: `${R2_PUBLIC_URL}/zls-${artifact.os}-${artifact.arch}-${artifact.version}.${artifact.extension}`,
shasum: artifact.fileShasum,
size: artifact.fileSize.toString(),
};
}
return targets;
}
Loading

0 comments on commit 9bd5b10

Please sign in to comment.