]> git.wincent.com - wincent.git/blob - src/Fig/operations/template.ts
refactor: prepare to implement chown etc
[wincent.git] / src / Fig / operations / template.ts
1 import * as fs from 'fs';
2
3 import ErrorWithMetadata from '../../ErrorWithMetadata';
4 import {log} from '../../console';
5 import expand from '../../expand';
6 import run from '../../run';
7 import tempfile from '../../tempfile';
8 import {compile, fill} from '../../template';
9 import Context from '../Context';
10 import compare from '../compare';
11
12 export default async function template({
13   force,
14   group,
15   mode,
16   owner,
17   path,
18   src,
19   variables = {},
20 }: {
21   force?: boolean;
22   group?: string;
23   path: string;
24   mode?: Mode;
25   owner?: string;
26   src: string;
27   variables: Variables;
28 }): Promise<void> {
29   const target = expand(path);
30
31   const contents = (await Context.compile(src)).fill({variables});
32
33   const diff = await compare({
34     contents,
35     force,
36     group,
37     mode,
38     owner,
39     path: target,
40     state: 'file',
41   });
42
43   if (owner && owner !== Context.attributes.username) {
44     log.notice(`needs sudo: ${Context.attributes.username} -> ${owner}`);
45     const passphrase = await Context.sudoPassphrase;
46     const result = await run('ls', ['-l', '/var/audit'], {passphrase});
47
48     if (result.status !== 0) {
49       throw new ErrorWithMetadata(`Failed command`, {
50         ...result,
51         error: result.error?.toString() ?? null,
52       });
53     }
54   } else {
55     if (diff.contents) {
56       log.info('change!');
57       const temp = await tempfile(contents);
58
59       // TODO: cp from temp to target
60       // TODO: deal with group/owner/mode etc
61     } else {
62       Context.informOk(`template ${path}`);
63     }
64   }
65 }