<commit_before>/*
Copyright (C) 2012 - 2016 <NAME> <<EMAIL>>
 */

"use strict";

import async  from 'async';
import fs     from 'fs';
import path   from 'path';
import uuid   from 'node-uuid';
import mkdirp from 'mkdirp';
import clone  from 'clone';

const isJSONFile = f => f.substr(-5) === ".json";

const removeFileExtension = f => f.split(".json")[0];

const getIDs = a => a.filter(isJSONFile).map(removeFileExtension);

const readIDsSync = d => getIDs(fs.readdirSync(d));

const readIDs = (d, cb) => fs.readdir(d, (err, ids) => {
  cb(err, getIDs(ids));
});

const getObjectFromFileSync = function(id) {
  try {
    return JSON.parse(fs.readFileSync(this._getFileName(id), "utf8"));
  } catch (error) {
    return error;
  }
};

const getObjectFromFile = function(id, cb) {
  fs.readFile(this._getFileName(id), "utf8", (err, o) => {
    if (err) {
      return cb(err);
    }
    try {
      cb(null, JSON.parse(o));
    } catch (error) {
      cb(error);
    }
  });
};

const saveObjectToFile = function(o, file, cb) {
  var json;
  const indent = this._pretty ? 2 : void 0;
  try {
    json = JSON.stringify(o, null, indent);
  } catch (error) {
    if (cb != null) {
      return cb(error);
    } else {
      return error;
    }
  }

  if (cb != null) {
    fs.writeFile(file, json, 'utf8', cb);
  } else {
    try {
      return fs.writeFileSync(file, json, 'utf8');
    } catch (error) {
      return error;
    }
  }
};

const id2fileName = (id, dir) => path.join(dir, id + ".json");<commit_msg>Revert logic so that saves first write to a temporary file and then atomically replaces the old file.<commit_after>/*
Copyright (C) 2012 - 2016 <NAME> <<EMAIL>>
 */

"use strict";

import async  from 'async';
import fs     from 'fs';
import path   from 'path';
import uuid   from 'node-uuid';
import mkdirp from 'mkdirp';
import clone  from 'clone';

const isJSONFile = f => f.substr(-5) === ".json";

const removeFileExtension = f => f.split(".json")[0];

const getIDs = a => a.filter(isJSONFile).map(removeFileExtension);

const readIDsSync = d => getIDs(fs.readdirSync(d));

const readIDs = (d, cb) => fs.readdir(d, (err, ids) => {
  cb(err, getIDs(ids));
});

const getObjectFromFileSync = function(id) {
  try {
    return JSON.parse(fs.readFileSync(this._getFileName(id), "utf8"));
  } catch (error) {
    return error;
  }
};

const getObjectFromFile = function(id, cb) {
  fs.readFile(this._getFileName(id), "utf8", (err, o) => {
    if (err) {
      return cb(err);
    }
    try {
      cb(null, JSON.parse(o));
    } catch (error) {
      cb(error);
    }
  });
};

const canWriteToFile = (file, cb) => {
  fs.access(file, fs.constants.F_OK, (err) => {
    if (err) {
      return cb(null);
    }

    fs.access(file, fs.constants.W_OK, cb);
  });
};

const canWriteToFileSync = (file) => {
  try {
    fs.accessSync(file, fs.constants.F_OK);
  } catch (err) {
    return;
  }

  fs.accessSync(file, fs.constants.W_OK);
};

const saveObjectToFile = function(o, file, cb) {
  var json;
  const indent = this._pretty ? 2 : void 0;
  try {
    json = JSON.stringify(o, null, indent);
  } catch (error) {
    if (cb != null) {
      return cb(error);
    } else {
      return error;
    }
  }

  const tmpFileName = file + uuid.v4() + ".tmp";
  if (cb != null) {
    canWriteToFile(file, (err) => {
      if (err) {
        return cb(err);
      }

      fs.writeFile(tmpFileName, json, 'utf8', (err) => {
        if (err) {
          return cb(err);
        }

        fs.rename(tmpFileName, file, cb);
      });
    });
  } else {
    try {
      canWriteToFileSync(file);
      fs.writeFileSync(tmpFileName, json, 'utf8');
      fs.renameSync(tmpFileName, file);
    } catch (error) {
      return error;
    }
  }
};

const id2fileName = (id, dir) => path.join(dir, id + ".json");
{'fraction_non_alphanumeric': 0.1726315789473684, 'fraction_numerical': 0.009210526315789473, 'mean_word_length': 2.808617234468938, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1588690', 'n_tokens_mistral': 1405, 'n_tokens_neox': 1384, 'n_words': 341}