Skip to content

Commit 8893bad

Browse files
authored
Merge pull request #99 from oceanprotocol/issue-95-cli-loop
avoid cli to exit, loop commands
2 parents 3dc111e + 32a03a7 commit 8893bad

4 files changed

Lines changed: 130 additions & 19 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,5 @@ jobs:
160160
INDEXING_RETRY_INTERVAL: 4000
161161
INDEXING_MAX_RETRIES: 120
162162
NODE_URL: 'http://127.0.0.1:8001'
163+
AVOID_LOOP_RUN: true
163164

README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,36 +63,44 @@ export RPC='XXXX'
6363
export NODE_URL='XXXX'
6464
```
6565

66-
- Optional set metadataCache URL if you want to use a custom Aquarius version instead of the default one. This will not be used if you have set an Ocean Node url.
66+
- Optional, set metadataCache URL if you want to use a custom Aquarius version instead of the default one. This will not be used if you have set an Ocean Node url.
6767

6868
```
6969
export AQUARIUS_URL='XXXX'
7070
```
7171

72-
- Optional set Provider URL if you want to use a custom Provider version instead of the default one. This will not be used if you have set an Ocean Node url.
72+
- Optional, set Provider URL if you want to use a custom Provider version instead of the default one. This will not be used if you have set an Ocean Node url.
7373

7474
```
7575
export PROVIDER_URL='XXXX'
7676
```
7777

78-
- Optional set ADDRESS_FILE if you want to use a custom set of smart contract address
78+
- Optional, set ADDRESS_FILE if you want to use a custom set of smart contract address
7979

8080
```
8181
export ADDRESS_FILE='path-to-address-file'
8282
```
8383

84-
- Optional set INDEXING_MAX_RETRIES to the max number of retries when waiting for an asset to be indexed. Default is 100 retries max.
84+
- Optional, set INDEXING_MAX_RETRIES to the max number of retries when waiting for an asset to be indexed. Default is 100 retries max.
8585

8686
```
8787
export INDEXING_MAX_RETRIES='100'
8888
```
8989

90-
- Optional set INDEXING_RETRY_INTERVAL to the interval (in miliseconds) for each retry when waiting for an asset to be indexed. Default is 3 seconds.
90+
- Optional, set INDEXING_RETRY_INTERVAL to the interval (in miliseconds) for each retry when waiting for an asset to be indexed. Default is 3 seconds.
9191

9292
```
9393
export INDEXING_RETRY_INTERVAL='3000'
9494
```
9595

96+
- Optional, set AVOID_LOOP_RUN to 'true' to run each command and exit afterwards (usefull for CI test env and default behaviour). IF not set or set to 'false' the CLI will listen interactively for commands, until exit is manually forced
97+
98+
```
99+
export AVOID_LOOP_RUN='true/false'
100+
```
101+
102+
103+
96104
### Build the TypeScript code
97105

98106
```

src/cli.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ export async function createCLI() {
5656
const assetDid = options.did || did;
5757
if (!assetDid) {
5858
console.error(chalk.red('DID is required'));
59-
process.exit(1);
59+
// process.exit(1);
60+
return
6061
}
6162
const { signer, chainId } = await initializeSigner();
6263
const commands = new Commands(signer, chainId);
@@ -74,7 +75,8 @@ export async function createCLI() {
7475
const file = options.file || metadataFile;
7576
if (!file) {
7677
console.error(chalk.red('Metadata file is required'));
77-
process.exit(1);
78+
// process.exit(1);
79+
return
7880
}
7981
const { signer, chainId } = await initializeSigner();
8082
const commands = new Commands(signer, chainId);
@@ -92,7 +94,8 @@ export async function createCLI() {
9294
const file = options.file || metadataFile;
9395
if (!file) {
9496
console.error(chalk.red('Metadata file is required'));
95-
process.exit(1);
97+
// process.exit(1);
98+
return
9699
}
97100
const { signer, chainId } = await initializeSigner();
98101
const commands = new Commands(signer, chainId);
@@ -114,7 +117,8 @@ export async function createCLI() {
114117
const file = options.file || metadataFile;
115118
if (!dsDid || !file) {
116119
console.error(chalk.red('Dataset DID and metadata file are required'));
117-
process.exit(1);
120+
// process.exit(1);
121+
return
118122
}
119123
const { signer, chainId } = await initializeSigner();
120124
const commands = new Commands(signer, chainId);
@@ -134,7 +138,8 @@ export async function createCLI() {
134138
const destFolder = options.folder || folder || '.';
135139
if (!assetDid) {
136140
console.error(chalk.red('DID is required'));
137-
process.exit(1);
141+
// process.exit(1);
142+
return
138143
}
139144
const { signer, chainId } = await initializeSigner();
140145
const commands = new Commands(signer, chainId);
@@ -155,7 +160,8 @@ export async function createCLI() {
155160
const aDid = options.algo || algoDid;
156161
if (!dsDid || !aDid) {
157162
console.error(chalk.red('Dataset DID and Algorithm DID are required'));
158-
process.exit(1);
163+
// process.exit(1);
164+
return
159165
}
160166
const { signer, chainId } = await initializeSigner();
161167
const commands = new Commands(signer, chainId);
@@ -178,7 +184,8 @@ export async function createCLI() {
178184
const envId = options.env || computeEnvId;
179185
if (!dsDids || !aDid || !envId) {
180186
console.error(chalk.red('Missing required arguments'));
181-
process.exit(1);
187+
// process.exit(1);
188+
return
182189
}
183190
const { signer, chainId } = await initializeSigner();
184191
const commands = new Commands(signer, chainId);
@@ -201,7 +208,8 @@ export async function createCLI() {
201208
const envId = options.env || computeEnvId;
202209
if (!dsDids || !aDid || !envId) {
203210
console.error(chalk.red('Missing required arguments'));
204-
process.exit(1);
211+
// process.exit(1);
212+
return
205213
}
206214
const { signer, chainId } = await initializeSigner();
207215
const commands = new Commands(signer, chainId);
@@ -248,7 +256,8 @@ export async function createCLI() {
248256
const agrId = options.agreement || agreementId;
249257
if (!dsDid || !jId) {
250258
console.error(chalk.red('Dataset DID and Job ID are required'));
251-
process.exit(1);
259+
// process.exit(1);
260+
return
252261
}
253262
const { signer, chainId } = await initializeSigner();
254263
const commands = new Commands(signer, chainId);
@@ -273,7 +282,8 @@ export async function createCLI() {
273282
const agrId = options.agreement || agreementId;
274283
if (!dsDid || !jId) {
275284
console.error(chalk.red('Dataset DID and Job ID are required'));
276-
process.exit(1);
285+
// process.exit(1);
286+
return
277287
}
278288
const { signer, chainId } = await initializeSigner();
279289
const commands = new Commands(signer, chainId);

src/index.ts

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,110 @@
1+
import { sleep } from '@oceanprotocol/lib';
2+
import {createInterface} from "readline";
13
import { createCLI } from './cli.js';
24

5+
let program
6+
let exit = false
7+
const supportedCommands: string[] = []
8+
const initializeCommands: string[] = []
9+
10+
async function waitForCommands() {
11+
const commandLine = await readLine("Enter command ('exit' | 'quit' or CTRL-C to terminate'):\n")
12+
let command = null
13+
if(commandLine === "quit" || commandLine === "exit" || commandLine === "\\q") {
14+
exit = true
15+
return
16+
}
17+
18+
const commandSplitted: string[] = commandLine.split(" ")
19+
if(commandSplitted.length < 1) {
20+
console.log("Invalid command, missing one or more arguments!")
21+
return
22+
}
23+
24+
if(commandSplitted.length>=3) {
25+
if(commandSplitted[0] === "npm" && commandSplitted[1] === "run" && commandSplitted[2] === "cli") {
26+
commandSplitted.splice(0,3)
27+
command = commandSplitted.join(" ")
28+
}
29+
} else if(commandSplitted.length >= 1) {
30+
// just the command without npm run cli
31+
command = commandSplitted[0]
32+
}
33+
34+
if(command && command.length > 0 && commandSplitted.length>0) {
35+
const commandName = commandSplitted[0]
36+
const args = initializeCommands.concat(commandSplitted)
37+
38+
if(!supportedCommands.includes(commandName)) {
39+
console.log("Invalid option: ", commandName)
40+
return
41+
}
42+
43+
try {
44+
await program.parseAsync(args);
45+
}catch(error) {
46+
console.log('Command error: ', error)
47+
}
48+
}
49+
50+
}
51+
52+
async function readLine(question: string): Promise<string> {
53+
54+
const readLine = createInterface({
55+
input: process.stdin,
56+
output: process.stdout
57+
});
58+
59+
let answer = ""
60+
readLine.question(question, (it: string) => {
61+
answer = it.trim()
62+
readLine.close()
63+
})
64+
while (answer == "") { await sleep(100) }
65+
66+
return answer
67+
68+
}
369
async function main() {
470
try {
5-
const program = await createCLI();
71+
program = await createCLI();
72+
for(const command of program.commands) {
73+
supportedCommands.push(command.name())
74+
supportedCommands.push(command.alias())
75+
}
676

77+
console.log("Type 'exit' or 'quit' or 'CTRL-C' to terminate process")
778
// Handle help command without initializing signer
879
if (process.argv.includes('--help') || process.argv.includes('-h')) {
980
program.outputHelp();
10-
process.exit(0);
1181
}
1282

13-
await program.parseAsync(process.argv);
83+
const initialCommandLine:string [] = process.argv
84+
if(process.env.AVOID_LOOP_RUN !== 'true') {
85+
86+
do {
87+
program.exitOverride();
88+
try {
89+
if(initializeCommands.length === 0 && initialCommandLine.length > 2) {
90+
initializeCommands.push(initialCommandLine[0]) // node
91+
initializeCommands.push(initialCommandLine[1]) // file path
92+
// just once
93+
await program.parseAsync(initialCommandLine);
94+
}
95+
}catch(err) {
96+
// silently ignore
97+
}
98+
await waitForCommands()
99+
}while(!exit)
100+
} else {
101+
// one shot
102+
await program.parseAsync(initialCommandLine);
103+
}
104+
14105
} catch (error) {
15-
console.error('Error:', error.message);
106+
console.error('Program Error:', error.message);
107+
exit = true
16108
process.exit(1);
17109
}
18110
}

0 commit comments

Comments
 (0)