]> git.wincent.com - wincent.git/blobdiff - src/Fig/operations/template.ts
chore(fig): turn on more TypeScript checks
[wincent.git] / src / Fig / operations / template.ts
index 938d8807043f15d6f9902baf70584d5507347438..44334db6dfd64b7dd77687b4ea4a8987da811588 100644 (file)
@@ -1,62 +1,65 @@
-import * as fs from 'fs';
-
 import ErrorWithMetadata from '../../ErrorWithMetadata';
+import chown from '../../chown';
 import {log} from '../../console';
 import expand from '../../expand';
-import sudo from '../../sudo';
-import {compile, fill} from '../../template';
+import tempfile from '../../tempfile';
 import Context from '../Context';
+import compare from '../compare';
 
 export default async function template({
-  group,
-  mode,
-  owner,
-  path,
-  src,
-  variables = {},
+    force,
+    group,
+    mode,
+    owner,
+    path,
+    src,
+    variables = {},
 }: {
-  group?: string;
-  path: string;
-  mode?: string;
-  owner?: string;
-  src: string;
-  variables: Variables;
+    force?: boolean;
+    group?: string;
+    path: string;
+    mode?: Mode;
+    owner?: string;
+    src: string;
+    variables: Variables;
 }): Promise<void> {
-  const target = expand(path);
-  log.info(`template ${src} -> ${target}`);
-
-  const filled = (await Context.compile(src)).fill({variables});
+    const target = expand(path);
 
-  if (owner && owner !== Context.attributes.username) {
-    log.notice(`needs sudo: ${Context.attributes.username} -> ${owner}`);
-    const passphrase = await Context.sudoPassphrase;
-    const result = await sudo('ls', ['-l', '/var/audit'], {passphrase});
-
-    if (result.status !== 0) {
-      throw new ErrorWithMetadata(`Failed command`, {
-        ...result,
-        error: result.error?.toString() ?? null,
-      });
-    }
+    const contents = (await Context.compile(src)).fill({variables});
 
-    // chown in node works with numeric uid and gid
-  } else {
-    // open, write, mode
-    // can't chown, i think? without uid and gid
+    const diff = await compare({
+        contents,
+        force,
+        group,
+        mode,
+        owner,
+        path: target,
+        state: 'file',
+    });
 
-    // TODO extract this somewhere else
-    // need low-level filesystem ops that are consumed by the high-level
-    // user-accessible ops
-    let contents;
+    if (diff.state === 'file') {
+        // TODO: file does not exist — have to create it
+    } else if (diff.owner || diff.group) {
+        const result = await chown(target, {group, owner, sudo: true});
 
-    if (fs.existsSync(target)) {
-      contents = fs.readFileSync(target, 'utf8');
+        if (result instanceof Error) {
+            throw new ErrorWithMetadata(`Failed command`, {
+                error: result.toString(),
+                group: group ?? null,
+                owner: owner ?? null,
+                target,
+            });
+        }
+    } else {
+        if (diff.contents) {
+            // log.info('change!');
+            const temp = await tempfile(contents);
+            log.debug(`Wrote to temporary file: ${temp}`);
 
-      if (contents !== filled) {
-        log.info('change!');
-      } else {
-        log.info('no change');
-      }
+            // TODO: cp from temp to target
+            // TODO: deal with group/owner/mode etc
+        } else {
+            Context.informOk(`template ${path}`);
+        }
     }
-  }
 }