diff --git a/deno.lock b/deno.lock index 90149d6..fb595bd 100644 --- a/deno.lock +++ b/deno.lock @@ -342,6 +342,52 @@ "https://deno.land/std@0.182.0/streams/reader_from_stream_reader.ts": "fa4971e5615a010e49492c5d1688ca1a4d17472a41e98b498ab89a64ebd7ac73", "https://deno.land/std@0.182.0/streams/write_all.ts": "aec90152978581ea62d56bb53a5cbf487e6a89c902f87c5969681ffbdf32b998", "https://deno.land/std@0.182.0/types.d.ts": "dbaeb2c4d7c526db9828fc8df89d8aecf53b9ced72e0c4568f97ddd8cda616a4", + "https://deno.land/std@0.188.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", + "https://deno.land/std@0.188.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", + "https://deno.land/std@0.188.0/bytes/bytes_list.ts": "31d664f4d42fa922066405d0e421c56da89d751886ee77bbe25a88bf0310c9d0", + "https://deno.land/std@0.188.0/bytes/concat.ts": "d26d6f3d7922e6d663dacfcd357563b7bf4a380ce5b9c2bbe0c8586662f25ce2", + "https://deno.land/std@0.188.0/bytes/copy.ts": "939d89e302a9761dcf1d9c937c7711174ed74c59eef40a1e4569a05c9de88219", + "https://deno.land/std@0.188.0/io/buf_reader.ts": "06fff3337091c49e99ebd2dd790c9a90364c087a2953ea081667400fd6c6cebb", + "https://deno.land/std@0.188.0/io/buf_writer.ts": "48c33c8f00b61dcbc7958706741cec8e59810bd307bc6a326cbd474fe8346dfd", + "https://deno.land/std@0.188.0/io/buffer.ts": "17f4410eaaa60a8a85733e8891349a619eadfbbe42e2f319283ce2b8f29723ab", + "https://deno.land/std@0.188.0/io/copy_n.ts": "0cc7ce07c75130f6fc18621ec1911c36e147eb9570664fee0ea12b1988167590", + "https://deno.land/std@0.188.0/io/limited_reader.ts": "6c9a216f8eef39c1ee2a6b37a29372c8fc63455b2eeb91f06d9646f8f759fc8b", + "https://deno.land/std@0.188.0/io/mod.ts": "2665bcccc1fd6e8627cca167c3e92aaecbd9897556b6f69e6d258070ef63fd9b", + "https://deno.land/std@0.188.0/io/multi_reader.ts": "9c2a0a31686c44b277e16da1d97b4686a986edcee48409b84be25eedbc39b271", + "https://deno.land/std@0.188.0/io/read_delim.ts": "c02b93cc546ae8caad8682ae270863e7ace6daec24c1eddd6faabc95a9d876a3", + "https://deno.land/std@0.188.0/io/read_int.ts": "7cb8bcdfaf1107586c3bacc583d11c64c060196cb070bb13ae8c2061404f911f", + "https://deno.land/std@0.188.0/io/read_lines.ts": "c526c12a20a9386dc910d500f9cdea43cba974e853397790bd146817a7eef8cc", + "https://deno.land/std@0.188.0/io/read_long.ts": "f0aaa420e3da1261c5d33c5e729f09922f3d9fa49f046258d4ff7a00d800c71e", + "https://deno.land/std@0.188.0/io/read_range.ts": "28152daf32e43dd9f7d41d8466852b0d18ad766cd5c4334c91fef6e1b3a74eb5", + "https://deno.land/std@0.188.0/io/read_short.ts": "805cb329574b850b84bf14a92c052c59b5977a492cd780c41df8ad40826c1a20", + "https://deno.land/std@0.188.0/io/read_string_delim.ts": "5dc9f53bdf78e7d4ee1e56b9b60352238ab236a71c3e3b2a713c3d78472a53ce", + "https://deno.land/std@0.188.0/io/slice_long_to_bytes.ts": "48d9bace92684e880e46aa4a2520fc3867f9d7ce212055f76ecc11b22f9644b7", + "https://deno.land/std@0.188.0/io/string_reader.ts": "da0f68251b3d5b5112485dfd4d1b1936135c9b4d921182a7edaf47f74c25cc8f", + "https://deno.land/std@0.188.0/io/string_writer.ts": "8a03c5858c24965a54c6538bed15f32a7c72f5704a12bda56f83a40e28e5433e", + "https://deno.land/std@0.188.0/streams/_common.ts": "f45cba84f0d813de3326466095539602364a9ba521f804cc758f7a475cda692d", + "https://deno.land/std@0.188.0/streams/buffer.ts": "d5b3d7d0299114e5b2ea895a8bf202a687fd915c5282f8096c7bae23b5a04407", + "https://deno.land/std@0.188.0/streams/byte_slice_stream.ts": "225d57263a34325d7c96cb3dafeb478eec0e6fd05cd0458d678752eadd132bb4", + "https://deno.land/std@0.188.0/streams/copy.ts": "75cbc795ff89291df22ddca5252de88b2e16d40c85d02840593386a8a1454f71", + "https://deno.land/std@0.188.0/streams/delimiter_stream.ts": "f69e849b3d1f59f02424497273f411105a6f76a9f13da92aeeb9a2d554236814", + "https://deno.land/std@0.188.0/streams/early_zip_readable_streams.ts": "4005fa74162b943f79899e5d7cb96adcbc0a6b867f9144974ed12d30e0a556e1", + "https://deno.land/std@0.188.0/streams/iterate_reader.ts": "bbec1d45c2df2c0c5920bad0549351446fdc8e0886d99e95959b259dbcdb6072", + "https://deno.land/std@0.188.0/streams/limited_bytes_transform_stream.ts": "05dc592ffaab83257494d22dd53917e56243c26e5e3129b3f13ddbbbc4785048", + "https://deno.land/std@0.188.0/streams/limited_transform_stream.ts": "d69ab790232c1b86f53621ad41ef03c235f2abb4b7a1cd51960ad6e12ee55e38", + "https://deno.land/std@0.188.0/streams/merge_readable_streams.ts": "5d6302888f4bb0616dafb5768771be0aec9bedc05fbae6b3d726d05ffbec5b15", + "https://deno.land/std@0.188.0/streams/mod.ts": "c07ec010e700b9ea887dc36ca08729828bc7912f711e4054e24d33fd46282252", + "https://deno.land/std@0.188.0/streams/read_all.ts": "ee319772fb0fd28302f97343cc48dfcf948f154fd0d755d8efe65814b70533be", + "https://deno.land/std@0.188.0/streams/readable_stream_from_iterable.ts": "cd4bb9e9bf6dbe84c213beb1f5085c326624421671473e410cfaecad15f01865", + "https://deno.land/std@0.188.0/streams/readable_stream_from_reader.ts": "bfc416c4576a30aac6b9af22c9dc292c20c6742141ee7c55b5e85460beb0c54e", + "https://deno.land/std@0.188.0/streams/reader_from_iterable.ts": "55f68110dce3f8f2c87b834d95f153bc904257fc65175f9f2abe78455cb8047c", + "https://deno.land/std@0.188.0/streams/reader_from_stream_reader.ts": "fa4971e5615a010e49492c5d1688ca1a4d17472a41e98b498ab89a64ebd7ac73", + "https://deno.land/std@0.188.0/streams/text_delimiter_stream.ts": "20e680ab8b751390e359288ce764f9c47d164af11a263870746eeca4bc7d976b", + "https://deno.land/std@0.188.0/streams/text_line_stream.ts": "0f2c4b33a5fdb2476f2e060974cba1347cefe99a4af33c28a57524b1a34750fa", + "https://deno.land/std@0.188.0/streams/to_transform_stream.ts": "7f55fc0b14cf3ed0f8d10d8f41d05bdc40726e44a65c37f58705d10a615f0159", + "https://deno.land/std@0.188.0/streams/writable_stream_from_writer.ts": "56fff5c82fb736fdd669b567cc0b2bbbe0351002cd13254eae26c366e2bed89a", + "https://deno.land/std@0.188.0/streams/write_all.ts": "aec90152978581ea62d56bb53a5cbf487e6a89c902f87c5969681ffbdf32b998", + "https://deno.land/std@0.188.0/streams/writer_from_stream_writer.ts": "07c7ee025151a190f37fc42cbb01ff93afc949119ebddc6e0d0df14df1bf6950", + "https://deno.land/std@0.188.0/streams/zip_readable_streams.ts": "a9d81aa451240f79230add674809dbee038d93aabe286e2d9671e66591fc86ca", + "https://deno.land/std@0.188.0/types.d.ts": "dbaeb2c4d7c526db9828fc8df89d8aecf53b9ced72e0c4568f97ddd8cda616a4", "https://deno.land/std@0.77.0/_util/assert.ts": "e1f76e77c5ccb5a8e0dbbbe6cce3a56d2556c8cb5a9a8802fc9565af72462149", "https://deno.land/std@0.77.0/flags/mod.ts": "1beaf22677d1d5fe13fb15b08552065aea032bca4a9664b73cad618d2c1f34ed", "https://deno.land/std@0.77.0/fmt/colors.ts": "c5665c66f1a67228f21c5989bbb04b36d369b98dd7ceac06f5e26856c81c2531", diff --git a/docs/started.md b/docs/started.md index 3d1bb76..6ceb6f8 100644 --- a/docs/started.md +++ b/docs/started.md @@ -61,4 +61,4 @@ deno run --allow-read --allow-env --allow-net --allow-run https://tepi.deno.dev/ * `--allow-read` Needed to read files from the file system. * `--allow-net` Needed to make HTTP requests. * `--allow-env` (optional) Needed to load and read environment variables. Required if you use the --env-file option. -* `--allow-run` (optional) Needed to run the upgrade command. Required if you use the --upgrade option. +* `--allow-run` (optional) Required if you use the --upgrade option. diff --git a/http/command.http b/http/command.http index 78acb11..828cc2d 100644 --- a/http/command.http +++ b/http/command.http @@ -1,28 +1,39 @@ --- host: <%= Deno.env.get('HOST') || 'https://faker.deno.dev' %> + --- ### --- id: run command with request -command: echo "with request" +command: echo "with request" && sleep 2 && echo "2s" --- -GET / +GET /?delay=1000 x-quiet: true ### + --- -id: run command with no request -command: echo "with NO request" && sleep 1 && echo "1s" && sleep 1 && echo "2s" +id: run command without request +command: echo "without request" +--- +### +--- +id: fail command +command: echo "fail command" && exit 133 --- - ### - --- -id: run command with timeout -timeout: 1000 -command: echo "with timeout && sleep 2" +id: log to stderr +command: sh toStderr.sh +ignore: true --- -### \ No newline at end of file +### +--- +id: run command without stdout +timeout: 2000 +command: sleep 5 +ignore: true +--- \ No newline at end of file diff --git a/http/debug.http b/http/debug.http index 02f4bdf..4a2fb7b 100644 --- a/http/debug.http +++ b/http/debug.http @@ -1,9 +1,4 @@ - -POST https://faker.deno.dev/pong -quiet: true -content-type: application/json - - -{ - "ping": "pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text pong long long very long text " -} +--- +id: fail command +command: echo "fail command" && exit 133 +--- diff --git a/src/command.ts b/src/command.ts index 3f2bb2c..9480495 100644 --- a/src/command.ts +++ b/src/command.ts @@ -1,39 +1,95 @@ import { Block } from "./types.ts"; -import $ from "https://deno.land/x/dax/mod.ts"; +import $ from "https://deno.land/x/dax@0.31.1/mod.ts"; import * as fmt from "https://deno.land/std@0.178.0/fmt/colors.ts"; import { DISPLAY_INDEX_MINIMAL, getDisplayIndex } from "./print.ts"; +import { getCmdSpinner } from "./logger.ts"; +import { deferred } from "https://deno.land/std@0.188.0/async/deferred.ts"; + +function mergeReadableStreams( + ...streams: ReadableStream[] +): ReadableStream { + const resolvePromises = streams.map(() => deferred()); + + return new ReadableStream({ + start(controller) { + Promise.all(resolvePromises).then(() => { + controller.close(); + }); + for (const [key, stream] of Object.entries(streams)) { + (async () => { + try { + for await (const data of stream) { + controller.enqueue(data); + } + resolvePromises[+key].resolve(); + + } catch (error) { + controller.error(error); + } + })(); + } + }, + }); +} export async function executeCommand(block: Block) { + + const command = block.meta.command?.trim(); if (!command) { return; } - const timeout = Number(block.meta.timeout) || 0; - - const displayIndex = getDisplayIndex(block.meta); - const cmd = $.raw`${command}`; - cmd.timeout(timeout); - - if (displayIndex > DISPLAY_INDEX_MINIMAL) { - console.info( - fmt.dim(`------- command output ------- `) - ); - cmd.printCommand(); - cmd.stderr("inheritPiped"); - cmd.stdout("inheritPiped"); - } else { - cmd.stderr("null"); - cmd.stdout("null"); - } - await cmd + let spinner; + let output = ""; + + // TODO: timeout + // const timeout = Number(block.meta.timeout) || 0; + + try { + const displayIndex = getDisplayIndex(block.meta); + if (displayIndex > DISPLAY_INDEX_MINIMAL) { + spinner = getCmdSpinner(command).start(); + const cmd = $.raw`${command}`; + + const child = cmd.stderr("piped").stdout('piped').spawn(); + // const stream = child.stdout(); + // TODO: merge stdout and stderr , and print them in order, now with mergeReadableStreams if the command fails it break execution + const stream = mergeReadableStreams(child.stdout(), child.stderr()); + for await (const chunk of stream) { + const text = new TextDecoder().decode(chunk); + if (!output) { + console.group(); + console.info( + fmt.dim(`------- output: ${command} ------- `) + ); + } + output += text; + console.info(text.replace(/\n$/, '')); + } + } else { + + await $.raw`${command}`.quiet() + // .timeout(timeout); + } + + if (output) { + console.info( + fmt.dim(`------- output end: ${command} ------- `) + ); + console.groupEnd(); + + } + spinner?.success(command); + } catch (error) { + + spinner?.fail(command); + const err = new Error(`command failed: ${command} \n ${error}`); + err.cause = error; + throw err - if (displayIndex > DISPLAY_INDEX_MINIMAL) { - console.info( - fmt.dim(`------- command output end ------- `) - ); } diff --git a/src/logger.ts b/src/logger.ts index 8dbf698..9301c74 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,5 +1,6 @@ -// TODO: fecth from deno.land/x +// TODO: fetch from deno.land/x import { wait } from "https://raw.githubusercontent.com/denosaurs/wait/main/mod.ts" +import * as fmt from "https://deno.land/std@0.178.0/fmt/colors.ts"; export const REFRESH_INTERVAL = 110; @@ -10,7 +11,7 @@ export function getSpinner(text: string) { prefix: "", text, spinner: "dots4", - color: "yellow", + color: "blue", interval: REFRESH_INTERVAL, discardStdin: true, }); @@ -18,6 +19,42 @@ export function getSpinner(text: string) { } +export function getCmdSpinner(text: string) { + + const spinner = wait({ + + text: fmt.blue("$") + " " + text, + spinner: "clock", + color: "green", + interval: REFRESH_INTERVAL, + discardStdin: true, + }); + const self = { + start: () => { + spinner.start(); + return self; + }, + success: (text: string) => { + spinner.stopAndPersist({ + symbol: ' ' + fmt.green("$"), + + text, + }) + }, + fail: (text: string) => { + spinner.stopAndPersist({ + symbol: ' ' + fmt.red("$"), + text, + + }) + } + } + + return self + +} + + export function log(text: string) { return getSpinner(text).start(); diff --git a/src/print.ts b/src/print.ts index b887e24..88b415b 100644 --- a/src/print.ts +++ b/src/print.ts @@ -445,7 +445,7 @@ export function createBlockSpinner( const text = `${fmt.white(block.description)} ${" "} ${fmt.gray(`${ms(_elapsedTime)}`) }${differentFile}`; - const symbol = fmt.yellow("ยท"); + const symbol = fmt.yellow("-"); clearInterval(id); if (globalMeta._noAnimation) { @@ -499,6 +499,7 @@ export function createBlockSpinner( text, }); }, + update, }; } diff --git a/src/runner.ts b/src/runner.ts index d882383..720d01b 100644 --- a/src/runner.ts +++ b/src/runner.ts @@ -281,7 +281,10 @@ async function runBlock( } if (block.meta.command) { + spinner.clear(); await executeCommand(block); + spinner.start(); + } if (!block.request) {