Skip to content

Commit

Permalink
add parsing env file
Browse files Browse the repository at this point in the history
  • Loading branch information
sirenkovladd committed Nov 18, 2023
1 parent fe2a9c1 commit 23597c3
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 7 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,22 @@ should not be re-used.
}
```

### Parsing the env file

```json
{
"wireit": {
"my-script": {
"command": "my-command",
"env-file": [
".env",
".dev.env"
]
}
}
}
```

## Services

By default, Wireit assumes that your scripts will eventually exit by themselves.
Expand Down
7 changes: 7 additions & 0 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@
}
]
}
},
"env-file": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
}
}
},
"type": "object"
Expand Down
79 changes: 72 additions & 7 deletions src/analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {
} from './config.js';
import type {Agent} from './cli-options.js';
import {Logger} from './logging/logger.js';
import {readEnvFile} from './read-env-file.js';

export interface AnalyzeResult {
config: Result<ScriptConfig, Failure[]>;
Expand Down Expand Up @@ -630,7 +631,12 @@ export class Analyzer {
files,
);

const env = this.#processEnv(placeholder, packageJson, syntaxInfo, command);
const entries = this.#processEnv(placeholder, packageJson, syntaxInfo, command);
await this.#processEnvFile(placeholder, packageJson, syntaxInfo, command, entries);

// Sort for better fingerprint match rate.
entries.sort();
const env = Object.fromEntries(entries);

if (placeholder.failures.length > 0) {
// A script with locally-determined errors doesn't get upgraded to
Expand Down Expand Up @@ -1319,13 +1325,13 @@ export class Analyzer {
packageJson: PackageJson,
syntaxInfo: ScriptSyntaxInfo,
command: JsonAstNode<string> | undefined,
): Record<string, string> {
): Array<[string, string]> {
if (syntaxInfo.wireitConfigNode === undefined) {
return {};
return [];
}
const envNode = findNodeAtLocation(syntaxInfo.wireitConfigNode, ['env']);
if (envNode === undefined) {
return {};
return [];
}
if (command === undefined) {
placeholder.failures.push({
Expand Down Expand Up @@ -1358,7 +1364,7 @@ export class Analyzer {
});
}
if (envNode.children === undefined) {
return {};
return [];
}
const entries: Array<[string, string]> = [];
for (const propNode of envNode.children) {
Expand Down Expand Up @@ -1428,8 +1434,67 @@ export class Analyzer {
}
}
// Sort for better fingerprint match rate.
entries.sort();
return Object.fromEntries(entries);
return entries;
}

async #processEnvFile(
placeholder: UnvalidatedConfig,
packageJson: PackageJson,
syntaxInfo: ScriptSyntaxInfo,
command: JsonAstNode<string> | undefined,
entries: Array<[string, string]>
): Promise<void> {
if (syntaxInfo.wireitConfigNode === undefined) {
return;
}
const envFileNode = findNodeAtLocation(syntaxInfo.wireitConfigNode, ['env-file']);
if (envFileNode === undefined) {
return;
}
if (command === undefined) {
placeholder.failures.push({
type: 'failure',
reason: 'invalid-config-syntax',
script: placeholder,
diagnostic: {
severity: 'error',
message: 'Can\'t set "env-file" unless "command" is set',
location: {
file: packageJson.jsonFile,
range: {length: envFileNode.length, offset: envFileNode.offset},
},
},
});
}
if (envFileNode.type !== 'array') {
placeholder.failures.push({
type: 'failure',
reason: 'invalid-config-syntax',
script: placeholder,
diagnostic: {
severity: 'error',
message: 'Expected an array',
location: {
file: packageJson.jsonFile,
range: {length: envFileNode.length, offset: envFileNode.offset},
},
},
});
}
if (envFileNode.children === undefined) {
return;
}
const promiseEnvFiles: Array<Promise<void>> = [];
for (const propNode of envFileNode.children) {
if (propNode.type !== 'string') {
throw new Error(
'Internal error: expected array JSON node child to be string',
);
}
const envFile = propNode.value as string;
promiseEnvFiles.push(readEnvFile(envFile, entries));
}
await Promise.all(promiseEnvFiles);
}

/**
Expand Down
33 changes: 33 additions & 0 deletions src/read-env-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/

import {readFile, stat} from 'node:fs/promises';

// TODO string-template-parser

export async function readEnvFile(filepath: string, entries: Array<[string, string]>): Promise<void> {
const fileStat = await stat(filepath);
if (!fileStat.isFile()) {
console.warn('Skipping non-file env file: ' + filepath);
return;
}
const content = await readFile(filepath, 'utf8');
const lines = content.split('\n');
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith('#')) {
continue;
}
const [key, ...rest] = trimmed.split('=');
if (rest.length === 0) {
continue;
}
const value = rest.join('=');
if (typeof key === 'string' && typeof value === 'string') {
entries.push([key, value]);
}
}
}

0 comments on commit 23597c3

Please sign in to comment.