cobolx 1.0.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/Cargo.toml ADDED
@@ -0,0 +1,39 @@
1
+ [package]
2
+ name = "rdo"
3
+ version = "0.1.0"
4
+ edition = "2024"
5
+
6
+ [dependencies]
7
+ clap = { version = "4.5", features = ["derive"] }
8
+ serde = { version = "1.0", features = ["derive"] }
9
+ serde_json = "1.0"
10
+ colored = "2.1"
11
+ chrono = { version = "0.4", features = ["serde"] }
12
+ ratatui = "0.26"
13
+ crossterm = "0.27"
14
+ reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }
15
+ tokio = { version = "1", features = ["full"] }
16
+ directories = "5.0"
17
+ futures-util = "0.3"
18
+ rusqlite = { version = "0.40.1", features = ["bundled"] }
19
+
20
+ [dev-dependencies]
21
+ tempfile = "3.8"
22
+
23
+ [lints.rust]
24
+ unused_variables = "warn"
25
+ dead_code = "allow"
26
+
27
+ [lints.clippy]
28
+ collapsible_if = "allow"
29
+ new_without_default = "allow"
30
+ implicit_saturating_sub = "allow"
31
+ manual_div_ceil = "allow"
32
+ if_same_then_else = "allow"
33
+ module_inception = "allow"
34
+ unnecessary_map_or = "allow"
35
+ needless_range_loop = "allow"
36
+
37
+
38
+
39
+
@@ -0,0 +1,44 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const https = require('https');
4
+
5
+ const pkg = require('../package.json');
6
+ const noticeFile = path.join(__dirname, '.update-notice');
7
+
8
+ const options = {
9
+ hostname: 'registry.npmjs.org',
10
+ path: `/${pkg.name}/latest`,
11
+ timeout: 3000,
12
+ headers: {
13
+ 'User-Agent': 'cobolx-cli-update-checker'
14
+ }
15
+ };
16
+
17
+ const req = https.get(options, (res) => {
18
+ if (res.statusCode !== 200) return;
19
+ let data = '';
20
+ res.on('data', (chunk) => { data += chunk; });
21
+ res.on('end', () => {
22
+ try {
23
+ const info = JSON.parse(data);
24
+ const latest = info.version;
25
+ if (latest && latest !== pkg.version) {
26
+ const msg = [
27
+ '\x1b[33m---------------------------------------------------------\x1b[0m',
28
+ ` 💡 \x1b[36mUpdate available:\x1b[0m \x1b[32m${latest}\x1b[0m (current: ${pkg.version})`,
29
+ ` Run \x1b[33mnpm update -g ${pkg.name}\x1b[0m to update!`,
30
+ '\x1b[33m---------------------------------------------------------\x1b[0m'
31
+ ].join('\n');
32
+ fs.writeFileSync(noticeFile, msg, 'utf8');
33
+ }
34
+ } catch (e) {
35
+ // ignore
36
+ }
37
+ });
38
+ });
39
+
40
+ req.on('error', () => {
41
+ // ignore
42
+ });
43
+
44
+ req.end();
package/bin/cobolx.js ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+
7
+ const isWin = process.platform === 'win32';
8
+ const binName = isWin ? 'cobolx.exe' : 'cobolx';
9
+ const binaryPath = path.join(__dirname, binName);
10
+
11
+ if (!fs.existsSync(binaryPath)) {
12
+ console.error(`Error: Native binary not found at ${binaryPath}`);
13
+ console.error('Please try reinstalling the package: npm install -g cobolx');
14
+ process.exit(1);
15
+ }
16
+
17
+ // 1. Check for pending update notification from previous background checks
18
+ const noticeFile = path.join(__dirname, '.update-notice');
19
+ if (fs.existsSync(noticeFile)) {
20
+ try {
21
+ const notice = fs.readFileSync(noticeFile, 'utf8').trim();
22
+ if (notice) {
23
+ console.log('\n' + notice);
24
+ }
25
+ fs.unlinkSync(noticeFile);
26
+ } catch (err) {
27
+ // ignore
28
+ }
29
+ }
30
+
31
+ // 2. Start the native binary child process
32
+ const args = process.argv.slice(2);
33
+ const child = spawn(binaryPath, args, { stdio: 'inherit' });
34
+
35
+ child.on('error', (err) => {
36
+ console.error('Failed to start the native binary:', err);
37
+ process.exit(1);
38
+ });
39
+
40
+ child.on('close', (code) => {
41
+ // 3. Trigger background update check
42
+ triggerBackgroundUpdateCheck();
43
+ process.exit(code ?? 0);
44
+ });
45
+
46
+ function triggerBackgroundUpdateCheck() {
47
+ try {
48
+ const pkg = require('../package.json');
49
+ const cacheFile = path.join(__dirname, '.last-update-check');
50
+ const CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
51
+ const now = Date.now();
52
+
53
+ let lastCheck = 0;
54
+ if (fs.existsSync(cacheFile)) {
55
+ lastCheck = parseInt(fs.readFileSync(cacheFile, 'utf8'), 10) || 0;
56
+ }
57
+
58
+ if (now - lastCheck < CHECK_INTERVAL) {
59
+ return;
60
+ }
61
+
62
+ // Write new timestamp immediately to throttle requests
63
+ fs.writeFileSync(cacheFile, now.toString(), 'utf8');
64
+
65
+ // Spawn a detached background process to check for updates
66
+ const checkerScript = path.join(__dirname, 'check-update.js');
67
+
68
+ // Ignore outputs or pipe to a log file
69
+ const logFile = path.join(__dirname, '.checker-log');
70
+ const out = fs.openSync(logFile, 'a');
71
+
72
+ const child = spawn(process.execPath, [checkerScript], {
73
+ detached: true,
74
+ stdio: ['ignore', out, out]
75
+ });
76
+
77
+ child.unref();
78
+ } catch (err) {
79
+ // ignore
80
+ }
81
+ }
@@ -0,0 +1,33 @@
1
+ services:
2
+ dev:
3
+ build:
4
+ context: .
5
+ dockerfile: dockerfile
6
+ command: sleep infinity
7
+ stdin_open: true
8
+ tty: true
9
+ environment:
10
+ CARGO_TARGET_DIR: /workspaces/cobolX/target
11
+ RUST_BACKTRACE: "1"
12
+ volumes:
13
+ - .:/workspaces/cobolX:cached
14
+ - cargo-registry:/usr/local/cargo/registry
15
+ - cargo-git:/usr/local/cargo/git
16
+ - target-cache:/workspaces/cobolX/target
17
+
18
+ test:
19
+ profiles:
20
+ - test
21
+ build:
22
+ context: .
23
+ dockerfile: dockerfile.test
24
+ stdin_open: true
25
+ tty: true
26
+ environment:
27
+ RUST_BACKTRACE: "1"
28
+ TERM: xterm-256color
29
+
30
+ volumes:
31
+ cargo-registry:
32
+ cargo-git:
33
+ target-cache:
package/dockerfile ADDED
@@ -0,0 +1,18 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM mcr.microsoft.com/devcontainers/rust:1-bookworm
4
+
5
+ RUN apt-get update \
6
+ && apt-get install -y --no-install-recommends \
7
+ ca-certificates \
8
+ git \
9
+ pkg-config \
10
+ libssl-dev \
11
+ gdb \
12
+ lldb \
13
+ && rm -rf /var/lib/apt/lists/*
14
+
15
+ RUN mkdir -p /workspaces/cobolX/target \
16
+ && chown -R vscode:vscode /workspaces
17
+
18
+ WORKDIR /workspaces/cobolX
@@ -0,0 +1,39 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM rust:1-bookworm AS build
4
+
5
+ RUN apt-get update \
6
+ && apt-get install -y --no-install-recommends \
7
+ ca-certificates \
8
+ pkg-config \
9
+ libssl-dev \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ WORKDIR /app
13
+
14
+ COPY Cargo.toml Cargo.lock ./
15
+ COPY src ./src
16
+ COPY tests ./tests
17
+
18
+ ENV CARGO_TARGET_DIR=/app/target \
19
+ RUST_BACKTRACE=1
20
+
21
+ RUN cargo test --locked --release
22
+ RUN cargo build --locked --release
23
+
24
+ FROM debian:bookworm-slim AS runtime
25
+
26
+ RUN apt-get update \
27
+ && apt-get install -y --no-install-recommends \
28
+ ca-certificates \
29
+ libssl3 \
30
+ && rm -rf /var/lib/apt/lists/*
31
+
32
+ WORKDIR /app
33
+
34
+ COPY --from=build /app/target/release/rdo /usr/local/bin/rdo
35
+ COPY example /app/example
36
+ ENV RUST_BACKTRACE=1 \
37
+ TERM=xterm-256color
38
+
39
+ CMD ["rdo"]
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "cobolx",
3
+ "version": "1.0.0",
4
+ "description": "CobolX CLI",
5
+ "main": "bin/cobolx.js",
6
+ "bin": {
7
+ "cobolx": "./bin/cobolx.js"
8
+ },
9
+ "scripts": {
10
+ "postinstall": "node scripts/install.js"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/WSPlXA/cobolX.git"
15
+ },
16
+ "keywords": [
17
+ "cobol",
18
+ "rust",
19
+ "cli"
20
+ ],
21
+ "author": "WSPlXA",
22
+ "license": "MIT",
23
+ "bugs": {
24
+ "url": "https://github.com/WSPlXA/cobolX/issues"
25
+ },
26
+ "homepage": "https://github.com/WSPlXA/cobolX#readme"
27
+ }
@@ -0,0 +1,145 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const https = require('https');
4
+ const { execSync } = require('child_process');
5
+
6
+ const pkg = require('../package.json');
7
+ const version = pkg.version;
8
+ const repo = 'WSPlXA/cobolX';
9
+ const binDir = path.join(__dirname, '../bin');
10
+
11
+ // Map process.platform and process.arch to Rust target triples and archives
12
+ function getTarget() {
13
+ const platform = process.platform;
14
+ const arch = process.arch;
15
+
16
+ if (platform === 'win32' && arch === 'x64') {
17
+ return {
18
+ triple: 'x86_64-pc-windows-msvc',
19
+ ext: 'zip'
20
+ };
21
+ }
22
+ if (platform === 'darwin') {
23
+ if (arch === 'x64') {
24
+ return {
25
+ triple: 'x86_64-apple-darwin',
26
+ ext: 'tar.gz'
27
+ };
28
+ }
29
+ if (arch === 'arm64') {
30
+ return {
31
+ triple: 'aarch64-apple-darwin',
32
+ ext: 'tar.gz'
33
+ };
34
+ }
35
+ }
36
+ if (platform === 'linux') {
37
+ if (arch === 'x64') {
38
+ return {
39
+ triple: 'x86_64-unknown-linux-gnu',
40
+ ext: 'tar.gz'
41
+ };
42
+ }
43
+ if (arch === 'arm64') {
44
+ return {
45
+ triple: 'aarch64-unknown-linux-gnu',
46
+ ext: 'tar.gz'
47
+ };
48
+ }
49
+ }
50
+
51
+ throw new Error(`Unsupported platform/architecture: ${platform}/${arch}`);
52
+ }
53
+
54
+ function downloadFile(url, dest, callback) {
55
+ https.get(url, (res) => {
56
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
57
+ // Follow redirect
58
+ downloadFile(res.headers.location, dest, callback);
59
+ } else if (res.statusCode === 200) {
60
+ const file = fs.createWriteStream(dest);
61
+ res.pipe(file);
62
+ file.on('finish', () => {
63
+ file.close(callback);
64
+ });
65
+ } else {
66
+ callback(new Error(`Failed to download: HTTP ${res.statusCode} ${res.statusMessage}`));
67
+ }
68
+ }).on('error', (err) => {
69
+ callback(err);
70
+ });
71
+ }
72
+
73
+ function install() {
74
+ try {
75
+ const target = getTarget();
76
+ const archiveName = `rdo-${target.triple}.${target.ext}`;
77
+ const downloadUrl = `https://github.com/${repo}/releases/download/v${version}/${archiveName}`;
78
+ const tempFile = path.join(binDir, `temp-${archiveName}`);
79
+
80
+ console.log(`Downloading CobolX binary for ${target.triple}...`);
81
+
82
+ // Ensure bin directory exists
83
+ if (!fs.existsSync(binDir)) {
84
+ fs.mkdirSync(binDir, { recursive: true });
85
+ }
86
+
87
+ downloadFile(downloadUrl, tempFile, (err) => {
88
+ if (err) {
89
+ console.error('Error downloading binary:', err.message);
90
+ process.exit(1);
91
+ }
92
+
93
+ console.log('Extracting binary...');
94
+ try {
95
+ if (target.ext === 'zip') {
96
+ // Decompress zip on Windows using PowerShell
97
+ const cmd = `powershell -Command "Expand-Archive -Path '${tempFile}' -DestinationPath '${binDir}' -Force"`;
98
+ execSync(cmd, { stdio: 'inherit' });
99
+ } else {
100
+ // Decompress tar.gz on Unix
101
+ const cmd = `tar -xzf "${tempFile}" -C "${binDir}"`;
102
+ execSync(cmd, { stdio: 'inherit' });
103
+ }
104
+
105
+ // Clean up temp archive
106
+ fs.unlinkSync(tempFile);
107
+
108
+ // Rename the binary from 'rdo' to 'cobolx'
109
+ const rawBinName = target.ext === 'zip' ? 'rdo.exe' : 'rdo';
110
+ const finalBinName = target.ext === 'zip' ? 'cobolx.exe' : 'cobolx';
111
+
112
+ const rawBinPath = path.join(binDir, rawBinName);
113
+ const finalBinPath = path.join(binDir, finalBinName);
114
+
115
+ if (fs.existsSync(rawBinPath)) {
116
+ fs.renameSync(rawBinPath, finalBinPath);
117
+ } else {
118
+ // Check if it was already named correctly or packaged differently
119
+ if (!fs.existsSync(finalBinPath)) {
120
+ throw new Error(`Could not find extracted binary in ${binDir}`);
121
+ }
122
+ }
123
+
124
+ // Set execution permissions on Unix
125
+ if (target.ext !== 'zip') {
126
+ fs.chmodSync(finalBinPath, 0o755);
127
+ }
128
+
129
+ console.log('CobolX binary installed successfully.');
130
+ } catch (extractErr) {
131
+ console.error('Error extracting binary:', extractErr.message);
132
+ // Clean up temp file in case of failure
133
+ if (fs.existsSync(tempFile)) {
134
+ fs.unlinkSync(tempFile);
135
+ }
136
+ process.exit(1);
137
+ }
138
+ });
139
+ } catch (err) {
140
+ console.error('Installation failed:', err.message);
141
+ process.exit(1);
142
+ }
143
+ }
144
+
145
+ install();