hugo-extended 0.152.1 → 0.153.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/install.js +105 -21
  2. package/lib/utils.js +25 -21
  3. package/package.json +20 -30
package/lib/install.js CHANGED
@@ -1,7 +1,11 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
3
  import { fileURLToPath } from "url";
4
- import downloader from "careful-downloader";
4
+ import { spawnSync } from "child_process";
5
+ import { pipeline } from "stream/promises";
6
+ import crypto from "crypto";
7
+ import * as tar from "tar";
8
+ import AdmZip from "adm-zip";
5
9
  import logSymbols from "log-symbols";
6
10
  import {
7
11
  getPkgVersion,
@@ -15,6 +19,41 @@ import {
15
19
 
16
20
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
21
 
22
+ async function downloadFile(url, dest) {
23
+ const response = await fetch(url);
24
+ if (!response.ok) {
25
+ throw new Error(`Failed to download ${url}: ${response.statusText}`);
26
+ }
27
+ await pipeline(response.body, fs.createWriteStream(dest));
28
+ }
29
+
30
+ async function verifyChecksum(filePath, checksumUrl, filename) {
31
+ const response = await fetch(checksumUrl);
32
+ if (!response.ok) {
33
+ throw new Error(`Failed to download checksums: ${response.statusText}`);
34
+ }
35
+ const checksums = await response.text();
36
+
37
+ // checksums file format: "sha256 filename"
38
+ const expectedChecksum = checksums
39
+ .split("\n")
40
+ .find((line) => line.endsWith(filename))
41
+ ?.split(/\s+/)[0];
42
+
43
+ if (!expectedChecksum) {
44
+ throw new Error(`Checksum for ${filename} not found in checksums file.`);
45
+ }
46
+
47
+ const fileBuffer = fs.readFileSync(filePath);
48
+ const hash = crypto.createHash("sha256");
49
+ hash.update(fileBuffer);
50
+ const actualChecksum = hash.digest("hex");
51
+
52
+ if (actualChecksum !== expectedChecksum) {
53
+ throw new Error(`Checksum mismatch! Expected ${expectedChecksum}, got ${actualChecksum}`);
54
+ }
55
+ }
56
+
18
57
  async function install() {
19
58
  try {
20
59
  const version = getPkgVersion();
@@ -22,36 +61,81 @@ async function install() {
22
61
  const checksumFile = getChecksumFilename(version);
23
62
  const binFile = getBinFilename();
24
63
 
25
- // stop here if there's nothing we can download
26
- if (!releaseFile)
64
+ if (!releaseFile) {
27
65
  throw new Error(`Are you sure this platform is supported? See: https://github.com/gohugoio/hugo/releases/tag/v${version}`);
66
+ }
28
67
 
29
- // warn if platform doesn't support Hugo Extended, proceed with vanilla Hugo
30
- if (!isExtended(releaseFile))
68
+ if (!isExtended(releaseFile)) {
31
69
  console.warn(`${logSymbols.info} Hugo Extended isn't supported on this platform, downloading vanilla Hugo instead.`);
70
+ }
71
+
72
+ // Prepare vendor directory
73
+ const vendorDir = path.join(__dirname, "..", "vendor");
74
+ if (!fs.existsSync(vendorDir)) {
75
+ fs.mkdirSync(vendorDir, { recursive: true });
76
+ }
77
+
78
+ const releaseUrl = getReleaseUrl(version, releaseFile);
79
+ const checksumUrl = getReleaseUrl(version, checksumFile);
80
+ const downloadPath = path.join(vendorDir, releaseFile);
81
+
82
+ console.info(`${logSymbols.info} Downloading ${releaseFile}...`);
83
+ await downloadFile(releaseUrl, downloadPath);
84
+
85
+ console.info(`${logSymbols.info} Verifying checksum...`);
86
+ await verifyChecksum(downloadPath, checksumUrl, releaseFile);
87
+
88
+ if (process.platform === "darwin") {
89
+ console.info(`${logSymbols.info} Installing ${releaseFile} (requires sudo)...`);
90
+ // Run MacOS installer
91
+ const result = spawnSync("sudo", ["installer", "-pkg", downloadPath, "-target", "/"], {
92
+ stdio: "inherit",
93
+ });
94
+
95
+ if (result.error) throw result.error;
96
+ if (result.status !== 0) {
97
+ throw new Error(`Installer failed with exit code ${result.status}`);
98
+ }
99
+
100
+ // Cleanup downloaded pkg
101
+ fs.unlinkSync(downloadPath);
102
+ } else {
103
+ console.info(`${logSymbols.info} Extracting...`);
104
+
105
+ if (releaseFile.endsWith(".zip")) {
106
+ const zip = new AdmZip(downloadPath);
107
+ zip.extractAllTo(vendorDir, true);
32
108
 
33
- // download release from GitHub and verify its checksum
34
- const download = await downloader(getReleaseUrl(version, releaseFile), {
35
- checksumUrl: getReleaseUrl(version, checksumFile),
36
- filename: releaseFile,
37
- destDir: path.join(__dirname, "..", "vendor"),
38
- algorithm: "sha256",
39
- extract: true,
40
- });
109
+ // Cleanup zip
110
+ fs.unlinkSync(downloadPath);
111
+ } else if (releaseFile.endsWith(".tar.gz")) {
112
+ await tar.x({
113
+ file: downloadPath,
114
+ cwd: vendorDir,
115
+ });
41
116
 
42
- // full path to the binary
43
- const installedToPath = path.join(download, binFile);
117
+ // Cleanup tar.gz
118
+ fs.unlinkSync(downloadPath);
119
+ }
44
120
 
45
- // ensure hugo[.exe] is executable
46
- fs.chmodSync(installedToPath, 0o755);
121
+ const binPath = path.join(vendorDir, binFile);
122
+ if (fs.existsSync(binPath)) {
123
+ fs.chmodSync(binPath, 0o755);
124
+ }
125
+ }
47
126
 
48
127
  console.info(`${logSymbols.success} Hugo installed successfully!`);
49
- console.info(getBinVersion(installedToPath));
50
128
 
51
- // return the full path to our Hugo binary
52
- return installedToPath;
129
+ // Check version
130
+ if (process.platform === "darwin") {
131
+ console.info(getBinVersion("/usr/local/bin/hugo"));
132
+ return "/usr/local/bin/hugo";
133
+ } else {
134
+ const binPath = path.join(vendorDir, binFile);
135
+ console.info(getBinVersion(binPath));
136
+ return binPath;
137
+ }
53
138
  } catch (error) {
54
- // pass whatever error occurred along the way to console
55
139
  console.error(`${logSymbols.error} Hugo installation failed. :(`);
56
140
  throw error;
57
141
  }
package/lib/utils.js CHANGED
@@ -2,7 +2,7 @@ import path from "path";
2
2
  import fs from "fs";
3
3
  import { fileURLToPath } from "url";
4
4
  import { execFileSync } from "child_process";
5
- import { readPackageUpSync } from "read-pkg-up";
5
+ import { readPackageUpSync } from "read-package-up";
6
6
 
7
7
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
8
 
@@ -26,11 +26,13 @@ export function getBinFilename() {
26
26
 
27
27
  // Simple shortcut to ./vendor/hugo[.exe] from package root.
28
28
  export function getBinPath() {
29
+ if (process.platform === "darwin") return "/usr/local/bin/hugo";
30
+
29
31
  return path.join(
30
32
  __dirname,
31
33
  "..",
32
34
  "vendor",
33
- getBinFilename(),
35
+ getBinFilename()
34
36
  );
35
37
  }
36
38
 
@@ -44,12 +46,14 @@ export function getBinVersion(bin) {
44
46
  // Simply detect if the given file exists.
45
47
  export function doesBinExist(bin) {
46
48
  try {
47
- if (fs.existsSync(bin))
49
+ if (fs.existsSync(bin)) {
48
50
  return true;
51
+ }
49
52
  } catch (error) {
50
53
  // something bad happened besides Hugo not existing
51
- if (error.code !== "ENOENT")
54
+ if (error.code !== "ENOENT") {
52
55
  throw error;
56
+ }
53
57
 
54
58
  return false;
55
59
  }
@@ -63,33 +67,33 @@ export function getReleaseFilename(version) {
63
67
 
64
68
  const filename =
65
69
  // macOS: as of 0.102.0, binaries are universal
66
- platform === "darwin" && arch === "x64" ?
67
- `hugo_extended_${version}_darwin-universal.tar.gz` :
68
- platform === "darwin" && arch === "arm64" ?
69
- `hugo_extended_${version}_darwin-universal.tar.gz` :
70
+ platform === "darwin" && arch === "x64"
71
+ ? `hugo_extended_${version}_darwin-universal.pkg`
72
+ : platform === "darwin" && arch === "arm64"
73
+ ? `hugo_extended_${version}_darwin-universal.pkg`
70
74
 
71
75
  // Windows
72
- platform === "win32" && arch === "x64" ?
73
- `hugo_extended_${version}_windows-amd64.zip` :
74
- platform === "win32" && arch === "arm64" ?
75
- `hugo_${version}_windows-arm64.zip` :
76
+ : platform === "win32" && arch === "x64"
77
+ ? `hugo_extended_${version}_windows-amd64.zip`
78
+ : platform === "win32" && arch === "arm64"
79
+ ? `hugo_${version}_windows-arm64.zip`
76
80
 
77
81
  // Linux
78
- platform === "linux" && arch === "x64" ?
79
- `hugo_extended_${version}_linux-amd64.tar.gz` :
80
- platform === "linux" && arch === "arm64" ?
81
- `hugo_extended_${version}_linux-arm64.tar.gz` :
82
+ : platform === "linux" && arch === "x64"
83
+ ? `hugo_extended_${version}_linux-amd64.tar.gz`
84
+ : platform === "linux" && arch === "arm64"
85
+ ? `hugo_extended_${version}_linux-arm64.tar.gz`
82
86
 
83
87
  // FreeBSD
84
- platform === "freebsd" && arch === "x64" ?
85
- `hugo_${version}_freebsd-amd64.tar.gz` :
88
+ : platform === "freebsd" && arch === "x64"
89
+ ? `hugo_${version}_freebsd-amd64.tar.gz`
86
90
 
87
91
  // OpenBSD
88
- platform === "openbsd" && arch === "x64" ?
89
- `hugo_${version}_openbsd-amd64.tar.gz` :
92
+ : platform === "openbsd" && arch === "x64"
93
+ ? `hugo_${version}_openbsd-amd64.tar.gz`
90
94
 
91
95
  // not gonna work :(
92
- null;
96
+ : null;
93
97
 
94
98
  return filename;
95
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hugo-extended",
3
- "version": "0.152.1",
3
+ "version": "0.153.0",
4
4
  "description": "✏️ Plug-and-play binary wrapper for Hugo Extended, the awesomest static-site generator.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/jakejarvis/hugo-extended",
@@ -13,6 +13,9 @@
13
13
  "type": "git",
14
14
  "url": "git+https://github.com/jakejarvis/hugo-extended.git"
15
15
  },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
16
19
  "files": [
17
20
  "index.js",
18
21
  "index.d.ts",
@@ -27,18 +30,24 @@
27
30
  "exports": "./index.js",
28
31
  "types": "./index.d.ts",
29
32
  "dependencies": {
30
- "careful-downloader": "^3.0.0",
31
- "log-symbols": "^5.1.0",
32
- "read-pkg-up": "^9.1.0"
33
+ "adm-zip": "^0.5.16",
34
+ "log-symbols": "^7.0.1",
35
+ "read-package-up": "^12.0.0",
36
+ "tar": "^7.5.2"
33
37
  },
34
38
  "devDependencies": {
35
- "@jakejarvis/eslint-config": "*",
36
- "del": "^7.1.0",
37
- "eslint": "^8.56.0",
38
- "mocha": "^10.3.0"
39
+ "@types/adm-zip": "^0.5.7",
40
+ "del": "^8.0.1",
41
+ "eslint": "^9.39.2",
42
+ "globals": "^16.5.0",
43
+ "mocha": "^11.7.5"
44
+ },
45
+ "scripts": {
46
+ "postinstall": "node postinstall.js",
47
+ "test": "eslint . && mocha"
39
48
  },
40
49
  "engines": {
41
- "node": ">=18.12"
50
+ "node": ">=18.17"
42
51
  },
43
52
  "keywords": [
44
53
  "hugo",
@@ -58,24 +67,5 @@
58
67
  "frontmatter",
59
68
  "go",
60
69
  "golang"
61
- ],
62
- "eslintConfig": {
63
- "extends": "@jakejarvis/eslint-config",
64
- "parserOptions": {
65
- "ecmaVersion": 2020,
66
- "sourceType": "module"
67
- },
68
- "env": {
69
- "node": true,
70
- "es6": true
71
- },
72
- "ignorePatterns": [
73
- "vendor/**",
74
- "*.d.ts"
75
- ]
76
- },
77
- "scripts": {
78
- "postinstall": "node postinstall.js",
79
- "test": "eslint . && mocha"
80
- }
81
- }
70
+ ]
71
+ }