diff --git a/bin/ffr.ts b/bin/ffr.ts index eaeb48d..9eeadd7 100644 --- a/bin/ffr.ts +++ b/bin/ffr.ts @@ -1,14 +1,26 @@ -console.log("poop"); - import { parseArgs } from "jsr:@std/cli/parse-args"; - import { main } from "../src/cli/ffr/main.ts"; +let VERSION = "0.0.0"; + +try { + const versionFile = "./version.ts"; + const v = await import(versionFile) as { + default: { + version: string; + }; + }; + VERSION = v.default.version; +} catch (_) { + // do nothing and assume we're not in the compiled version +} + const { _, cwd, ["remote-url"]: remoteUrl, verbose, + version, } = parseArgs( Deno.args, { @@ -17,14 +29,15 @@ const { r: "report", c: "cwd", }, - boolean: ["verbose"], + boolean: ["verbose", "version"], }, ); -await main({ +await main(VERSION, { _, raw: Deno.args, cwd, verbose, + version, remoteUrl, }); diff --git a/build/bin.ts b/build/bin.ts index 3c42690..87c28a1 100644 --- a/build/bin.ts +++ b/build/bin.ts @@ -3,88 +3,128 @@ import { format, increment, parse } from "jsr:@std/semver"; const __dirname = new URL(".", import.meta.url).pathname; -async function compile(src: string, dest: string) { - console.log(`Compiling ${src} to ${dest}`); - - const cmd = new Deno.Command(Deno.execPath(), { - cwd: join(__dirname, "../"), - args: [ - "compile", - "-A", - "--unstable-worker-options", - "--include", - join(__dirname, "../src/libs/expression/worker.ts"), - "--output", - dest, - src, - ], - stderr: "inherit", - stdout: "inherit", - }); - - const result = await cmd.output(); - - console.log(` > Compile Exit Code: ${result.code}`); - - if (result.code !== 0) { - return; - } - - const zip = new Deno.Command(Deno.execPath(), { - cwd: join(__dirname, "../dist"), - args: [ - "zip", - `${basename(dest)}.zip`, - basename(dest), - ], - stderr: "inherit", - stdout: "inherit", - }); +const appleDeveloperId = Deno.env.get("APPLE_DEVELOPER_ID"); +const currentVersion = + await (await fetch("https://elwood.run/ffremote/release/latest.txt")).text(); +const nextVersion = format(increment(parse(currentVersion), "patch")); - const zipResult = await cmd.output(); +const dist = join(__dirname, "../dist"); +const versionFile = join(__dirname, "../bin/version.ts"); + +try { + // clean out our dist folder + // we don't want to leave any old files around + // that will get pushed with the release + await Deno.remove(dist, { recursive: true }); + await Deno.mkdir( + dist, + { recursive: true }, + ); + + // write out our new version file + // this will be included in the compiled binaries + await Deno.writeTextFile( + versionFile, + `export default { version: "${nextVersion}" };\n`, + ); + + // generate builds for `elwood-run` and `ffr` + await Promise.all([ + compile( + join(__dirname, "../bin/cli.ts"), + join(dist, "elwood-run"), + ), + compile( + join(__dirname, "../bin/ffr.ts"), + join(dist, "ffr"), + ), + ]); +} catch (err) { + console.log(`%c${(err as Error).message}`, "color:red"); + Deno.exit(1); +} finally { + // remove the version file + await Deno.remove(versionFile); +} - console.log(` > Zip Exit Code: ${zipResult.code}`); +async function compile(src: string, dest: string) { + console.log(`Compiling ${src} to ${dest}`); - if (zipResult.code !== 0) { - return; + const targets = [ + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + ]; + + for (const target of targets) { + const cmd = new Deno.Command(Deno.execPath(), { + cwd: join(__dirname, "../"), + args: [ + "compile", + "-A", + "--unstable-worker-options", + "--include", + join(__dirname, "../src/libs/expression/worker.ts"), + "--include", + versionFile, + "--target", + target, + "--output", + dest, + src, + ], + stderr: "inherit", + stdout: "inherit", + }); + + const result = await cmd.output(); + + console.log(` > Compile Exit Code: ${result.code}`); + + if (result.code !== 0) { + return; + } + + if (target.includes("darwin") && appleDeveloperId) { + const sign = new Deno.Command("codesign", { + cwd: dist, + args: [ + "-s", + appleDeveloperId, + basename(dest), + ], + stderr: "inherit", + stdout: "inherit", + }); + + const result = await sign.output(); + + console.log(` > Sign Exit Code: ${result.code}`); + + if (result.code !== 0) { + return; + } + } + + const zip = new Deno.Command("zip", { + cwd: join(__dirname, "../dist"), + args: [ + `${basename(dest)}-${target}.zip`, + basename(dest), + ], + stderr: "inherit", + stdout: "inherit", + }); + + const zipResult = await zip.output(); + + console.log(` > Zip Exit Code: ${zipResult.code}`); + + if (zipResult.code !== 0) { + return; + } + + await Deno.remove(dest); } - - // // output - // const output = await Deno.open(`${dest}.zip`, { - // create: true, - // write: true, - // read: true, - // }); - - // const source = await Deno.open(dest, { read: true }); - - // const zipWriter = new zip.ZipWriter(output.writable); - // await zipWriter.add(basename(dest), source.readable); - // await zipWriter.close(); - - await Deno.remove(dest); } - -const dest = join(__dirname, "../dist"); - -await Deno.mkdir( - dest, - { recursive: true }, -); - -await Promise.all([ - compile( - join(__dirname, "../bin/cli.ts"), - join(dest, "elwood-run"), - ), - compile( - join(__dirname, "../bin/ffr.ts"), - join(dest, "ffr"), - ), -]); - -const currentVersion = - await (await fetch("https://elwood.run/ffremote/release/latest.txt")).text(); -const nextVersion = format(increment(parse(currentVersion), "patch")); - -console.log(`new_version=${nextVersion}`); diff --git a/deno.json b/deno.json index e45dfbb..60ff7c5 100644 --- a/deno.json +++ b/deno.json @@ -19,7 +19,7 @@ "test": "deno test -A --unstable-worker-options ./**/*.test.ts", "compile": "deno compile -A --unstable-worker-options --include ./src/libs/expression/worker.ts -o ./dist/elwood-run ./src/launch.ts", "build-image": "packer build build/run.pkr.hcl", - "build-cli": "deno run -A ./build/bin.ts", + "build-cli": "deno run --env-file=./.env -A ./build/bin.ts", "generate-schemas": "deno run --allow-read --allow-write ./schema/generate.ts", "cli": "deno run -A --unstable-worker-options ./bin/cli.ts", "ffr": "deno run -A --unstable-worker-options ./bin/ffr.ts" diff --git a/install-ffr.sh b/install-ffr.sh index 104fa3d..7e115c7 100644 --- a/install-ffr.sh +++ b/install-ffr.sh @@ -6,7 +6,7 @@ set -e if ! command -v unzip >/dev/null && ! command -v 7z >/dev/null; then - echo "Error: either unzip or 7z is required to install FFr (see: https://github.com/denoland/ffr_install#either-unzip-or-7z-is-required )." 1>&2 + echo "Error: either unzip or 7z is required to install FFremote." 1>&2 exit 1 fi @@ -39,7 +39,7 @@ for arg in "$@"; do "--help") print_help_and_exit ;; - "-"*) ;; + "-"*) ;;w *) if [ -z "$ffr_version" ]; then ffr_version="$arg" @@ -49,10 +49,10 @@ for arg in "$@"; do done if [ -z "$ffr_version" ]; then - ffr_version="$(curl -s https://elwood.run/ffr/release/latest.txt)" + ffr_version="$(curl -s https://elwood.run/ffremote/release/latest.txt)" fi -ffr_uri="https://elwood.run/ffr/release/${ffr_version}.zip" +ffr_uri="https://elwood.run/ffremote/release/${target}@${ffr_version}.zip" ffr_install="${FFR_INSTALL:-$HOME/.elwood/run}" bin_dir="$ffr_install/bin" exe="$bin_dir/ffr" diff --git a/src/cli/ffr/main.ts b/src/cli/ffr/main.ts index d26b583..746d784 100644 --- a/src/cli/ffr/main.ts +++ b/src/cli/ffr/main.ts @@ -14,14 +14,20 @@ import watch from "./watch.ts"; import auth from "./auth.ts"; import { printError } from "../lib.ts"; -export async function main(args: FFrArgs) { +export async function main(compiledVersion: string, args: FFrArgs) { + if (args.version) { + console.log(`ffremote ${compiledVersion}`); + Deno.exit(0); + } + if (args.raw.length === 0) { [ "", - "./ffr - FFremote: The Remote FFmpeg Runner", + `ffremote (${compiledVersion}) - FFremote: The Remote FFmpeg Runner`, "", "Usage:", - " ffr --size= <...ffmpeg-args>", + " ffr <...ffmpeg-args>", + " ffr --size= --include= -- <...ffmpeg-args>", " ffr get ", " ffr watch ", " ffr status ", diff --git a/src/types.ts b/src/types.ts index c5b5ef9..589afc3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -151,6 +151,7 @@ export type CliArgs = { verbose?: boolean; reportFile?: string; remoteUrl?: string; + version?: boolean; }; export type FFrArgs = Omit< diff --git a/www/next.config.mjs b/www/next.config.mjs index 68449db..b771522 100644 --- a/www/next.config.mjs +++ b/www/next.config.mjs @@ -16,6 +16,26 @@ const nextConfig = { source: '/ffr/:slug', destination: '/ffremote/:slug', permanent: true + }, + { + source: '/ffr/docs/:slug', + destination: '/docs/ffremote/:slug', + permanent: true + }, + { + source: '/ffr/docs', + destination: '/docs/ffremote', + permanent: true + }, + { + source: '/ffremote/docs/:slug', + destination: '/docs/ffremote/:slug', + permanent: true + }, + { + source: '/ffremote/docs', + destination: '/docs/ffremote', + permanent: true } ] } diff --git a/www/src/app/docs/ffremote/pricing/page.tsx b/www/src/app/docs/ffremote/pricing/page.tsx index fef0e9b..468919d 100644 --- a/www/src/app/docs/ffremote/pricing/page.tsx +++ b/www/src/app/docs/ffremote/pricing/page.tsx @@ -4,7 +4,7 @@ import {useMDXComponents} from '../../../../mdx-components'; import Content from './content.mdx'; export default async function Page() { - const apiUrl = process.env.API_URL ?? 'https://api.elwood.run'; + const apiUrl = 'https://api.elwood.run'; const response = await fetch(`${apiUrl}/billing/prices`, { next: {revalidate: 60}, }); diff --git a/www/src/app/ffremote/docs/[...slug]/route.ts b/www/src/app/ffremote/docs/[...slug]/route.ts deleted file mode 100644 index fa1568b..0000000 --- a/www/src/app/ffremote/docs/[...slug]/route.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {NextResponse, NextRequest} from 'next/server'; - -type Context = { - params: { - slug: string | string[]; - } -} - -export async function GET(request: NextRequest, ctx:Context) { - const _slug = Array.isArray(ctx.params.slug) ? ctx.params.slug.join('/') : ctx.params.slug; - return NextResponse.redirect(new URL(`/docs/ffr/${_slug}`, request.nextUrl.href)); -} diff --git a/www/src/app/ffremote/docs/route.ts b/www/src/app/ffremote/docs/route.ts deleted file mode 100644 index 767448e..0000000 --- a/www/src/app/ffremote/docs/route.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {NextResponse, NextRequest} from 'next/server'; - -export async function GET(request: NextRequest) { - return NextResponse.redirect(new URL('/docs/ffr', request.nextUrl.href)); -} diff --git a/www/src/app/ffremote/release/[id]/route.ts b/www/src/app/ffremote/release/[id]/route.ts index dbea5c5..feccd94 100644 --- a/www/src/app/ffremote/release/[id]/route.ts +++ b/www/src/app/ffremote/release/[id]/route.ts @@ -1,30 +1,51 @@ -import { NextRequest, NextResponse } from "next/server"; +import {NextRequest, NextResponse} from 'next/server'; export type Context = { params: { id: string; }; }; - -export async function GET(req:NextRequest, ctx:Context) { - const id = ctx.params.id.replace('.zip', ''); + +export async function GET(req: NextRequest, ctx: Context) { + const [target, version] = ctx.params.id.replace('.zip', '').split('@'); + let data: unknown = {}; + + if (version === 'latest') { + const response = await fetch( + `https://api.github.com/repos/elwood-software/run/releases/latest`, + { + headers: { + Authorization: `bearer ${process.env.GH_TOKEN}`, + }, + }, + ); + data = await response.json(); + } else { + const response = await fetch( + `https://api.github.com/repos/elwood-software/run/releases/tags/${version}`, + { + headers: { + Authorization: `bearer ${process.env.GH_TOKEN}`, + }, + }, + ); + data = await response.json(); + } + - const response = await fetch(`https://api.github.com/repos/elwood-software/run/releases/tags/${id}`); - const data = await response.json(); const body = data as { assets: Array<{ - name:string; - browser_download_url:string; - }> + name: string; + browser_download_url: string; + }>; }; - const asset = body.assets.find((asset) => asset.name === `ffr.zip`); + const asset = body.assets.find(asset => asset.name === `ffr-${target}.zip`); if (!asset) { return NextResponse.error(); } - return NextResponse.redirect(asset!.browser_download_url, 302); } diff --git a/www/src/app/ffremote/release/latest.txt/route.ts b/www/src/app/ffremote/release/latest.txt/route.ts index 1f964c1..ac619b8 100644 --- a/www/src/app/ffremote/release/latest.txt/route.ts +++ b/www/src/app/ffremote/release/latest.txt/route.ts @@ -1,5 +1,12 @@ + +export const dynamic = 'force-dynamic' + export async function GET() { - const response = await fetch('https://api.github.com/repos/elwood-software/run/releases/latest'); + const response = await fetch('https://api.github.com/repos/elwood-software/run/releases/latest', { + headers: { + "Authorization": `bearer ${process.env.GH_TOKEN}`, + } + }); const data = await response.json(); const latest = data as { tag_name: string; @@ -8,6 +15,7 @@ export async function GET() { return new Response(latest.tag_name, { headers: { 'Content-Type': 'text/plain', + }, }); }