@dagu-org/dagu 1.17.4 → 1.23.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > A powerful Workflow Orchestration Engine with simple declarative YAML API
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@dagu-org/dagu.svg)](https://www.npmjs.com/package/@dagu-org/dagu)
5
+ [![npm version](https://img.shields.io/npm/v/%40dagu-org%2Fdagu.svg)](https://www.npmjs.com/package/@dagu-org/dagu)
6
6
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
7
7
 
8
8
  ## Installation
@@ -81,4 +81,4 @@ For detailed documentation, visit: https://github.com/dagu-org/dagu
81
81
 
82
82
  ## License
83
83
 
84
- GNU General Public License v3.0
84
+ GNU General Public License v3.0
package/bin/cli ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ const path = require("path");
4
+ const childProcess = require("child_process");
5
+
6
+ const { getPlatformPackage } = require("../lib/platform");
7
+
8
+ const binaryName = process.platform === "win32" ? "dagu.exe" : "dagu";
9
+
10
+ function getBinaryPath() {
11
+ const platformSpecificPackageName = getPlatformPackage();
12
+
13
+ try {
14
+ return require.resolve(`${platformSpecificPackageName}/bin/${binaryName}`);
15
+ } catch (e) {
16
+ return path.join(__dirname, "..", binaryName);
17
+ }
18
+ }
19
+
20
+ function exitForError(error) {
21
+ if (error && typeof error.status === "number") {
22
+ process.exit(error.status);
23
+ }
24
+
25
+ if (error && error.signal) {
26
+ process.kill(process.pid, error.signal);
27
+ return;
28
+ }
29
+
30
+ const message = error && typeof error.message === "string" ? error.message : "dagu execution failed";
31
+ if (message) {
32
+ process.stderr.write(`${message}\n`);
33
+ }
34
+
35
+ process.exit(1);
36
+ }
37
+
38
+ try {
39
+ childProcess.execFileSync(getBinaryPath(), process.argv.slice(2), {
40
+ stdio: "inherit",
41
+ });
42
+ } catch (error) {
43
+ exitForError(error);
44
+ }
package/index.js CHANGED
@@ -1,84 +1,43 @@
1
- /**
2
- * Dagu npm package - programmatic interface
3
- */
1
+ const path = require("path");
2
+ const childProcess = require("child_process");
4
3
 
5
- const { getBinaryPath } = require('./lib/platform');
6
- const { spawn } = require('child_process');
7
- const path = require('path');
4
+ const { getPlatformPackage } = require("./lib/platform");
8
5
 
9
- /**
10
- * Get the path to the Dagu binary
11
- * @returns {string|null} Path to the binary or null if not found
12
- */
13
- function getDaguPath() {
14
- return getBinaryPath();
15
- }
6
+ const binaryName = process.platform === "win32" ? "dagu.exe" : "dagu";
16
7
 
17
- /**
18
- * Execute Dagu with given arguments
19
- * @param {string[]} args Command line arguments
20
- * @param {object} options Child process spawn options
21
- * @returns {ChildProcess} The spawned child process
22
- */
23
- function execute(args = [], options = {}) {
24
- const binaryPath = getDaguPath();
25
-
26
- if (!binaryPath) {
27
- throw new Error('Dagu binary not found. Please ensure Dagu is properly installed.');
8
+ function getBinaryPath() {
9
+ try {
10
+ const platformSpecificPackageName = getPlatformPackage();
11
+ return require.resolve(`${platformSpecificPackageName}/bin/${binaryName}`);
12
+ } catch (e) {
13
+ return path.join(__dirname, "..", binaryName);
28
14
  }
29
-
30
- return spawn(binaryPath, args, {
31
- stdio: 'inherit',
32
- ...options
33
- });
34
15
  }
35
16
 
36
- /**
37
- * Execute Dagu and return a promise
38
- * @param {string[]} args Command line arguments
39
- * @param {object} options Child process spawn options
40
- * @returns {Promise<{code: number, signal: string|null}>} Exit code and signal
41
- */
42
- function executeAsync(args = [], options = {}) {
43
- return new Promise((resolve, reject) => {
44
- const child = execute(args, {
45
- stdio: 'pipe',
46
- ...options
47
- });
48
-
49
- let stdout = '';
50
- let stderr = '';
51
-
52
- if (child.stdout) {
53
- child.stdout.on('data', (data) => {
54
- stdout += data.toString();
55
- });
56
- }
57
-
58
- if (child.stderr) {
59
- child.stderr.on('data', (data) => {
60
- stderr += data.toString();
61
- });
62
- }
63
-
64
- child.on('error', reject);
65
-
66
- child.on('close', (code, signal) => {
67
- resolve({
68
- code,
69
- signal,
70
- stdout,
71
- stderr
72
- });
73
- });
74
- });
17
+ function exitForError(error) {
18
+ if (error && typeof error.status === "number") {
19
+ process.exit(error.status);
20
+ }
21
+
22
+ if (error && error.signal) {
23
+ process.kill(process.pid, error.signal);
24
+ return;
25
+ }
26
+
27
+ const message = error && typeof error.message === "string" ? error.message : "dagu execution failed";
28
+ if (message) {
29
+ process.stderr.write(`${message}\n`);
30
+ }
31
+
32
+ process.exit(1);
75
33
  }
76
34
 
77
- module.exports = {
78
- getDaguPath,
79
- execute,
80
- executeAsync,
81
- // Re-export useful functions
82
- getBinaryPath,
83
- getPlatformInfo: require('./lib/platform').getPlatformInfo
84
- };
35
+ module.exports.runBinary = function (...args) {
36
+ try {
37
+ childProcess.execFileSync(getBinaryPath(), args, {
38
+ stdio: "inherit",
39
+ });
40
+ } catch (error) {
41
+ exitForError(error);
42
+ }
43
+ };
package/install.js CHANGED
@@ -1,135 +1,109 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { getBinaryPath, getPlatformPackage, setPlatformBinary, getPlatformInfo } = require('./lib/platform');
6
- const { downloadBinary, downloadBinaryFromNpm } = require('./lib/download');
7
- const { validateBinary } = require('./lib/validate');
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const zlib = require("zlib");
6
+ const https = require("https");
8
7
 
9
- async function install() {
10
- console.log('Installing Dagu...');
11
-
12
- try {
13
- // Check if running in CI or with --ignore-scripts
14
- if (process.env.npm_config_ignore_scripts === 'true') {
15
- console.log('Skipping postinstall script (--ignore-scripts flag detected)');
16
- return;
17
- }
18
-
19
- // Try to resolve platform-specific package
20
- const platformPackage = getPlatformPackage();
21
- if (!platformPackage) {
22
- console.error(`
23
- Error: Unsupported platform: ${process.platform}-${process.arch}
8
+ const { getPlatformPackage, isPlatformSpecificPackageInstalled } = require("./lib/platform");
24
9
 
25
- Dagu does not provide pre-built binaries for this platform.
26
- Please build from source: https://github.com/dagu-org/dagu#building-from-source
27
- `);
28
- process.exit(1);
29
- }
30
-
31
- console.log(`Detected platform: ${process.platform}-${process.arch}`);
32
- console.log(`Looking for package: ${platformPackage}`);
33
-
34
- // Check for cross-platform scenario
35
- const { checkCrossPlatformScenario } = require('./lib/platform');
36
- const crossPlatformWarning = checkCrossPlatformScenario();
37
- if (crossPlatformWarning) {
38
- console.warn(`\n${crossPlatformWarning.message}\n`);
39
- }
40
-
41
- // Check if binary already exists from optionalDependency
42
- const existingBinary = getBinaryPath();
43
- if (existingBinary && fs.existsSync(existingBinary)) {
44
- console.log('Using pre-installed binary from optional dependency');
45
-
46
- // Validate the binary
47
- if (await validateBinary(existingBinary)) {
48
- console.log('✓ Dagu installation complete!');
49
- return;
50
- } else {
51
- console.warn('Binary validation failed, attempting to download...');
52
- }
53
- }
54
- } catch (e) {
55
- console.log('Optional dependency not found, downloading binary...');
56
- }
57
-
58
- // Fallback: Download binary
59
- try {
60
- const binaryPath = path.join(__dirname, 'bin', process.platform === 'win32' ? 'dagu.exe' : 'dagu');
61
-
62
- // Create bin directory if it doesn't exist
63
- const binDir = path.dirname(binaryPath);
64
- if (!fs.existsSync(binDir)) {
65
- fs.mkdirSync(binDir, { recursive: true });
66
- }
67
-
68
- // Skip download in development if flag file exists
69
- if (fs.existsSync(path.join(__dirname, '.skip-install'))) {
70
- console.log('Development mode: skipping binary download (.skip-install file found)');
71
- return;
72
- }
73
-
74
- // Download the binary
75
- await downloadBinary(binaryPath, { method: 'auto' });
76
-
77
- // Validate the downloaded binary
78
- if (await validateBinary(binaryPath)) {
79
- setPlatformBinary(binaryPath);
80
- console.log('✓ Dagu installation complete!');
81
-
82
- // Print warning about optionalDependencies if none were found
83
- if (!hasAnyOptionalDependency()) {
84
- console.warn(`
85
- ⚠ WARNING: optionalDependencies may be disabled in your environment.
86
- For better performance and reliability, consider enabling them.
87
- See: https://docs.npmjs.com/cli/v8/using-npm/config#optional
88
- `);
89
- }
90
- } else {
91
- throw new Error('Downloaded binary validation failed');
92
- }
93
- } catch (error) {
94
- console.error('Failed to install Dagu:', error.message);
95
- console.error(`
96
- Platform details:
97
- ${JSON.stringify(getPlatformInfo(), null, 2)}
10
+ // Windows binaries end with .exe so we need to special case them.
11
+ const binaryName = process.platform === "win32" ? "dagu.exe" : "dagu";
98
12
 
99
- Please try one of the following:
100
- 1. Install manually from: https://github.com/dagu-org/dagu/releases
101
- 2. Build from source: https://github.com/dagu-org/dagu#building-from-source
102
- 3. Report this issue: https://github.com/dagu-org/dagu/issues
103
- `);
104
- process.exit(1);
105
- }
13
+ // Adjust the version you want to install. You can also make this dynamic.
14
+ const PACKAGE_VERSION = require("./package.json").version;
15
+
16
+ // Compute the path we want to emit the fallback binary to
17
+ const fallbackBinaryPath = path.join(__dirname, binaryName);
18
+
19
+ function makeRequest(url) {
20
+ return new Promise((resolve, reject) => {
21
+ https
22
+ .get(url, (response) => {
23
+ if (response.statusCode >= 200 && response.statusCode < 300) {
24
+ const chunks = [];
25
+ response.on("data", (chunk) => chunks.push(chunk));
26
+ response.on("end", () => {
27
+ resolve(Buffer.concat(chunks));
28
+ });
29
+ } else if (
30
+ response.statusCode >= 300 &&
31
+ response.statusCode < 400 &&
32
+ response.headers.location
33
+ ) {
34
+ // Follow redirects
35
+ makeRequest(response.headers.location).then(resolve, reject);
36
+ } else {
37
+ reject(
38
+ new Error(
39
+ `npm responded with status code ${response.statusCode} when downloading the package!`
40
+ )
41
+ );
42
+ }
43
+ })
44
+ .on("error", (error) => {
45
+ reject(error);
46
+ });
47
+ });
106
48
  }
107
49
 
108
- // Check if any optional dependency is installed
109
- function hasAnyOptionalDependency() {
110
- const pkg = require('./package.json');
111
- const optionalDeps = Object.keys(pkg.optionalDependencies || {});
112
-
113
- for (const dep of optionalDeps) {
114
- try {
115
- require.resolve(dep);
116
- return true;
117
- } catch (e) {
118
- // Continue checking
50
+ function extractFileFromTarball(tarballBuffer, filepath) {
51
+ // Tar archives are organized in 512 byte blocks.
52
+ // Blocks can either be header blocks or data blocks.
53
+ // Header blocks contain file names of the archive in the first 100 bytes, terminated by a null byte.
54
+ // The size of a file is contained in bytes 124-135 of a header block and in octal format.
55
+ // The following blocks will be data blocks containing the file.
56
+ let offset = 0;
57
+ while (offset < tarballBuffer.length) {
58
+ const header = tarballBuffer.subarray(offset, offset + 512);
59
+ offset += 512;
60
+
61
+ const fileName = header.toString("utf-8", 0, 100).replace(/\0.*/g, "");
62
+ const fileSize = parseInt(
63
+ header.toString("utf-8", 124, 136).replace(/\0.*/g, ""),
64
+ 8
65
+ );
66
+
67
+ if (fileName === filepath) {
68
+ return tarballBuffer.subarray(offset, offset + fileSize);
119
69
  }
70
+
71
+ // Clamp offset to the uppoer multiple of 512
72
+ offset = (offset + fileSize + 511) & ~511;
120
73
  }
121
-
122
- return false;
123
74
  }
124
75
 
125
- // Handle errors gracefully
126
- process.on('unhandledRejection', (error) => {
127
- console.error('Installation error:', error);
128
- process.exit(1);
129
- });
76
+ async function downloadBinaryFromNpm() {
77
+ console.log({
78
+ getPlatformPackage,
79
+ });
80
+ // Determine package name for this platform
81
+ const platformSpecificPackageName = getPlatformPackage();
82
+
83
+ const url = `https://registry.npmjs.org/@dagu-org/${platformSpecificPackageName}/-/${platformSpecificPackageName}-${PACKAGE_VERSION}.tgz`;
84
+ console.log(`Downloading binary distribution package from ${url}...`);
85
+ // Download the tarball of the right binary distribution package
86
+ const tarballDownloadBuffer = await makeRequest(url);
87
+ const tarballBuffer = zlib.unzipSync(tarballDownloadBuffer);
130
88
 
131
- // Run installation
132
- install().catch((error) => {
133
- console.error('Installation failed:', error);
134
- process.exit(1);
135
- });
89
+ console.log(fallbackBinaryPath);
90
+
91
+ // Extract binary from package and write to disk
92
+ fs.writeFileSync(
93
+ fallbackBinaryPath,
94
+ extractFileFromTarball(tarballBuffer, `package/bin/${binaryName}`),
95
+ { mode: 0o755 } // Make binary file executable
96
+ );
97
+ }
98
+
99
+ // Skip downloading the binary if it was already installed via optionalDependencies
100
+ if (!isPlatformSpecificPackageInstalled()) {
101
+ console.log(
102
+ "Platform specific package not found. Will manually download binary."
103
+ );
104
+ downloadBinaryFromNpm();
105
+ } else {
106
+ console.log(
107
+ "Platform specific package already installed. Will fall back to manually downloading binary."
108
+ );
109
+ }