Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
705ab96
Add Flatpak Deno generator
sigmaSd May 8, 2025
1b82dac
fix publish path
sigmaSd May 8, 2025
d72d795
better fix
sigmaSd May 8, 2025
66b539a
document lockfile version
sigmaSd May 8, 2025
5d3323b
Add GitHub Actions workflow for Deno CI
sigmaSd May 8, 2025
4f207e4
Add MIT license info to README and source files
sigmaSd May 8, 2025
c714f7f
fmt
sigmaSd May 8, 2025
1955998
dcouemnt local run
sigmaSd May 8, 2025
f9646e8
set sigmasd as deno module maintainer
sigmaSd May 8, 2025
01b6abc
Trigger Deno workflow only on changes in deno directory
sigmaSd May 8, 2025
eae2bed
Rename Deno workflow to CI
sigmaSd May 8, 2025
09724dc
Rename test job to deno in workflow file
sigmaSd May 8, 2025
c50fac9
Remove matrix strategy from Deno workflow
sigmaSd May 8, 2025
91ea5cf
Remove submodules option from checkout step in CI workflow
sigmaSd May 8, 2025
2c7713f
Add tests and refactor main function for better testability
sigmaSd May 8, 2025
e0504a3
Refactor Flatpak data types and improve README instructions
sigmaSd May 9, 2025
07051f6
show usage when no argument is provided
sigmaSd May 9, 2025
579fadc
Add --output option and usage examples to CLI entrypoint
sigmaSd May 9, 2025
f7ef1b2
Remove unused _urlToDenoCacheFilename function
sigmaSd May 9, 2025
c0a72ed
Clarify output file naming in usage instructions
sigmaSd May 9, 2025
515d052
more correct typing
sigmaSd May 9, 2025
a7f234a
document technical choices
sigmaSd May 9, 2025
ff2bf48
typo
sigmaSd May 9, 2025
a04e297
Rename package to @flatpak-contrib and update version to 1.3.0
sigmaSd May 9, 2025
e6b1753
remove extra folder
sigmaSd May 9, 2025
cf1ab2a
Update deno/README.md
sigmaSd May 9, 2025
d45ba45
fmt
sigmaSd May 9, 2025
1d23e69
Update example command to use src/main.ts path
sigmaSd May 9, 2025
eba8715
Add labeler config for deno directory
sigmaSd May 9, 2025
ca8a261
Handle peer dependencies in lockfile
sigmaSd May 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/publish-jsr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish
on:
push:
paths:
- deno/**
branches:
- master

defaults:
run:
working-directory: deno

jobs:
publish:
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@v4

- name: Setup Deno
uses: denoland/setup-deno@v2

- name: Publish package
run: deno publish
42 changes: 42 additions & 0 deletions deno/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Flatpak Deno Generator

```
deno -RN -W=. jsr:@flatpak/flatpak-deno-generator deno.lock
```

This will create a `deno-sources.json` that can be used in flatpak build files:

- it creates and populates `./deno_dir` with npm dependencies
- it creates and populates `./vendor` with jsr + http dependencies

## Usage:

- Use the sources file as a source, example:

```yml
sources:
- deno-sources.json
```

- To use `deno_dir` point `DENO_DIR` env variable to it, like so:

```yml
- name: someModule
buildsystem: simple
build-options:
env:
DENO_DIR: deno_dir
```

- To use `vendor` move it next to your `deno.json` file and make sure to compile
or run with `--vendor` flag, exmaple:

```yml
- # src is where my deno project at
- mv ./vendor src/
- DENORT_BIN=$PWD/denort ./deno compile --vendor --no-check --output virtaudio-bin --cached-only
--allow-all --include ./src/gui.slint --include ./src/client.html ./src/gui.ts
```

## Example
- checkout https://github.com/flathub/io.github.sigmasd.VirtAudio/
6 changes: 6 additions & 0 deletions deno/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "@flatpak/flatpak-deno-generator",
"version": "1.2.2",
"exports": "./src/main.ts",
"license": "MIT"
}
11 changes: 11 additions & 0 deletions deno/deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

204 changes: 204 additions & 0 deletions deno/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import {
base64ToHex,
sha256,
shortHash,
shouldHash,
splitOnce,
urlSegments,
} from "./utils.ts";

interface Pkg {
module: string;
version: string;
name: string;
cpu?: "x86_64" | "aarch64";
}

async function jsrPkgToFlatpakData(pkg: Pkg) {
const flatpkData = [];
const metaUrl = `https://jsr.io/${pkg.module}/meta.json`;
const metaText = await fetch(
metaUrl,
).then((r) => r.text());

flatpkData.push({
type: "file",
url: metaUrl,
sha256: await sha256(metaText),
dest: `vendor/jsr.io/${pkg.module}`,
"dest-filename": "meta.json",
});

const metaVerUrl = `https://jsr.io/${pkg.module}/${pkg.version}_meta.json`;
const metaVerText = await fetch(
metaVerUrl,
).then((r) => r.text());

flatpkData.push({
type: "file",
url: metaVerUrl,
sha256: await sha256(metaVerText),
dest: `vendor/jsr.io/${pkg.module}`,
"dest-filename": `${pkg.version}_meta.json`,
});

const metaVer = JSON.parse(metaVerText);

for (
const fileUrl of Object.keys(metaVer.moduleGraph2 || metaVer.moduleGraph1)
) {
const fileMeta = metaVer.manifest[fileUrl];
// this mean the url exists in the module graph but not in the manifest -> this url is not needed
if (!fileMeta) continue;
const [checksumType, checksumValue] = splitOnce(fileMeta.checksum, "-");

const url = `https://jsr.io/${pkg.module}/${pkg.version}${fileUrl}`;
let [fileDir, fileName] = splitOnce(fileUrl, "/", "right");
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${fileDir}`;

if (shouldHash(fileName)) {
fileName = await shortHash(fileName);
}

flatpkData.push({
type: "file",
url,
[checksumType]: checksumValue,
dest,
"dest-filename": fileName,
});
}

// If a moule imports deno.json (import ... from "deno.json" with {type:"json"}), it won't appear in the module graph
// Worarkound: if there is a deno.json file in the manifest just add it
// Note this can be made better, by looking in the moduleGraph if deno.json is specified in the dependencies
for (const [fileUrl, fileMeta] of Object.entries(metaVer.manifest)) {
if (fileUrl.includes("deno.json")) {
const [checksumType, checksumValue] = splitOnce(
// deno-lint-ignore no-explicit-any
(fileMeta as any).checksum,
"-",
);
const url = `https://jsr.io/${pkg.module}/${pkg.version}${fileUrl}`;
const [fileDir, fileName] = splitOnce(fileUrl, "/", "right");
const dest = `vendor/jsr.io/${pkg.module}/${pkg.version}${fileDir}`;
flatpkData.push({
type: "file",
url,
[checksumType]: checksumValue,
dest,
"dest-filename": fileName,
});
}
}

return flatpkData;
}

async function npmPkgToFlatpakData(pkg: Pkg) {
//url: https://registry.npmjs.org/@napi-rs/cli/-/cli-2.18.4.tgz
//npmPkgs;
const metaUrl = `https://registry.npmjs.org/${pkg.module}`;
const metaText = await fetch(metaUrl).then(
(r) => r.text(),
);
const meta = JSON.parse(metaText);

const metaData = {
type: "file",
url: metaUrl,
sha256: await sha256(metaText),
dest: `deno_dir/npm/registry.npmjs.org/${pkg.module}`,
"dest-filename": "registry.json",
};

const [checksumType, checksumValue] = splitOnce(
meta.versions[pkg.version].dist.integrity,
"-",
);
const pkgData: Record<string, unknown> = {
type: "archive",
"archive-type": "tar-gzip",
url:
`https://registry.npmjs.org/${pkg.module}/-/${pkg.name}-${pkg.version}.tgz`,
[checksumType]: base64ToHex(checksumValue),
dest: `deno_dir/npm/registry.npmjs.org/${pkg.module}/${pkg.version}`,
};

if (pkg.cpu) {
pkgData["only-arches"] = [pkg.cpu];
}

return [metaData, pkgData];
}

if (import.meta.main) {
const arg = Deno.args[0];
if (!arg) {
console.error("No argument provided");
Deno.exit(1);
}

const lock = JSON.parse(Deno.readTextFileSync(arg));
if (lock.version !== "5") {
throw new Error(`Unsupported deno lock version: ${lock.version}`);
}

const jsrPkgs: Pkg[] = !lock.jsr ? [] : Object.keys(lock.jsr).map((pkg) => {
const r = splitOnce(pkg, "@", "right");
const name = r[0].split("/")[1];
return { module: r[0], version: r[1], name };
});
jsrPkgs;
const npmPkgs: Pkg[] = !lock.npm ? [] : Object.entries(lock.npm)
.filter((
// deno-lint-ignore no-explicit-any
[_key, val]: any,
) => (val.os === undefined || val.os?.at(0) === "linux"))
// deno-lint-ignore no-explicit-any
.map(([key, val]: any) => {
const r = splitOnce(key, "@", "right");
const name = r[0].includes("/") ? r[0].split("/")[1] : r[0];
const cpu = val.cpu?.at(0);
return {
module: r[0],
version: r[1],
name,
cpu: cpu === "x64" ? "x86_64" : cpu === "arm64" ? "aarch64" : cpu,
};
});
//url: https://registry.npmjs.org/@napi-rs/cli/-/cli-2.18.4.tgz
npmPkgs;
const httpPkgsData = !lock.remote
? []
: Object.entries(lock.remote).map(async ([urlStr, checksum]) => {
const url = new URL(urlStr);
const segments = await Promise.all(
urlSegments(url)
.map(async (part) => shouldHash(part) ? await shortHash(part) : part),
);
const filename = segments.pop();
return {
type: "file",
url: urlStr,
sha256: checksum,
dest: `vendor/${url.hostname}/${segments.join("/")}`,
"dest-filename": filename,
};
});

const flatpakData = [
await Promise.all(
jsrPkgs.map((pkg) => jsrPkgToFlatpakData(pkg)),
).then((r) => r.flat()),
await Promise.all(npmPkgs.map((pkg) => npmPkgToFlatpakData(pkg))).then(
(r) => r.flat(),
),
await Promise.all(httpPkgsData),
].flat();
// console.log(flatpakData);
Deno.writeTextFileSync(
"deno-sources.json",
JSON.stringify(flatpakData, null, 2),
);
}
Loading