axe312ger/sftp-cache

View on GitHub
src/diff.js

Summary

Maintainability
C
7 hrs
Test Coverage
const { resolve } = require('path')
const { difference, intersection, uniq } = require('lodash')

const { getLocalMd5 } = require('./filesystem')
const { getRemoteMd5 } = require('./sftp')

async function diff({ ssh, localMap, remoteMap, localDir, remoteDir }) {
  /**
   * find files missing local
   * find files missing remote
   * find files newer local
   * find files newer remote
   * find files size different
   */

  const missingLocal = difference(Object.keys(remoteMap), Object.keys(localMap))

  const missingRemote = difference(
    Object.keys(localMap),
    Object.keys(remoteMap)
  )

  const existing = intersection(Object.keys(localMap), Object.keys(remoteMap))

  const newerLocal = existing
    .map((path) => {
      const localFile = localMap[path]
      const remoteFile = remoteMap[path]

      if (localFile.stats.mtime > remoteFile.stats.mtime) {
        return path
      }
    })
    .filter(Boolean)

  const newerRemote = existing
    .map((path) => {
      const localFile = localMap[path]
      const remoteFile = remoteMap[path]

      if (remoteFile.stats.mtime > localFile.stats.mtime) {
        return path
      }
    })
    .filter(Boolean)

  const sizeDifferent = existing
    .map((path) => {
      const localFile = localMap[path]
      const remoteFile = remoteMap[path]

      if (remoteFile.stats.size !== localFile.stats.size) {
        return path
      }
    })
    .filter(Boolean)

  const md5Different = []

  // check files that differ in time but with same size
  const differentTimestamp = uniq([...newerLocal, ...newerRemote])
  const filesToCheck = difference(differentTimestamp, sizeDifferent)

  for (const path of filesToCheck) {
    const localFile = resolve(localDir, path)
    const remoteFile = resolve(remoteDir, path)

    const localMd5 = await getLocalMd5(localFile)
    const remoteMd5 = await getRemoteMd5({ ssh, path: remoteFile })

    if (localMd5 !== remoteMd5) {
      md5Different.push(path)
    }
  }

  const filesToDownload = uniq([
    ...missingLocal,
    ...sizeDifferent,
    ...md5Different
  ]).sort()

  const filesToUpload = uniq([
    ...missingRemote,
    ...sizeDifferent,
    ...md5Different
  ]).sort()

  return {
    filesToDownload,
    filesToUpload
  }
}

module.exports = diff