Skip to content

Commit

Permalink
feat: add printenv command (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigmaSd authored Jun 4, 2023
1 parent f108c11 commit 7b5b33e
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,7 @@ Currently implemented (though not every option is supported):
- [`touch`](https://man7.org/linux/man-pages/man1/touch.1.html) - Creates a file (note: flags have not been implemented yet).
- [`unset`](https://man7.org/linux/man-pages/man1/unset.1p.html) - Unsets an environment variable.
- [`cat`](https://man7.org/linux/man-pages/man1/cat.1.html) - Concatenate files and print on the standard output
- [`printenv`](https://man7.org/linux/man-pages/man1/printenv.1.html) - Print all or part of environment
- More to come. Will try to get a similar list as https://deno.land/manual/tools/task_runner#built-in-commands

You can also register your own commands with the shell parser (see below).
Expand Down
30 changes: 30 additions & 0 deletions mod.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import $, { build$, CommandBuilder, CommandContext, CommandHandler } from "./mod
import {
assert,
assertEquals,
assertMatch,
assertRejects,
assertStringIncludes,
assertThrows,
Expand Down Expand Up @@ -1463,3 +1464,32 @@ Deno.test("cat", async () => {
}
});
});

Deno.test("printenv", async () => {
{
const result = await $`printenv`.env("hello", "world").env("ab", "cd").text();
if (Deno.build.os === "windows") {
assertMatch(result, /HELLO=world/);
assertMatch(result, /AB=cd/);
} else {
assertMatch(result, /hello=world/);
assertMatch(result, /ab=cd/);
}
}
{
const result = await $`printenv hello ab`.env("hello", "world").env("ab", "cd").stdout("piped");
assertEquals(result.code, 0);
assertEquals(result.stdout, "world\ncd\n");
}
if (Deno.build.os === "windows") {
// windows is case insensitive
const result = await $`printenv HeLlO aB`.env("hello", "world").env("ab", "cd").stdout("piped");
assertEquals(result.code, 0);
assertEquals(result.stdout, "world\ncd\n");
}
{
const result = await $`printenv hello doesntExist`.env("hello", "world").env("ab", "cd").noThrow().stdout("piped");
assertEquals(result.code, 1);
assertEquals(result.stdout, "world\n");
}
});
2 changes: 2 additions & 0 deletions src/command.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CommandHandler } from "./command_handler.ts";
import { cdCommand } from "./commands/cd.ts";
import { printEnvCommand } from "./commands/printenv.ts";
import { cpCommand, mvCommand } from "./commands/cp_mv.ts";
import { echoCommand } from "./commands/echo.ts";
import { catCommand } from "./commands/cat.ts";
Expand Down Expand Up @@ -50,6 +51,7 @@ const textDecoder = new TextDecoder();

const builtInCommands = {
cd: cdCommand,
printenv: printEnvCommand,
echo: echoCommand,
cat: catCommand,
exit: exitCommand,
Expand Down
1 change: 1 addition & 0 deletions src/command_handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface CommandPipeWriter extends Deno.WriterSync {
export interface CommandContext {
get args(): string[];
get cwd(): string;
get env(): Record<string, string>;
get stdin(): CommandPipeReader;
get stdout(): CommandPipeWriter;
get stderr(): CommandPipeWriter;
Expand Down
47 changes: 47 additions & 0 deletions src/commands/printenv.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { CommandContext } from "../command_handler.ts";
import { ExecuteResult, resultFromCode } from "../result.ts";

export function printEnvCommand(context: CommandContext): ExecuteResult {
// windows expects env vars to be upcased
let args;
if (Deno.build.os === "windows") {
args = context.args.map((arg) => arg.toUpperCase());
} else {
args = context.args;
}

try {
const result = executePrintEnv(context.env, args);
context.stdout.writeLine(result);
if (args.some((arg) => context.env[arg] === undefined)) {
return resultFromCode(1);
}
return resultFromCode(0);
} catch (err) {
context.stderr.writeLine(`printenv: ${err?.message ?? err}`);
return resultFromCode(1);
}
}

/**
* follows printenv on linux:
* - if arguments are provided, return a string containing a list of all env variables as `repeat(KEY=VALUE\n)`
* - if no arguments are provided, return a string containing a list of the values of the provided env vars as `repeat(VALUE\n)`
*/
function executePrintEnv(env: Record<string, string>, args: string[]) {
const isWindows = Deno.build.os === "windows";
if (args.length === 0) {
return Object.entries(env)
// on windows, env vars are case insensitive
.map(([key, val]) => `${isWindows ? key.toUpperCase() : key}=${val}`)
.join("\n");
} else {
if (isWindows) {
args = args.map((arg) => arg.toUpperCase());
}
return Object.entries(env)
.filter(([key]) => args.includes(key))
.map(([_key, val]) => val)
.join("\n");
}
}
1 change: 1 addition & 0 deletions src/deps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createPathRef, PathRef } from "./path.ts";
export {
assert,
assertEquals,
assertMatch,
assertRejects,
assertStringIncludes,
assertThrows,
Expand Down
3 changes: 3 additions & 0 deletions src/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ export class Context {
get cwd() {
return context.getCwd();
},
get env() {
return context.getEnvVars();
},
get stdin() {
return context.stdin;
},
Expand Down

0 comments on commit 7b5b33e

Please sign in to comment.