Skip to content

Commit

Permalink
Support new windows build (replaced prior update.sh)
Browse files Browse the repository at this point in the history
  • Loading branch information
mceachen committed Jul 13, 2024
1 parent cc9fb9a commit 8f7e682
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 75 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ Provides the win32 distribution of [ExifTool](http://www.sno.phy.queensu.ca/~phi
[exiftool-vendored](https://github.com/photostructure/exiftool-vendored.js) for
performant, type-safe access to this binary.**

## Thanks to Oliver Betz!
## Thanks to Phil Harvey and Oliver Betz!

This module heavily depends on [Oliver Betz's portable Perl
launcher](https://oliverbetz.de/pages/Artikel/Portable-Perl-Applications) which leverages Strawberry Perl. [Read more
Phil Harvey has been [working tirelessly on ExifTool since 2003](https://exiftool.org/ancient_history.html).

This module uses the new (as of version 12.88) official Windows installation, which depends on [Oliver Betz's portable Perl
launcher](https://oliverbetz.de/pages/Artikel/Portable-Perl-Applications) and Strawberry Perl. [Read more
here.](https://oliverbetz.de/pages/Artikel/ExifTool-for-Windows)

## Versioning
Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
"scripts": {
"prettier": "prettier --write test/*.js",
"test": "mocha",
"sign": "node ./sign.js",
"update": "ncu --upgrade --install always && bash -c ./update.sh"
"update": "ncu --upgrade --install always && ./update.js"
},
"release-it": {
"hooks": {
Expand All @@ -42,10 +41,12 @@
}
},
"devDependencies": {
"@electron/windows-sign": "^1.1.2",
"mocha": "^10.4.0",
"axios": "^1.7.2",
"mocha": "^10.6.0",
"npm-check-updates": "^16.14.20",
"prettier": "^3.2.5",
"release-it": "^17.3.0"
"prettier": "^3.3.2",
"release-it": "^17.5.0",
"unzipper": "^0.12.1",
"xml2js": "^0.6.2"
}
}
9 changes: 0 additions & 9 deletions sign.js

This file was deleted.

132 changes: 132 additions & 0 deletions update.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env node
// @ts-check

const { createHash } = require("node:crypto");
const { createWriteStream, createReadStream } = require("node:fs");
const { mkdir, rm, rename, stat } = require("node:fs/promises");
const { join } = require("node:path");
const { pipeline } = require("node:stream");
const { promisify } = require("node:util");

const xml2js = require("xml2js");
const unzipper = require("unzipper");

// Currently is "12.88", but "13.1" is valid.

const VersionRE = /\b([\d\.]{4,})\b/;

const asyncPipeline = promisify(pipeline);

async function fetchLatestEnclosure() {
const response = await fetch("https://exiftool.org/rss.xml");
const xmlData = await response.text();
const parser = new xml2js.Parser();
const xmlDoc = await parser.parseStringPromise(xmlData);
const items = xmlDoc.rss.channel[0].item;
let enc;
for (const item of items) {
const title = item.title[0];
const version = /\b(\d{2}\.\d+\b)/.exec(title)?.[1];
enc = item.enclosure?.find(
(ea) => ea.$.type === "application/zip" && ea.$.url.endsWith("_64.zip"),
)?.$;
if (enc != null) break;
}
if (enc == null) {
throw new Error("No enclosure with a valid download link was found");
}
return enc;
}

async function fetchLatestSHA256(basename) {
const response = await fetch("https://exiftool.org/checksums.txt");
const text = await response.text();
for (const line of text.split("\n")) {
if (line.startsWith("SHA256") && line.includes(basename)) {
const sha256 = /\b([0-9a-f]{64})\b/.exec(line)?.[1];
if (sha256 != null) return sha256;
else
throw new Error("No SHA256 hash was found for matching line: " + line);
}
}
throw new Error("No SHA256 hash was found for basename: " + basename);
}

function computeSHA256(path) {
return new Promise((resolve, reject) => {
const hash = createHash("sha256");
const stream = createReadStream(path);

stream.on("data", (data) => {
hash.update(data);
});

stream.on("end", () => {
const sha256 = hash.digest("hex");
resolve(sha256);
});

stream.on("error", (error) => {
reject(error);
});
});
}

async function run() {
const enc = await fetchLatestEnclosure();
const url = new URL(enc.url);
const basename = url.pathname.split("/").at(-1);
if (basename == null) {
throw new Error("Invalid basename from enclosure: " + JSON.stringify(enc));
}
const expectedSha256 = await fetchLatestSHA256(basename);

const dlDir = join(__dirname, ".dl");

await mkdir(dlDir, { recursive: true });
const zipPath = join(dlDir, basename);
const dlStream = createWriteStream(zipPath);
console.log("Fetching ", { url: enc.url, out: zipPath });
const response = await fetch(enc.url);
if (response.body == null) {
throw new Error("Response body from fetch(" + enc.url + ") is null");
}
await asyncPipeline(response.body, dlStream);

const expectedFileSize = parseInt(enc.length);
const actualFileSize = (await stat(zipPath)).size;
if (actualFileSize !== expectedFileSize) {
throw new Error(
"Unexpected file size: " +
JSON.stringify({
actualFileSize,
expectedFileSize,
url: enc.url,
file: zipPath,
}),
);
}

const actualSha256 = await computeSHA256(zipPath);
console.log("SHA256:", { expected: expectedSha256, actual: actualSha256 });
if (actualSha256 !== expectedSha256) {
throw new Error("SHA256 hash mismatch");
}

const expectedZipOutDir = join(dlDir, basename.replace(/\.zip$/, ""));
await rm(expectedZipOutDir, { recursive: true, force: true });
await asyncPipeline(
createReadStream(zipPath),
unzipper.Extract({ path: dlDir }),
);
const destDir = join(__dirname, "bin");
await rm(destDir, { recursive: true, force: true });
await rename(expectedZipOutDir, destDir);
await rename(
join(__dirname, "bin", "exiftool(-k).exe"),
join(__dirname, "bin", "exiftool.exe"),
);
console.log("Success!");
}

run();
57 changes: 0 additions & 57 deletions update.sh

This file was deleted.

0 comments on commit 8f7e682

Please sign in to comment.