<commit_before>// TODO use Gpml2pvjson to convert GPML/XML to pvjson
// when the user requests it.
//var gpml2pvjson = require('gpml2pvjson');
//var Gpml2pvjson = require('../../gpml2pvjson-js/index.js');
var Rx = require('rx');
var RxNode = require('rx-node');
var JSONStream = require('JSONStream');
var hyperquest = require('hyperquest');
var URI = require('URIjs');
var utils = require('./utils.js');

function WikipathwaysApiClient(args) {

  args = args || {};

  var baseIri;
  var isBrowserVisitingWikipathwaysTestServer;

  // TODO should we use the code immediately below or
  // the code further below for setting the baseIRI?
  /*
  if (!document.baseURI.match(/wikipathways\.org/)) {
    throw new Error('Cannot save on a non-WikiPathways server.');
  }

  var baseIri = 'http://webservice.wikipathways.org/';
  if (!document.baseURI.match(/http:\/\/(www\.)?wikipathways\.org\//)) {
    // if at a test server like pvjs.wikipathways.org
    baseIri = window.location.origin + '/webservice/';
  }
  //*/

  var isBrowser = (typeof window !== 'undefined' && typeof document !== 'undefined');
  if (isBrowser) {
    var hostnameSplit = window.location.hostname.split('wikipathways.org');
    if (hostnameSplit[0] !== '' &&
        hostnameSplit[0] !== 'www.' &&
        hostnameSplit[hostnameSplit.length - 1] === '') {
      isBrowserVisitingWikipathwaysTestServer = true;
    }
  }

  if (!!args.baseIri) {
    baseIri = args.baseIri;
  } else if (isBrowserVisitingWikipathwaysTestServer) {
    // TODO what should the permanent IRI be for the test servers?
    // E.g., should it be this: http://pvjs.wikipathways.org/wpi/webservice/
    baseIri = window.location.origin + '/wpi/webservicetest/';
  } else {
    baseIri = 'http://webservice.wikipathways.org/';
  }

  // convert potential file format request value to standardized media type
  var genericRequestedFileFormatToMediaTypeMappings = {
    'xml':'application/xml',
    'application/ld+json':'application/ld+json',
    'application/json':'application/ld+json',
    'json':'application/ld+json',
    'jsonld':'application/ld+json'
  };

  // convert potential file format request value to standardized media type for pathway data
  var pathwayRequestedFileFormatToMediaTypeMappings = {
    'application/vnd.biopax.rdf+xml':'application/vnd.biopax.rdf+xml',
    'application/biopax.rdf+xml':'application/vnd.biopax.rdf+xml',
    'application/biopax+xml':'application/vnd.biopax.rdf+xml',
    'application/rdf+xml':'application/vnd.biopax.rdf+xml',
    'biopax':'application/vnd.biopax.rdf+xml',
    'application/owl+xml':'application/vnd.biopax.rdf+xml',
    'owl':'application/vnd.biopax.rdf+xml',
    'application/vnd.gpml+xml':'application/vnd.gpml+xml',
    'application/gpml+xml':'application/vnd.gpml+xml',
    'gpml':'application/vnd.gpml+xml',
    'xml':'application/vnd.gpml+xml',
    'application/xml':'application/vnd.gpml+xml',
    'application/ld+json':'application/ld+json',
    'application/json':'application/ld+json',
    'json':'application/ld+json',
    'jsonld':'application/ld+json',
    'pvjson':'application/ld+json',
    'application/pdf':'application/pdf',
    'pdf':'application/pdf',
    'image/png':'image/png',
    'png':'image/png',
    'image/svg+xml':'image/svg+xml',
    'application/svg+xml':'image/svg+xml',
    'svg':'image/svg+xml',
    'text/genelist':'text/genelist',
    'text/plain':'text/genelist',
    'genelist':'text/genelist',
    'text/pwf':'text/pwf',
    'text/eugene':'text/pwf',
    'eugene':'text/pwf',
    'pwf':'text/pwf'
  };

  // convert from standardized format (as specified above) to
  // the format used by the current (2014-06-09) WikiPathways REST API
  // for the pathway
  var mediaTypeToWikipathwaysApiPathwayFileFormatMappings = {
    'application/vnd.biopax.rdf+xml':'owl',
    'application/vnd.gpml+xml':'gpml',
    // TODO the WikiPathways API cannot currently return the pathway as JSON,
    // only the pathway metadata.
    //'application/ld+json':'json',
    'application/ld+json':'gpml',
    'application/pdf':'pdf',
    'image/png':'png',
    'image/svg+xml':'svg',
    'text/genelist':'txt',
    'text/pwf':'pwf'
  };

  // convert from standardized format (as specified above) to
  // the format used by the current (2015-04-29) WikiPathways REST API
  // for the response envelope
  var mediaTypeToWikipathwaysApiEnvelopeFileFormatMappings = {
    'application/vnd.biopax.rdf+xml':'xml',
    'application/xml':'xml',
    'application/vnd.gpml+xml':'xml',
    'application/ld+json':'json',
    'text/genelist':'text',
    'text/pwf':'text'
  };

  function getPathway(args, responseType, stream) {
    args = args || {};

    var requestedFileFormat = args.fileFormat || 'application/ld+json';
    var mediaType = pathwayRequestedFileFormatToMediaTypeMappings[
      requestedFileFormat.toLowerCase()];

    var iri = URI(baseIri)
      .filename('getPathwayAs')
      .query({
        pwId: args.identifier,
        fileType: mediaTypeToWikipathwaysApiPathwayFileFormatMappings[mediaType],
        revision: args.version || 0,
        format: 'json'
      });

    var pathwayMetadata = {};
    pathwayMetadata['@id'] = 'http://identifiers.org/wikipathways/' + args.identifier;
    pathwayMetadata.version = args.version;

    var pathway = RxNode.fromReadableStream(
        hyperquest(iri.toString()).pipe(JSONStream.parse('data')))
    .flatMap(function(data) {
      return Rx.Observable.return(data);
      // TODO when we switch to use the streaming Gpml2pvjson converter,
      // we can get back JSON-LD, but it doesn't work right now with
      // the current Gpml2pvjson converter.
      /*
      if (requestedFileFormat === 'application/ld+json') {
        var gpml2pvjsonInstance = new Gpml2pvjson();
        return Rx.Observable.fromNodeCallback(gpml2pvjsonInstance.toPvjson)(
            data, pathwayMetadata)
          .map(function(pvjson) {
            return JSON.stringify(pvjson, null, '  ');
          });
      } else {
        return Rx.Observable.return(data);
      }
      //*/
    });

    return utils.respondUniversal(pathway, responseType, stream);
  }

  function PathwayStream(inputStream) {
    var outputStream = inputStream || process.stdout;
    inputStream = inputStream || process.stdin;

    RxNode.fromReadableStream(inputStream)
      .subscribe(function(args) {
        var parsedArgs = !Buffer.isBuffer(args) ? args :
            JSON.parse(args.toString());
        //getPathway(args, 'stream', newStream);
        getPathway(parsedArgs, 'stream', outputStream);
      });

    return outputStream;
  }

  function listPathways(args, responseType, stream) {
    args = args || {};

    var requestedFileFormat = args.fileFormat || 'application/ld+json';

    var mediaType = genericRequestedFileFormatToMediaTypeMappings[
        requestedFileFormat.toLowerCase()];

    if (mediaType !== 'application/ld+json' &&
          mediaType !== 'application/json') {
      throw new Error('Requested file format not recognized or not available.');
    }

    var iri = URI(baseIri)
      .filename('listPathways')
      .query({
        format: mediaTypeToWikipathwaysApiEnvelopeFileFormatMappings[mediaType]
      });

    var pathwayList = RxNode.fromReadableStream(
        hyperquest(iri.toString()).pipe(JSONStream.parse('pathways.*')))
      .map(function(data) {
        var pathway = {
          '@context': [
            'https://wikipathwayscontexts.firebaseio.com/biopax.json',
            'https://wikipathwayscontexts.firebaseio.com/organism.json',
            {
              '@vocab': 'http://www.biopax.org/release/biopax-level3.owl#'
            }
          ],
          '@id': 'http://identifiers.org/wikipathways/' + data.id,
          db: 'wikipathways',
          identifier: data.id,
          name: data.name,
          webPage: data.url,
          version: data.revision,
          organism: data.species
        };

        return pathway;
      });

    return utils.respondUniversal(pathwayList, responseType, stream);
  }

  function PathwayListStream(inputStream) {
    var outputStream = inputStream || process.stdout;
    inputStream = inputStream || process.stdin;

    RxNode.fromReadableStream(inputStream)
      .subscribe(function(args) {
        var parsedArgs = !Buffer.isBuffer(args) ? args :
            JSON.parse(args.toString());
        listPathways(parsedArgs, 'stream', outputStream);
      });

    return outputStream;
  }

  function updatePathway(args) {
    args = args || {};

    console.log('Updating ' + args.identifier + '...');

  //Alternative AJAX approach
  var prefixedGpml = '<?xml version="1.0" encoding="UTF-8"?>'.concat(e.gpml);

  var pathData = {
    pwId: args.identifier,
    description:"Quick edit by pvjs",
    revision:args.version,
    gpml:prefixedGpml,
    method:"updatePathway"
  };

  $.ajax({
    url: URI(baseIri).filename("index.php"),
    type:"post",
    data:pathData,
    success: function(response){
      console.log("Success");
      return true;
    },
    error: function(xhr,stat,err){
      console.log("Fail: "+ stat + "ERROR" + err);
      return false;
    }
  });

  /* Iri approach

    var iri = URI(baseIri)
      .filename('index.php');

    iri.setQuery({method: "updatePathway"});

    if (!!args.identifier) {
      iri.setQuery({pwId: args.identifier});
    }
    if (!!args.version) {
      iri.setQuery({revision: args.version});
    }
    if (!!args.username) {
      iri.setQuery({username: args.username});
      if (!!args.password) {
        iri.setQuery({auth: args.username + '-' + args.password});
      }
    }
    if (!!args.description) {
      iri.setQuery({description: args.description});
    }

    var iriString = iri.toString();

    console.log('IRI (URI) string');
    console.log(iriString);

    var body;
    if (!!args.gpml) {
      body = args.gpml;
    }

    // for an example of making a post request with hyperquest, see
    // https://github.com/substack/hyperquest/blob/master/test/post_immediate.js
    var req = hyperquest.post(iriString);
    req.setHeader('Content-Type', 'application/xml');
    req.end(body);

    var data = '';
    req.on('data', function(buf) {data += buf;});
    req.on('end', function() {
      console.log('Did the update work?');
      console.log(data === JSON.stringify(body));
      console.log('data');
      console.log(data);
    });

    return Rx.Observable.fromEvent(req, 'end').toPromise();
    //*/

  }

  return {
    getPathway: getPathway,
    PathwayStream: PathwayStream,
    listPathways: listPathways,
    PathwayListStream: PathwayListStream,
    updatePathway: updatePathway
  };

}

(function() {
  if (typeof window !== 'undefined' && typeof document !== 'undefined') {
    //in browser environment
    window.WikipathwaysApiClient = WikipathwaysApiClient;
  }

  if (!!module && !!module.exports) {
    //in node and/or CommonJS environment
    module.exports = WikipathwaysApiClient;
  }
})();
<commit_msg>implementing promise for ajax post<commit_after>// TODO use Gpml2pvjson to convert GPML/XML to pvjson
// when the user requests it.
//var gpml2pvjson = require('gpml2pvjson');
//var Gpml2pvjson = require('../../gpml2pvjson-js/index.js');
var Rx = require('rx');
var RxNode = require('rx-node');
var JSONStream = require('JSONStream');
var hyperquest = require('hyperquest');
var URI = require('URIjs');
var utils = require('./utils.js');

function WikipathwaysApiClient(args) {

  args = args || {};

  var baseIri;
  var isBrowserVisitingWikipathwaysTestServer;

  // TODO should we use the code immediately below or
  // the code further below for setting the baseIRI?
  /*
  if (!document.baseURI.match(/wikipathways\.org/)) {
    throw new Error('Cannot save on a non-WikiPathways server.');
  }

  var baseIri = 'http://webservice.wikipathways.org/';
  if (!document.baseURI.match(/http:\/\/(www\.)?wikipathways\.org\//)) {
    // if at a test server like pvjs.wikipathways.org
    baseIri = window.location.origin + '/webservice/';
  }
  //*/

  var isBrowser = (typeof window !== 'undefined' && typeof document !== 'undefined');
  if (isBrowser) {
    var hostnameSplit = window.location.hostname.split('wikipathways.org');
    if (hostnameSplit[0] !== '' &&
        hostnameSplit[0] !== 'www.' &&
        hostnameSplit[hostnameSplit.length - 1] === '') {
      isBrowserVisitingWikipathwaysTestServer = true;
    }
  }

  if (!!args.baseIri) {
    baseIri = args.baseIri;
  } else if (isBrowserVisitingWikipathwaysTestServer) {
    // TODO what should the permanent IRI be for the test servers?
    // E.g., should it be this: http://pvjs.wikipathways.org/wpi/webservice/
    baseIri = window.location.origin + '/wpi/webservicetest/';
  } else {
    baseIri = 'http://webservice.wikipathways.org/';
  }

  // convert potential file format request value to standardized media type
  var genericRequestedFileFormatToMediaTypeMappings = {
    'xml':'application/xml',
    'application/ld+json':'application/ld+json',
    'application/json':'application/ld+json',
    'json':'application/ld+json',
    'jsonld':'application/ld+json'
  };

  // convert potential file format request value to standardized media type for pathway data
  var pathwayRequestedFileFormatToMediaTypeMappings = {
    'application/vnd.biopax.rdf+xml':'application/vnd.biopax.rdf+xml',
    'application/biopax.rdf+xml':'application/vnd.biopax.rdf+xml',
    'application/biopax+xml':'application/vnd.biopax.rdf+xml',
    'application/rdf+xml':'application/vnd.biopax.rdf+xml',
    'biopax':'application/vnd.biopax.rdf+xml',
    'application/owl+xml':'application/vnd.biopax.rdf+xml',
    'owl':'application/vnd.biopax.rdf+xml',
    'application/vnd.gpml+xml':'application/vnd.gpml+xml',
    'application/gpml+xml':'application/vnd.gpml+xml',
    'gpml':'application/vnd.gpml+xml',
    'xml':'application/vnd.gpml+xml',
    'application/xml':'application/vnd.gpml+xml',
    'application/ld+json':'application/ld+json',
    'application/json':'application/ld+json',
    'json':'application/ld+json',
    'jsonld':'application/ld+json',
    'pvjson':'application/ld+json',
    'application/pdf':'application/pdf',
    'pdf':'application/pdf',
    'image/png':'image/png',
    'png':'image/png',
    'image/svg+xml':'image/svg+xml',
    'application/svg+xml':'image/svg+xml',
    'svg':'image/svg+xml',
    'text/genelist':'text/genelist',
    'text/plain':'text/genelist',
    'genelist':'text/genelist',
    'text/pwf':'text/pwf',
    'text/eugene':'text/pwf',
    'eugene':'text/pwf',
    'pwf':'text/pwf'
  };

  // convert from standardized format (as specified above) to
  // the format used by the current (2014-06-09) WikiPathways REST API
  // for the pathway
  var mediaTypeToWikipathwaysApiPathwayFileFormatMappings = {
    'application/vnd.biopax.rdf+xml':'owl',
    'application/vnd.gpml+xml':'gpml',
    // TODO the WikiPathways API cannot currently return the pathway as JSON,
    // only the pathway metadata.
    //'application/ld+json':'json',
    'application/ld+json':'gpml',
    'application/pdf':'pdf',
    'image/png':'png',
    'image/svg+xml':'svg',
    'text/genelist':'txt',
    'text/pwf':'pwf'
  };

  // convert from standardized format (as specified above) to
  // the format used by the current (2015-04-29) WikiPathways REST API
  // for the response envelope
  var mediaTypeToWikipathwaysApiEnvelopeFileFormatMappings = {
    'application/vnd.biopax.rdf+xml':'xml',
    'application/xml':'xml',
    'application/vnd.gpml+xml':'xml',
    'application/ld+json':'json',
    'text/genelist':'text',
    'text/pwf':'text'
  };

  function getPathway(args, responseType, stream) {
    args = args || {};

    var requestedFileFormat = args.fileFormat || 'application/ld+json';
    var mediaType = pathwayRequestedFileFormatToMediaTypeMappings[
      requestedFileFormat.toLowerCase()];

    var iri = URI(baseIri)
      .filename('getPathwayAs')
      .query({
        pwId: args.identifier,
        fileType: mediaTypeToWikipathwaysApiPathwayFileFormatMappings[mediaType],
        revision: args.version || 0,
        format: 'json'
      });

    var pathwayMetadata = {};
    pathwayMetadata['@id'] = 'http://identifiers.org/wikipathways/' + args.identifier;
    pathwayMetadata.version = args.version;

    var pathway = RxNode.fromReadableStream(
        hyperquest(iri.toString()).pipe(JSONStream.parse('data')))
    .flatMap(function(data) {
      return Rx.Observable.return(data);
      // TODO when we switch to use the streaming Gpml2pvjson converter,
      // we can get back JSON-LD, but it doesn't work right now with
      // the current Gpml2pvjson converter.
      /*
      if (requestedFileFormat === 'application/ld+json') {
        var gpml2pvjsonInstance = new Gpml2pvjson();
        return Rx.Observable.fromNodeCallback(gpml2pvjsonInstance.toPvjson)(
            data, pathwayMetadata)
          .map(function(pvjson) {
            return JSON.stringify(pvjson, null, '  ');
          });
      } else {
        return Rx.Observable.return(data);
      }
      //*/
    });

    return utils.respondUniversal(pathway, responseType, stream);
  }

  function PathwayStream(inputStream) {
    var outputStream = inputStream || process.stdout;
    inputStream = inputStream || process.stdin;

    RxNode.fromReadableStream(inputStream)
      .subscribe(function(args) {
        var parsedArgs = !Buffer.isBuffer(args) ? args :
            JSON.parse(args.toString());
        //getPathway(args, 'stream', newStream);
        getPathway(parsedArgs, 'stream', outputStream);
      });

    return outputStream;
  }

  function listPathways(args, responseType, stream) {
    args = args || {};

    var requestedFileFormat = args.fileFormat || 'application/ld+json';

    var mediaType = genericRequestedFileFormatToMediaTypeMappings[
        requestedFileFormat.toLowerCase()];

    if (mediaType !== 'application/ld+json' &&
          mediaType !== 'application/json') {
      throw new Error('Requested file format not recognized or not available.');
    }

    var iri = URI(baseIri)
      .filename('listPathways')
      .query({
        format: mediaTypeToWikipathwaysApiEnvelopeFileFormatMappings[mediaType]
      });

    var pathwayList = RxNode.fromReadableStream(
        hyperquest(iri.toString()).pipe(JSONStream.parse('pathways.*')))
      .map(function(data) {
        var pathway = {
          '@context': [
            'https://wikipathwayscontexts.firebaseio.com/biopax.json',
            'https://wikipathwayscontexts.firebaseio.com/organism.json',
            {
              '@vocab': 'http://www.biopax.org/release/biopax-level3.owl#'
            }
          ],
          '@id': 'http://identifiers.org/wikipathways/' + data.id,
          db: 'wikipathways',
          identifier: data.id,
          name: data.name,
          webPage: data.url,
          version: data.revision,
          organism: data.species
        };

        return pathway;
      });

    return utils.respondUniversal(pathwayList, responseType, stream);
  }

  function PathwayListStream(inputStream) {
    var outputStream = inputStream || process.stdout;
    inputStream = inputStream || process.stdin;

    RxNode.fromReadableStream(inputStream)
      .subscribe(function(args) {
        var parsedArgs = !Buffer.isBuffer(args) ? args :
            JSON.parse(args.toString());
        listPathways(parsedArgs, 'stream', outputStream);
      });

    return outputStream;
  }

  function updatePathway(args) {
    args = args || {};

    console.log('Updating ' + args.identifier + '...');

  //Alternative AJAX approach
  var prefixedGpml = '<?xml version="1.0" encoding="UTF-8"?>'.concat(e.gpml);

  var pathData = {
    pwId: args.identifier,
    description:"Quick edit by pvjs",
    revision:args.version,
    gpml:prefixedGpml,
    method:"updatePathway"
  };

  //return promise to editor.js
  return Promise.resolve($.ajax({
    url: URI(baseIri).filename("index.php"),
    type:"post",
    data:pathData
  }));

  /* Iri approach

    var iri = URI(baseIri)
      .filename('index.php');

    iri.setQuery({method: "updatePathway"});

    if (!!args.identifier) {
      iri.setQuery({pwId: args.identifier});
    }
    if (!!args.version) {
      iri.setQuery({revision: args.version});
    }
    if (!!args.username) {
      iri.setQuery({username: args.username});
      if (!!args.password) {
        iri.setQuery({auth: args.username + '-' + args.password});
      }
    }
    if (!!args.description) {
      iri.setQuery({description: args.description});
    }

    var iriString = iri.toString();

    console.log('IRI (URI) string');
    console.log(iriString);

    var body;
    if (!!args.gpml) {
      body = args.gpml;
    }

    // for an example of making a post request with hyperquest, see
    // https://github.com/substack/hyperquest/blob/master/test/post_immediate.js
    var req = hyperquest.post(iriString);
    req.setHeader('Content-Type', 'application/xml');
    req.end(body);

    var data = '';
    req.on('data', function(buf) {data += buf;});
    req.on('end', function() {
      console.log('Did the update work?');
      console.log(data === JSON.stringify(body));
      console.log('data');
      console.log(data);
    });

    return Rx.Observable.fromEvent(req, 'end').toPromise();
    //*/

  }

  return {
    getPathway: getPathway,
    PathwayStream: PathwayStream,
    listPathways: listPathways,
    PathwayListStream: PathwayListStream,
    updatePathway: updatePathway
  };

}

(function() {
  if (typeof window !== 'undefined' && typeof document !== 'undefined') {
    //in browser environment
    window.WikipathwaysApiClient = WikipathwaysApiClient;
  }

  if (!!module && !!module.exports) {
    //in node and/or CommonJS environment
    module.exports = WikipathwaysApiClient;
  }
})();
<|endoftext|>


<commit_before>"use strict";

const pathUtil = require("path");
const treeWalker = require("./utils/tree_walker");
const inspect = require("./inspect");
const matcher = require("./utils/matcher");
const validate = require("./utils/validate");

const validateInput = (methodName, path, options) => {
  const methodSignature = `${methodName}([path], options)`;
  validate.argument(methodSignature, "path", path, ["string"]);
  validate.options(methodSignature, "options", options, {
    matching: ["string", "array of string"],
    files: ["boolean"],
    directories: ["boolean"],
    recursive: ["boolean"],
    ignoreCase: ["boolean"]
  });
};

const normalizeOptions = options => {
  const opts = options || {};
  // defaults:
  if (opts.files === undefined) {
    opts.files = true;
  }
  if (opts.ignoreCase === undefined) {
    opts.ignoreCase = false;
  }
  if (opts.directories === undefined) {
    opts.directories = false;
  }
  if (opts.recursive === undefined) {
    opts.recursive = true;
  }
  return opts;
};

const processFoundObjects = (foundObjects, cwd) => {
  return foundObjects.map(inspectObj => {
    return pathUtil.relative(cwd, inspectObj.absolutePath);
  });
};

const generatePathDoesntExistError = path => {
  const err = new Error(`Path you want to find stuff in doesn't exist ${path}`);
  err.code = "ENOENT";
  return err;
};

const generatePathNotDirectoryError = path => {
  const err = new Error(
    `Path you want to find stuff in must be a directory ${path}`
  );
  err.code = "ENOTDIR";
  return err;
};

// ---------------------------------------------------------
// Sync
// ---------------------------------------------------------

const findSync = (path, options) => {
  const foundInspectObjects = [];
  const matchesAnyOfGlobs = matcher.create(
    path,
    options.matching,
    options.ignoreCase
  );

  let maxLevelsDeep = Infinity;
  if (options.recursive === false) {
    maxLevelsDeep = 1;
  }

  treeWalker.sync(
    path,
    {
      maxLevelsDeep,
      inspectOptions: {
        absolutePath: true,
        symlinks: "follow"
      }
    },
    (itemPath, item) => {
      if (itemPath !== path && matchesAnyOfGlobs(itemPath)) {
        if (
          (item.type === "file" && options.files === true) ||
          (item.type === "dir" && options.directories === true)
        ) {
          foundInspectObjects.push(item);
        }
      }
    }
  );

  return processFoundObjects(foundInspectObjects, options.cwd);
};

const findSyncInit = (path, options) => {
  const entryPointInspect = inspect.sync(path, { symlinks: "follow" });
  if (entryPointInspect === undefined) {
    throw generatePathDoesntExistError(path);
  } else if (entryPointInspect.type !== "dir") {
    throw generatePathNotDirectoryError(path);
  }

  return findSync(path, normalizeOptions(options));
};

// ---------------------------------------------------------
// Async
// ---------------------------------------------------------

const findAsync = (path, options) => {
  return new Promise((resolve, reject) => {
    const foundInspectObjects = [];
    const matchesAnyOfGlobs = matcher.create(
      path,
      options.matching,
      options.ignoreCase
    );

    let maxLevelsDeep = Infinity;
    if (options.recursive === false) {
      maxLevelsDeep = 1;
    }

    const walker = treeWalker
      .stream(path, {
        maxLevelsDeep,
        inspectOptions: {
          absolutePath: true,
          symlinks: "follow"
        }
      })
      .on("readable", () => {
        const data = walker.read();
        if (data && data.path !== path && matchesAnyOfGlobs(data.path)) {
          const item = data.item;
          if (
            (item.type === "file" && options.files === true) ||
            (item.type === "dir" && options.directories === true)
          ) {
            foundInspectObjects.push(item);
          }
        }
      })
      .on("error", reject)
      .on("end", () => {
        resolve(processFoundObjects(foundInspectObjects, options.cwd));
      });
  });
};

const findAsyncInit = (path, options) => {
  return inspect.async(path, { symlinks: "follow" }).then(entryPointInspect => {
    if (entryPointInspect === undefined) {
      throw generatePathDoesntExistError(path);
    } else if (entryPointInspect.type !== "dir") {
      throw generatePathNotDirectoryError(path);
    }
    return findAsync(path, normalizeOptions(options));
  });
};

// ---------------------------------------------------------
// API
// ---------------------------------------------------------

exports.validateInput = validateInput;
exports.sync = findSyncInit;
exports.async = findAsyncInit;
<commit_msg>find no longer crashes on ENOENT<commit_after>"use strict";

const pathUtil = require("path");
const treeWalker = require("./utils/tree_walker");
const inspect = require("./inspect");
const matcher = require("./utils/matcher");
const validate = require("./utils/validate");

const validateInput = (methodName, path, options) => {
  const methodSignature = `${methodName}([path], options)`;
  validate.argument(methodSignature, "path", path, ["string"]);
  validate.options(methodSignature, "options", options, {
    matching: ["string", "array of string"],
    files: ["boolean"],
    directories: ["boolean"],
    recursive: ["boolean"],
    ignoreCase: ["boolean"]
  });
};

const normalizeOptions = options => {
  const opts = options || {};
  // defaults:
  if (opts.files === undefined) {
    opts.files = true;
  }
  if (opts.ignoreCase === undefined) {
    opts.ignoreCase = false;
  }
  if (opts.directories === undefined) {
    opts.directories = false;
  }
  if (opts.recursive === undefined) {
    opts.recursive = true;
  }
  return opts;
};

const processFoundObjects = (foundObjects, cwd) => {
  return foundObjects.map(inspectObj => {
    return pathUtil.relative(cwd, inspectObj.absolutePath);
  });
};

const generatePathDoesntExistError = path => {
  const err = new Error(`Path you want to find stuff in doesn't exist ${path}`);
  err.code = "ENOENT";
  return err;
};

const generatePathNotDirectoryError = path => {
  const err = new Error(
    `Path you want to find stuff in must be a directory ${path}`
  );
  err.code = "ENOTDIR";
  return err;
};

// ---------------------------------------------------------
// Sync
// ---------------------------------------------------------

const findSync = (path, options) => {
  const foundInspectObjects = [];
  const matchesAnyOfGlobs = matcher.create(
    path,
    options.matching,
    options.ignoreCase
  );

  let maxLevelsDeep = Infinity;
  if (options.recursive === false) {
    maxLevelsDeep = 1;
  }

  treeWalker.sync(
    path,
    {
      maxLevelsDeep,
      inspectOptions: {
        absolutePath: true,
        symlinks: "follow"
      }
    },
    (itemPath, item) => {
      if (item && itemPath !== path && matchesAnyOfGlobs(itemPath)) {
        if (
          (item.type === "file" && options.files === true) ||
          (item.type === "dir" && options.directories === true)
        ) {
          foundInspectObjects.push(item);
        }
      }
    }
  );

  return processFoundObjects(foundInspectObjects, options.cwd);
};

const findSyncInit = (path, options) => {
  const entryPointInspect = inspect.sync(path, { symlinks: "follow" });
  if (entryPointInspect === undefined) {
    throw generatePathDoesntExistError(path);
  } else if (entryPointInspect.type !== "dir") {
    throw generatePathNotDirectoryError(path);
  }

  return findSync(path, normalizeOptions(options));
};

// ---------------------------------------------------------
// Async
// ---------------------------------------------------------

const findAsync = (path, options) => {
  return new Promise((resolve, reject) => {
    const foundInspectObjects = [];
    const matchesAnyOfGlobs = matcher.create(
      path,
      options.matching,
      options.ignoreCase
    );

    let maxLevelsDeep = Infinity;
    if (options.recursive === false) {
      maxLevelsDeep = 1;
    }

    const walker = treeWalker
      .stream(path, {
        maxLevelsDeep,
        inspectOptions: {
          absolutePath: true,
          symlinks: "follow"
        }
      })
      .on("readable", () => {
        const data = walker.read();
        if (data && data.path !== path && matchesAnyOfGlobs(data.path)) {
          const item = data.item;
          if (
            (item.type === "file" && options.files === true) ||
            (item.type === "dir" && options.directories === true)
          ) {
            foundInspectObjects.push(item);
          }
        }
      })
      .on("error", reject)
      .on("end", () => {
        resolve(processFoundObjects(foundInspectObjects, options.cwd));
      });
  });
};

const findAsyncInit = (path, options) => {
  return inspect.async(path, { symlinks: "follow" }).then(entryPointInspect => {
    if (entryPointInspect === undefined) {
      throw generatePathDoesntExistError(path);
    } else if (entryPointInspect.type !== "dir") {
      throw generatePathNotDirectoryError(path);
    }
    return findAsync(path, normalizeOptions(options));
  });
};

// ---------------------------------------------------------
// API
// ---------------------------------------------------------

exports.validateInput = validateInput;
exports.sync = findSyncInit;
exports.async = findAsyncInit;
<|endoftext|>


<commit_before>"use strict";

// In the code, unless otherwise specified, "hash" means our SHA-256 hash string,
// including the "sha256-" prefix.
// In the code, unless otherwise specified, ID means the Git object's SHA-1 hash string.
// Commit is a concept (or object), not a string. But commit ID is a string.
// In the code, "file" can also mean a directory. File is a concept (or object), not a string.
// File path is a string.
// The first lock for a commit is called the base lock. Subsequent locks for this commit
// are called derived locks.
// Lock name is the string starting with "gitlock-" (tag name). Lock content is
// the tag message. Lock is a concept (or object), not a string.
// Time is an ISO-8601 string, not a `Date` object or a number.

// Since GitHub mixes all tags into "releases" and can only sort them by tagger time, we must
// put locks into an earlier time, so that people can still easily find real releases.
// Luckily, tagger time can be different from the commit time as long as it's annotated.
// The first Git commit happens on 2005-04-07T22:13Z (see https://github.com/git/git).
// We set it to be a little after this time to respect Git.
// The first lock's time will be 2 seconds after this time.
let TAGGER_TIME_ORIGIN = "2005-04-08T00:00:00Z";

let $cp = require("child_process");
let assert = require("assert");
let $crypto = require("crypto");
let $path = require("path").posix;
let $fs = require("fs");
let $http = require("http");
let $url = require("url");
let $util = require("./util");
let $git = require("./git");
let $diff = require("./diff");
let $v = require("./validate");
let $lock = require("./lock");

let args = process.argv.slice();
args.splice(0, 2); // strip "node" and the name of this file

let addLocks = () => {
    let commits = {};
    let fileIdToHash = {}; // cache for performance
    let directoryFiles = {}; // cache for performance
    let finishedCount = 0;
    let progressTime = new Date().toISOString();
    let taggerTime = TAGGER_TIME_ORIGIN;
    $git.lines(["rev-list", "--children", "--reverse", "HEAD"])
    .forEach(m => {
        let parts = m.split(" ");
        let commit = commits[parts[0]] = {};
        commit.lockHashes = [];
        commit.childIDs = parts.slice(1);
        commit.isNew = true;
        commit.traversed = false;
    });
    let commitIDs = Object.keys(commits);
    let firstCommitId = commitIDs[0];
    let lastCommitId = $util.last(commitIDs);
    $git.lines(["rev-list", "--parents", "HEAD"]).forEach(m => {
        let parts = m.split(" ");
        commits[parts[0]].parentIDs = parts.slice(1);
    });

    let loadAllLocks = () => {
        let lines = $git.lines([
            "for-each-ref",
            "--format=%(object) %(refname:short) %(taggerdate:iso-strict)",
            "refs/tags/gitlock-*"
        ]);
        lines.forEach(line => {
            let parts = line.split(" ");
            let commitId = parts[0];
            let lock = parts[1];
            let time = parts[2];
            commits[commitId].lockHashes.push(lock);
            commits[commitId].time = time;
            commits[commitId].isNew = false;
            let timespan = $util.subtractTime(time, taggerTime);
            if (timespan > 0 && timespan % 2 === 0) {
                taggerTime = time;
            }
        });
    };

    let traverse = commitId => {
        let commit = commits[commitId];
        if (commit.isNew) {
            let commitContent = $git.run(["cat-file", "commit", $v.id(commitId)]);
            let lines = $util.parseLines(commitContent);
            let firstLineParts = lines[0].split(" ");
            assert(firstLineParts.length === 2 && firstLineParts[0] === "tree");
            let directoryId = firstLineParts[1];
            let emptyLineIndex = lines.indexOf("");

            // We verbatim restore the commit message. If the raw message ends with newline, it should
            // end with newline. If not, it should not.
            // (Normally all commit messages end with newlines. But if you use stdin to pass the
            // message and use verbatim option, it will not generate a trailing newline.)
            let commitMessage = lines.slice(emptyLineIndex + 1).join("\n"); // if out-of-boundary, it's ""
            if (commitMessage !== "" && commitContent.endsWith("\n")) {
                commitMessage += "\n";
            }

            let files = [];
            let traverseDirectory = (id, pathPrefix) => {
                let parsedTree = directoryFiles[id];
                if (parsedTree === undefined) {
                    parsedTree = $git.parseTree(
                        $git.run(["cat-file", "tree", $v.id(id)], {encoding: "buffer"})
                    );
                    directoryFiles[id] = parsedTree;
                }
                parsedTree.forEach(file => {
                    file.path = pathPrefix + file.name;
                    if (!file.mode.startsWith("160")) { // exclude the submodule mode
                        files.push(file);
                        if (file.mode.startsWith("040")) { // is tree
                            traverseDirectory(file.id, file.path + "/");
                        }
                    }
                });
            };
            traverseDirectory(directoryId, "");

            let lockContentPart1 = "";
            if (commit.parentIDs.length > 0) {
                commit.parentIDs.forEach(id => {
                    lockContentPart1 += "parent " + commits[id].lockHashes[0] + "\n";
                });
                lockContentPart1 += "\n";
            }
            let lockContentPart2 = "";
            files.forEach(file => {
                let hash = fileIdToHash[file.id];
                if (hash === undefined) {
                    if (file.mode.startsWith("040")) {
                        hash = "sha256-0000000000000000000000000000000000000000000000000000000000000000";
                    }
                    else {
                        let bytes = $git.run(["cat-file", "blob", $v.id(file.id)], {encoding: "buffer"});
                        hash = $lock.computeHash(bytes);
                    }
                    fileIdToHash[file.id] = hash;
                }
                lockContentPart2 += file.mode + " " + hash + " " + file.path + "\n";
            });
            let lockContentPart3 =
                "\n" +
                "commit " + commitId + "\n" +
                "\n" +
                $lock.generateBase64(commitMessage) + "\n" +
                "\n" +
                $lock.generateNonce();
            let lockContent = lockContentPart1 + lockContentPart2 + lockContentPart3;
            commit.lockHashes.push($lock.computeHash(lockContent));

            commit.filesString = lockContentPart2;

            let storedLockContent = null;
            let firstParentId = commit.parentIDs[0];
            if (firstParentId === undefined) {
                storedLockContent = lockContent;
            }
            else {
                let baseFilesString = commits[firstParentId].filesString;
                if (baseFilesString === undefined) {
                    storedLockContent = lockContent;
                }
                else {
                    storedLockContent =
                        lockContentPart1 +
                        $diff.computeDiff(baseFilesString, lockContentPart2) +
                        lockContentPart3;
                }
            }
            taggerTime = $util.addTime(taggerTime, 2);
            $lock.add(
                "gitlock-000-" + commit.lockHashes[0],
                storedLockContent,
                commitId,
                taggerTime
            );
        }

        commit.traversed = true;

        finishedCount++;

        let now = new Date().toISOString();
        if ($util.subtractTime(now, progressTime) >= 1) {
            console.log(`${finishedCount} of ${commitIDs.length} commits processed.`);
            progressTime = now;
        }

        commit.childIDs.forEach(child => {
            if (commit.isNew && !commits[child].isNew) {
                throw new Error("Old lock already exists after a new lock.");
            }
            if (commits[child].parentIDs.every(m => commits[m].traversed)) {
                traverse(child);
            }
        });
    };

    console.log("Loading existing locks...");
    loadAllLocks();
    console.log("Adding locks...");
    traverse(firstCommitId);
    console.log(`${finishedCount} of ${commitIDs.length} commits processed successfully.`);
};

let configFilePath = $path.join($util.homeDir, ".gitlock");

// default config
let config = {
    tsa: ["http://timestamp.comodoca.com/rfc3161"],
    openssl: "openssl",
    lockDefault: "lock",
    pushDefault: "lock",
    private: []
};

if ($fs.existsSync(configFilePath)) {
    let savedConfig = JSON.parse($fs.readFileSync(configFilePath, {encoding: "utf8"}));
    Object.assign(config, savedConfig);
    $fs.writeFileSync(configFilePath, JSON.stringify(config));
}
else {
    $fs.writeFileSync(configFilePath, JSON.stringify(config));
}

if (args.length === 0 || args[0] === "-m" || args[0] === "commit") {
    let status = $git.lines(["status", "--porcelain"]);
    if (status.some(m => m[0] !== " " && m[0] !== "?" && m[0] !== "!")) {
        if (args.length === 0) {
            $git.run(["commit", "--allow-empty-message", "-m", ""]);
        }

        // These are the only 2 commands that bypass the argument validation,
        // because it's impossible. But luckily, on one hand, "git commit -m <message>"
        // is obviously safe. On the other hand, when one use "gitlock commit [...]" he must
        // be aware that it has the same grammar as "git commit [...]", so it's also safe.
        else if (args[0] === "-m") {
            assert(args.length === 2);
            $git.run(["commit", "-m", args[1]]);
        }
        else if (args[0] === "commit") {
            $git.run(args);
        }
    }
    addLocks();
}
else if (args[0] === "timestamp") {
    let lastCommitId = $git.getLastCommitId();
    let lockNames = $git.lines([
        "tag", "-l", "--points-at", $v.id(lastCommitId), "--sort=refname", "gitlock-*"
    ]);
    let lockName = $util.last(lockNames);
    let baseTaggerTime = $lock.getTime(lockNames[0]);
    let request = $cp.execFileSync(
        config.openssl,
        ["ts", "-query", "-cert", "-sha256"],
        {input: $lock.getContent(lockName)}
    );
    let url = $url.parse(config.tsa[0]);
    assert(url.protocol === "http:");
    let clientRequest = $http.request({
        method: "POST",
        hostname: url.hostname,
        port: url.port,
        path: url.path,
        headers: {"Content-Type": "application/timestamp-query"}
    }, serverResponse => {
        let data = Buffer.from([]);
        serverResponse.on("data", chunk => {
            data = Buffer.concat([data, chunk]);
        });
        serverResponse.on("end", () => {
            let newLockContent =
                "timestamps\n" +
                "\n" +
                "parent " + $lock.getHash(lockName) + "\n" +
                "\n" +
                $lock.generateBase64(data) + "\n" +
                "\n" +
                $lock.generateNonce();
            let newLockName =
                "gitlock-" + $lock.generateLabel(lockName) + "-" + $lock.computeHash(newLockContent);
            $lock.add(
                newLockName,
                newLockContent,
                lastCommitId,
                $util.addTime(baseTaggerTime, 1)
            );
            console.log(`Timestamp added. Content length: ${data.length}`);
        });
    });
    clientRequest.write(request);
    clientRequest.end();
}
else if (args[0] === "verify") {
}
else if (args[0] === "proof") {
    assert(args.length === 3);
    let commitId = args[1];
    let tags = $git.lines([
        "tag", "-l", "--points-at", $v.id(commitId), "--sort=refname", "gitlock-*"
    ]);
    let dirPath = $util.slashPath(args[2]);
    assert($fs.existsSync(dirPath));
    let list = [];
    tags.forEach((tag, index) => {
        let message = $lock.getContent(tag);
        let hash = $lock.getHash(tag);
        let filePath = $path.join(dirPath, hash + ".txt");
        $fs.writeFileSync(filePath, message);
        list.push(commitId + " " + $util.pad(index, 3) + " " + hash + "\n");
    });
    $fs.writeFileSync($path.join(dirPath, "list.txt"), list.join(""));
    let readmePath = $path.join($path.dirname($util.slashPath(module.filename)), "proof-readme.txt");
    let readmeBytes = $fs.readFileSync(readmePath);
    $fs.writeFileSync($path.join(dirPath, "README.txt"), readmeBytes);
}
else if (args[0] === "show") {
    // "--points-at" also applies to tag names. So it also works if `args[1]` is a lock name.
    // TODO: Currently do not support hash name
    let tags = $git.lines([
        "tag", "-l", "--points-at", $v.idOrHashOrLockName(args[1]), "--sort=refname", "gitlock-*"
    ]);
    tags.forEach(tag => {
        console.log(tag);
        console.log("=".repeat(tag.length));
        console.log("");
        console.log($lock.getContent(tag));
    });
}
else if (args[0] === "list") {
    let tags = $git.lines(["tag", "-l", "--sort=taggerdate", "gitlock-*"]);
    tags.forEach(tag => {
        console.log(tag);
    });
}
else if (args[0] === "log") {
    $git.run(["log", "--all", "--decorate", "--graph"], {
        stdio: ["pipe", process.stdout, process.stderr],
        encoding: "buffer"
    });
}
else if (args[0] === "remove") {
    let type = args[1];
    if (type === undefined) {
        type = "--commit";
    }
    assert(type === "--all");
    if (type === "--all") {
        let tags = $git.lines(["tag", "-l", "gitlock-*"]);
        $git.run(["tag", "-d"].concat(tags.map(m => $v.lockName(m))));
    }
}
else if (args[0] === "config") {
    if (args.length === 1) {
        console.log(config);
    }
    else {
        if (args[1] === "tsa") {
            config.tsa = [args[2]];
        }
        else if (args[1] === "openssl") {
            config.openssl = args[2];
        }
        $fs.writeFileSync(configFilePath, JSON.stringify(config));
    }
}
<commit_msg>rename<commit_after>"use strict";

// In the code, unless otherwise specified, "hash" means our SHA-256 hash string,
// including the "sha256-" prefix.
// In the code, unless otherwise specified, ID means the Git object's SHA-1 hash string.
// Commit is a concept (or object), not a string. But commit ID is a string.
// In the code, "file" can also mean a directory. File is a concept (or object), not a string.
// File path is a string.
// The first lock for a commit is called the base lock. Subsequent locks for this commit
// are called derived locks.
// Lock name is the string starting with "gitlock-" (tag name). Lock content is
// the tag message. Lock is a concept (or object), not a string.
// Time is an ISO-8601 string, not a `Date` object or a number.

// Since GitHub mixes all tags into "releases" and can only sort them by tagger time, we must
// put locks into an earlier time, so that people can still easily find real releases.
// Luckily, tagger time can be different from the commit time as long as it's annotated.
// The first Git commit happens on 2005-04-07T22:13Z (see https://github.com/git/git).
// We set it to be a little after this time to respect Git.
// The first lock's time will be 2 seconds after this time.
let TAGGER_TIME_ORIGIN = "2005-04-08T00:00:00Z";

let $cp = require("child_process");
let assert = require("assert");
let $crypto = require("crypto");
let $path = require("path").posix;
let $fs = require("fs");
let $http = require("http");
let $url = require("url");
let $util = require("./util");
let $git = require("./git");
let $diff = require("./diff");
let $v = require("./validate");
let $lock = require("./lock");

let args = process.argv.slice();
args.splice(0, 2); // strip "node" and the name of this file

let addLocks = () => {
    let commits = {};
    let fileIdToHash = {}; // cache for performance
    let directoryFiles = {}; // cache for performance
    let finishedCount = 0;
    let progressTime = new Date().toISOString();
    let taggerTime = TAGGER_TIME_ORIGIN;
    $git.lines(["rev-list", "--children", "--reverse", "HEAD"])
    .forEach(m => {
        let parts = m.split(" ");
        let commit = commits[parts[0]] = {};
        commit.lockHashes = [];
        commit.childIDs = parts.slice(1);
        commit.isNew = true;
        commit.traversed = false;
    });
    let commitIDs = Object.keys(commits);
    let firstCommitId = commitIDs[0];
    let lastCommitId = $util.last(commitIDs);
    $git.lines(["rev-list", "--parents", "HEAD"]).forEach(m => {
        let parts = m.split(" ");
        commits[parts[0]].parentIDs = parts.slice(1);
    });

    let loadAllLocks = () => {
        let lines = $git.lines([
            "for-each-ref",
            "--format=%(object) %(refname:short) %(taggerdate:iso-strict)",
            "refs/tags/gitlock-*"
        ]);
        lines.forEach(line => {
            let parts = line.split(" ");
            let commitId = parts[0];
            let lock = parts[1];
            let time = parts[2];
            commits[commitId].lockHashes.push(lock);
            commits[commitId].time = time;
            commits[commitId].isNew = false;
            let timespan = $util.subtractTime(time, taggerTime);
            if (timespan > 0 && timespan % 2 === 0) {
                taggerTime = time;
            }
        });
    };

    let traverse = commitId => {
        let commit = commits[commitId];
        if (commit.isNew) {
            let commitContent = $git.run(["cat-file", "commit", $v.id(commitId)]);
            let lines = $util.parseLines(commitContent);
            let firstLineParts = lines[0].split(" ");
            assert(firstLineParts.length === 2 && firstLineParts[0] === "tree");
            let directoryId = firstLineParts[1];
            let emptyLineIndex = lines.indexOf("");

            // We verbatim restore the commit message. If the raw message ends with newline, it should
            // end with newline. If not, it should not.
            // (Normally all commit messages end with newlines. But if you use stdin to pass the
            // message and use verbatim option, it will not generate a trailing newline.)
            let commitMessage = lines.slice(emptyLineIndex + 1).join("\n"); // if out-of-boundary, it's ""
            if (commitMessage !== "" && commitContent.endsWith("\n")) {
                commitMessage += "\n";
            }

            let files = [];
            let traverseDirectory = (id, pathPrefix) => {
                let parsedTree = directoryFiles[id];
                if (parsedTree === undefined) {
                    parsedTree = $git.parseTree(
                        $git.run(["cat-file", "tree", $v.id(id)], {encoding: "buffer"})
                    );
                    directoryFiles[id] = parsedTree;
                }
                parsedTree.forEach(file => {
                    file.path = pathPrefix + file.name;
                    if (!file.mode.startsWith("160")) { // exclude the submodule mode
                        files.push(file);
                        if (file.mode.startsWith("040")) { // is tree
                            traverseDirectory(file.id, file.path + "/");
                        }
                    }
                });
            };
            traverseDirectory(directoryId, "");

            let lockContentPart1 = "";
            if (commit.parentIDs.length > 0) {
                commit.parentIDs.forEach(id => {
                    lockContentPart1 += "parent " + commits[id].lockHashes[0] + "\n";
                });
                lockContentPart1 += "\n";
            }
            let lockContentPart2 = "";
            files.forEach(file => {
                let hash = fileIdToHash[file.id];
                if (hash === undefined) {
                    if (file.mode.startsWith("040")) {
                        hash = "sha256-0000000000000000000000000000000000000000000000000000000000000000";
                    }
                    else {
                        let bytes = $git.run(["cat-file", "blob", $v.id(file.id)], {encoding: "buffer"});
                        hash = $lock.computeHash(bytes);
                    }
                    fileIdToHash[file.id] = hash;
                }
                lockContentPart2 += file.mode + " " + hash + " " + file.path + "\n";
            });
            let lockContentPart3 =
                "\n" +
                "commit " + commitId + "\n" +
                "\n" +
                $lock.generateBase64(commitMessage) + "\n" +
                "\n" +
                $lock.generateNonce();
            let lockContent = lockContentPart1 + lockContentPart2 + lockContentPart3;
            commit.lockHashes.push($lock.computeHash(lockContent));

            commit.filesString = lockContentPart2;

            let storedLockContent = null;
            let firstParentId = commit.parentIDs[0];
            if (firstParentId === undefined) {
                storedLockContent = lockContent;
            }
            else {
                let baseFilesString = commits[firstParentId].filesString;
                if (baseFilesString === undefined) {
                    storedLockContent = lockContent;
                }
                else {
                    storedLockContent =
                        lockContentPart1 +
                        $diff.computeDiff(baseFilesString, lockContentPart2) +
                        lockContentPart3;
                }
            }
            taggerTime = $util.addTime(taggerTime, 2);
            $lock.add(
                "gitlock-000-" + commit.lockHashes[0],
                storedLockContent,
                commitId,
                taggerTime
            );
        }

        commit.traversed = true;

        finishedCount++;

        let now = new Date().toISOString();
        if ($util.subtractTime(now, progressTime) >= 1) {
            console.log(`${finishedCount} of ${commitIDs.length} commits processed.`);
            progressTime = now;
        }

        commit.childIDs.forEach(child => {
            if (commit.isNew && !commits[child].isNew) {
                throw new Error("Old lock already exists after a new lock.");
            }
            if (commits[child].parentIDs.every(m => commits[m].traversed)) {
                traverse(child);
            }
        });
    };

    console.log("Loading existing locks...");
    loadAllLocks();
    console.log("Adding locks...");
    traverse(firstCommitId);
    console.log(`${finishedCount} of ${commitIDs.length} commits processed successfully.`);
};

let configFilePath = $path.join($util.homeDir, ".gitlock");

// default config
let config = {
    tsa: ["http://timestamp.comodoca.com/rfc3161"],
    openssl: "openssl",
    lockDefault: "lock",
    pushDefault: "lock",
    private: []
};

if ($fs.existsSync(configFilePath)) {
    let savedConfig = JSON.parse($fs.readFileSync(configFilePath, {encoding: "utf8"}));
    Object.assign(config, savedConfig);
    $fs.writeFileSync(configFilePath, JSON.stringify(config));
}
else {
    $fs.writeFileSync(configFilePath, JSON.stringify(config));
}

if (args.length === 0 || args[0] === "-m" || args[0] === "commit") {
    let status = $git.lines(["status", "--porcelain"]);
    if (status.some(m => m[0] !== " " && m[0] !== "?" && m[0] !== "!")) {
        if (args.length === 0) {
            $git.run(["commit", "--allow-empty-message", "-m", ""]);
        }

        // These are the only 2 commands that bypass the argument validation,
        // because it's impossible. But luckily, on one hand, "git commit -m <message>"
        // is obviously safe. On the other hand, when one use "gitlock commit [...]" he must
        // be aware that it has the same grammar as "git commit [...]", so it's also safe.
        else if (args[0] === "-m") {
            assert(args.length === 2);
            $git.run(["commit", "-m", args[1]]);
        }
        else if (args[0] === "commit") {
            $git.run(args);
        }
    }
    addLocks();
}
else if (args[0] === "timestamp") {
    let lastCommitId = $git.getLastCommitId();
    let lockNames = $git.lines([
        "tag", "-l", "--points-at", $v.id(lastCommitId), "--sort=refname", "gitlock-*"
    ]);
    let lockName = $util.last(lockNames);
    let baseTaggerTime = $lock.getTime(lockNames[0]);
    let request = $cp.execFileSync(
        config.openssl,
        ["ts", "-query", "-cert", "-sha256"],
        {input: $lock.getContent(lockName)}
    );
    let url = $url.parse(config.tsa[0]);
    assert(url.protocol === "http:");
    let clientRequest = $http.request({
        method: "POST",
        hostname: url.hostname,
        port: url.port,
        path: url.path,
        headers: {"Content-Type": "application/timestamp-query"}
    }, serverResponse => {
        let data = Buffer.from([]);
        serverResponse.on("data", chunk => {
            data = Buffer.concat([data, chunk]);
        });
        serverResponse.on("end", () => {
            let newLockContent =
                "timestamps\n" +
                "\n" +
                "parent " + $lock.getHash(lockName) + "\n" +
                "\n" +
                $lock.generateBase64(data) + "\n" +
                "\n" +
                $lock.generateNonce();
            let newLockName =
                "gitlock-" + $lock.generateLabel(lockName) + "-" + $lock.computeHash(newLockContent);
            $lock.add(
                newLockName,
                newLockContent,
                lastCommitId,
                $util.addTime(baseTaggerTime, 1)
            );
            console.log(`Timestamp added. Content length: ${data.length}`);
        });
    });
    clientRequest.write(request);
    clientRequest.end();
}
else if (args[0] === "verify") {
}
else if (args[0] === "proof") {
    assert(args.length === 3);
    let commitId = args[1];
    let lockNames = $git.lines([
        "tag", "-l", "--points-at", $v.id(commitId), "--sort=refname", "gitlock-*"
    ]);
    let dirPath = $util.slashPath(args[2]);
    assert($fs.existsSync(dirPath));
    let list = [];
    lockNames.forEach((name, index) => {
        let content = $lock.getContent(name);
        let hash = $lock.getHash(name);
        let filePath = $path.join(dirPath, hash + ".txt");
        $fs.writeFileSync(filePath, content);
        list.push(commitId + " " + $util.pad(index, 3) + " " + hash + "\n");
    });
    $fs.writeFileSync($path.join(dirPath, "list.txt"), list.join(""));
    let readmePath = $path.join($path.dirname($util.slashPath(module.filename)), "proof-readme.txt");
    let readmeBytes = $fs.readFileSync(readmePath);
    $fs.writeFileSync($path.join(dirPath, "README.txt"), readmeBytes);
}
else if (args[0] === "show") {
    // "--points-at" also applies to tag names. So it also works if `args[1]` is a lock name.
    // TODO: Currently do not support hash name
    let tags = $git.lines([
        "tag", "-l", "--points-at", $v.idOrHashOrLockName(args[1]), "--sort=refname", "gitlock-*"
    ]);
    tags.forEach(tag => {
        console.log(tag);
        console.log("=".repeat(tag.length));
        console.log("");
        console.log($lock.getContent(tag));
    });
}
else if (args[0] === "list") {
    let tags = $git.lines(["tag", "-l", "--sort=taggerdate", "gitlock-*"]);
    tags.forEach(tag => {
        console.log(tag);
    });
}
else if (args[0] === "log") {
    $git.run(["log", "--all", "--decorate", "--graph"], {
        stdio: ["pipe", process.stdout, process.stderr],
        encoding: "buffer"
    });
}
else if (args[0] === "remove") {
    let type = args[1];
    if (type === undefined) {
        type = "--commit";
    }
    assert(type === "--all");
    if (type === "--all") {
        let tags = $git.lines(["tag", "-l", "gitlock-*"]);
        $git.run(["tag", "-d"].concat(tags.map(m => $v.lockName(m))));
    }
}
else if (args[0] === "config") {
    if (args.length === 1) {
        console.log(config);
    }
    else {
        if (args[1] === "tsa") {
            config.tsa = [args[2]];
        }
        else if (args[1] === "openssl") {
            config.openssl = args[2];
        }
        $fs.writeFileSync(configFilePath, JSON.stringify(config));
    }
}
<|endoftext|>


<commit_before>'use strict';

var restify = require('restify'),
    redis = require('redis'),
    config = require('./configUtil'),
    Router = require('./router'),
    channel = require('./channel'),
    stream = require('./stream');

var main = {};

main.vars = {};

main.run = function(configFile) {
  configFile = configFile || 'config.json';
  config.init(configFile);

  // Configure server.
  var server = main.vars.server = restify.createServer({name: config.get('server:name')});
  server.use(restify.bodyParser({mapParams: true}));

  // Bind subscription to stream.
  stream(server, config.get('server:streamURI'), config.get('redis:channel'), function(next) {
    var subscriber = redis.createClient();
    channel.sub(subscriber, config.get('redis:channel'), false, function(message) {
      next(message);
    });
  });

  // Route API calls.
  var router = main.vars.router = new Router(server, 'controllers');
  server.post('/push', router.dispatch('push'));

  // Listen!
  server.listen(process.env.PORT || config.get('server:port'), function() {
    console.log('%s listening at %s', server.name, server.url);
  });
};

main.stop = function() {
  main.vars.server.close();
  delete main.vars.server;
};
module.exports = main;<commit_msg>Delete router on stop.<commit_after>'use strict';

var restify = require('restify'),
    redis = require('redis'),
    config = require('./configUtil'),
    Router = require('./router'),
    channel = require('./channel'),
    stream = require('./stream');

var main = {};

main.vars = {};

main.run = function(configFile) {
  configFile = configFile || 'config.json';
  config.init(configFile);

  // Configure server.
  var server = main.vars.server = restify.createServer({name: config.get('server:name')});
  server.use(restify.bodyParser({mapParams: true}));

  // Bind subscription to stream.
  stream(server, config.get('server:streamURI'), config.get('redis:channel'), function(next) {
    var subscriber = redis.createClient();
    channel.sub(subscriber, config.get('redis:channel'), false, function(message) {
      next(message);
    });
  });

  // Route API calls.
  var router = main.vars.router = new Router(server, 'controllers');
  server.post('/push', router.dispatch('push'));

  // Listen!
  server.listen(process.env.PORT || config.get('server:port'), function() {
    console.log('%s listening at %s', server.name, server.url);
  });
};

main.stop = function() {
  main.vars.server.close();
  delete main.vars.server;
  delete main.vars.router;
};
module.exports = main;
<|endoftext|>


<commit_before>
function Heap(comp, onMove) {
  this.comp = comp || function (a, b) {
    if (a > b) {
      return 1;
    } else if (a < b) {
      return -1;
    } else {
      return 0;
    }
  };
  this.data = [];
  this.onMove = onMove || function () {};
}

Heap.getParentIndex = function (i) {
  var parent = i % 2 ? (i - 1) / 2 : Math.floor((i - 1) / 2);
  return parent >= 0 ? parent : undefined;
};

Heap.getChild1Index = function (i) {
  return 2 * i + 1;
};

Heap.getChild2Index = function (i) {
  return 2 * i + 2;
};

Heap.prototype._swap = function (x, y) {
  var tmp = this.data[x];
  this.data[x] = this.data[y];
  this.data[y] = tmp;
  this.onMove(this.data[x], x, y);
  this.onMove(this.data[y], y, x);
};

Heap.prototype._bubbleUp = function bubbleUp(i) {
  var parentIndex;
  var data = this.data;
  var comp = this.comp;
  while (i > 0) {
    parentIndex = Heap.getParentIndex(i);
    if (comp(data[i], data[parentIndex]) < 0) {
      this._swap(i, parentIndex);
      i = parentIndex;
    }
    else {
      return i;
    }
  }
};

Heap.prototype._bubbleDown = function bubbleDown(i) {
  var data = this.data;
  var comp = this.comp;
  var child1Index, child2Index,
    child1isSmaller, child2isSmaller;
  while (i < data.length) {
    child1Index = Heap.getChild1Index(i);
    child2Index = Heap.getChild2Index(i);
    child1isSmaller = typeof data[child1Index] !== 'undefined' ? comp(data[child1Index], data[i]) < 0 : false;
    child2isSmaller = typeof data[child2Index] !== 'undefined' ? comp(data[child2Index], data[i]) < 0 : false;
    if (child1isSmaller && child2isSmaller) {
      if (comp(data[child1Index], data[child2Index]) < 0) {
        this._swap(child1Index, i);
        i = child1Index;
      }
      else {
        this._swap(child2Index, i);
        i = child2Index;
      }
    }
    else if (child1isSmaller) {
      this._swap(child1Index, i);
      i = child1Index;
    }
    else if (child2isSmaller) {
      this._swap(child2Index, i);
      i = child2Index;
    }
    else {
      return i;
    }
  }
};

Heap.prototype.pushAll = function (items) {
  for (var i = 0; i < items.length; i++) {
    this.push(items[i]);
  }
};

Heap.prototype.push = function (item) {
  this.data.push(item);
  this.onMove(this.data[this.data.length - 1], this.data.length - 1);
  this._bubbleUp(this.data.length - 1);
};

Heap.prototype.peek = function () {
  return this.data[0];
};

Heap.prototype.pop = function () {
  var root = this.data[0];
  var last = this.data.pop();

  if (this.data.length !== 0) {
    this.data[0] = last;
    this.onMove(this.data[0], 0);
    this._bubbleDown(0);
  }
  return root;
};

Heap.prototype.popAll = function () {
  var out = [];
  while (this.size()) {
    out.push(this.pop());
  }
  return out;
};

Heap.prototype.size = function () {
  return this.data.length;
};

Heap.prototype.indexOf = function (value) {
  var n, i = -1;
  var last;

  if (typeof value === 'function') {
    for (n = 0; n < this.data.length; n++) {
      if (value(this.data[n])) {
        i = n;
        break;
      }
    }
  }
  else {
    i = this.data.indexOf(value);
  }
  return i;
};

Heap.prototype.remove = function (value) {
  var i = this.indexOf(value);
  return this.removeIndex(i);
};

Heap.prototype.get = function (i) {
  return this.data[i];
};

Heap.prototype.removeIndex = function (i) {
  var last;
  if (i === -1) return;

  if (i === this.data.length - 1) {
    last = this.data.pop();
    return last;
  }

  this._swap(i, this.data.length - 1);

  last = this.data.pop();

  if (this.data.length > 1) {
    this._bubbleUp(i);
    this._bubbleDown(i);
  }
  return last;
};

Heap.prototype.replaceIndex = function (i, value) {
  var last;
  if (i === -1) return;
  this.data.push(value);

  this._swap(i, this.data.length - 1);

  last = this.data.pop();

  if (this.data.length > 1) {
    this._bubbleUp(i);
    this._bubbleDown(i);
  }
  return last;
};

Heap.prototype.toArray = function () {
  return this.data.slice(0);
};

module.exports = Heap;
<commit_msg>fixed onMove<commit_after>
function Heap(comp, onMove) {
  this.comp = comp || function (a, b) {
    if (a > b) {
      return 1;
    } else if (a < b) {
      return -1;
    } else {
      return 0;
    }
  };
  this.data = [];
  this.onMove = onMove || function () {};
}

Heap.getParentIndex = function (i) {
  var parent = i % 2 ? (i - 1) / 2 : Math.floor((i - 1) / 2);
  return parent >= 0 ? parent : undefined;
};

Heap.getChild1Index = function (i) {
  return 2 * i + 1;
};

Heap.getChild2Index = function (i) {
  return 2 * i + 2;
};

Heap.prototype._swap = function (x, y) {
  var tmp = this.data[x];
  this.onMove(this.data[x], x, y);
  this.onMove(this.data[y], y, x);
  this.data[x] = this.data[y];
  this.data[y] = tmp;
};

Heap.prototype._bubbleUp = function bubbleUp(i) {
  var parentIndex;
  var data = this.data;
  var comp = this.comp;
  while (i > 0) {
    parentIndex = Heap.getParentIndex(i);
    if (comp(data[i], data[parentIndex]) < 0) {
      this._swap(i, parentIndex);
      i = parentIndex;
    }
    else {
      return i;
    }
  }
};

Heap.prototype._bubbleDown = function bubbleDown(i) {
  var data = this.data;
  var comp = this.comp;
  var child1Index, child2Index,
    child1isSmaller, child2isSmaller;
  while (i < data.length) {
    child1Index = Heap.getChild1Index(i);
    child2Index = Heap.getChild2Index(i);
    child1isSmaller = typeof data[child1Index] !== 'undefined' ? comp(data[child1Index], data[i]) < 0 : false;
    child2isSmaller = typeof data[child2Index] !== 'undefined' ? comp(data[child2Index], data[i]) < 0 : false;
    if (child1isSmaller && child2isSmaller) {
      if (comp(data[child1Index], data[child2Index]) < 0) {
        this._swap(child1Index, i);
        i = child1Index;
      }
      else {
        this._swap(child2Index, i);
        i = child2Index;
      }
    }
    else if (child1isSmaller) {
      this._swap(child1Index, i);
      i = child1Index;
    }
    else if (child2isSmaller) {
      this._swap(child2Index, i);
      i = child2Index;
    }
    else {
      return i;
    }
  }
};

Heap.prototype.pushAll = function (items) {
  for (var i = 0; i < items.length; i++) {
    this.push(items[i]);
  }
};

Heap.prototype.push = function (item) {
  this.data.push(item);
  this.onMove(this.data[this.data.length - 1], this.data.length - 1);
  this._bubbleUp(this.data.length - 1);
};

Heap.prototype.peek = function () {
  return this.data[0];
};

Heap.prototype.pop = function () {
  var root = this.data[0];
  var last = this.data.pop();

  if (this.data.length !== 0) {
    this.data[0] = last;
    this.onMove(this.data[0], 0);
    this._bubbleDown(0);
  }
  return root;
};

Heap.prototype.popAll = function () {
  var out = [];
  while (this.size()) {
    out.push(this.pop());
  }
  return out;
};

Heap.prototype.size = function () {
  return this.data.length;
};

Heap.prototype.indexOf = function (value) {
  var n, i = -1;
  var last;

  if (typeof value === 'function') {
    for (n = 0; n < this.data.length; n++) {
      if (value(this.data[n])) {
        i = n;
        break;
      }
    }
  }
  else {
    i = this.data.indexOf(value);
  }
  return i;
};

Heap.prototype.remove = function (value) {
  var i = this.indexOf(value);
  return this.removeIndex(i);
};

Heap.prototype.get = function (i) {
  return this.data[i];
};

Heap.prototype.removeIndex = function (i) {
  var last;
  if (i === -1) return;

  if (i === this.data.length - 1) {
    last = this.data.pop();
    return last;
  }

  this._swap(i, this.data.length - 1);

  last = this.data.pop();

  if (this.data.length > 1) {
    this._bubbleUp(i);
    this._bubbleDown(i);
  }
  return last;
};

Heap.prototype.replaceIndex = function (i, value) {
  var last;
  if (i === -1) return;
  this.data.push(value);

  this._swap(i, this.data.length - 1);

  last = this.data.pop();

  if (this.data.length > 1) {
    this._bubbleUp(i);
    this._bubbleDown(i);
  }
  return last;
};

Heap.prototype.toArray = function () {
  return this.data.slice(0);
};

module.exports = Heap;
<|endoftext|>


<commit_before>// this runs on all vikings with an etcd client to listen for events
var etcdjs = require('etcdjs')
var config = require('./config')()
var utils = require('component-consoler');
var HostMonitor = require('./hostmonitor')

module.exports = function(etcdhosts){
	var etcd = etcdjs(etcdhosts)

	var vikingHostname = config.network.hostname

	var hostMonitor = HostMonitor(config, etcd)

	// this means the leadership can be lost and then regained by the same server with no effect
	var leaderRunning = false

	// this will be trigged in another viking master if the etcd leadership changes
	function runLeader(){
		if(leaderRunning) return
		utils.log('leader', 'starting')
		leaderRunning = true

		hostMonitor.leader(function(){
			// the leader module has all the servies like registry and git push
			var leader = require('./leader')(config, etcd)
			leader.start(function(err){
				if(err){
					console.error('ERROR STARTING LEADER ' + err)
					return
				}

				utils.log('leader', 'running')
			})
		})
	}

	function runSlave(){
		console.log('-------------------------------------------');
		console.log('-------------------------------------------');
		console.log('running slave - ')
		console.dir(config)
		var slave = require('./slave')(config, etcd)
		slave.start(function(err){
			if(err){
				utils.error('ERROR STARTING SLAVE ' + err)
				return
			}

			utils.log('slave', 'running')
		})
	}

	function masterLoop(){
		etcd.stats.leader(function(err, stats){
			if(err){
				//utils.error(err)
				setTimeout(masterLoop, 200)
				return
			}
			if(!stats){
				utils.error('no stats were returned from the etcd server')
				setTimeout(masterLoop, 200)
				return
			}

			if(stats.leader==vikingHostname){
				runLeader()
			}
			setTimeout(masterLoop, 2000)
		})
	}

	setTimeout(function(){

		hostMonitor.start(function(){
			utils.log('host monitor', 'running')
		})

		setTimeout(function(){

			if(config.master){
				masterLoop()
			}

			runSlave()

		}, 500)
	}, 500)

}
<commit_msg>logging<commit_after>// this runs on all vikings with an etcd client to listen for events
var etcdjs = require('etcdjs')
var config = require('./config')()
var utils = require('component-consoler');
var HostMonitor = require('./hostmonitor')

module.exports = function(etcdhosts){
	var etcd = etcdjs(etcdhosts)

	var vikingHostname = config.network.hostname

	var hostMonitor = HostMonitor(config, etcd)

	// this means the leadership can be lost and then regained by the same server with no effect
	var leaderRunning = false

	// this will be trigged in another viking master if the etcd leadership changes
	function runLeader(){
		if(leaderRunning) return
		utils.log('leader', 'starting')
		leaderRunning = true

		hostMonitor.leader(function(){
			// the leader module has all the servies like registry and git push
			var leader = require('./leader')(config, etcd)
			leader.start(function(err){
				if(err){
					console.error('ERROR STARTING LEADER ' + err)
					return
				}

				utils.log('leader', 'running')
			})
		})
	}

	function runSlave(){
		var slave = require('./slave')(config, etcd)
		slave.start(function(err){
			if(err){
				utils.error('ERROR STARTING SLAVE ' + err)
				return
			}

			utils.log('slave', 'running')
		})
	}

	function masterLoop(){
		etcd.stats.leader(function(err, stats){
			if(err){
				//utils.error(err)
				setTimeout(masterLoop, 200)
				return
			}
			if(!stats){
				utils.error('no stats were returned from the etcd server')
				setTimeout(masterLoop, 200)
				return
			}

			if(stats.leader==vikingHostname){
				runLeader()
			}
			setTimeout(masterLoop, 2000)
		})
	}

	setTimeout(function(){

		hostMonitor.start(function(){
			utils.log('host monitor', 'running')
		})

		setTimeout(function(){

			if(config.master){
				masterLoop()
			}

			runSlave()

		}, 500)
	}, 500)

}
<|endoftext|>


<commit_before>"use strict";

// this is a basic wrapper for making Request() requests
//  we wrap this so we can have the same debug information for all requests

var needle = require("needle");

// get our project Log function for writing log output
var Log = require("./debugPrint");

// include our Promise library
var Promise = require("./promise");

/**
 * Make a network request
 * @private
 * @param parameters to pass to request library
 */
function MakeRequest(networkRequest) {
    if (arguments.length != 1) {
        return Promise.reject("HTTP requires 1 argument. The network object configuration");
    }

    // debug log if we're in debug mode
    Log(`Making request to ${networkRequest.url}`);

    // grab method from the request (we'll call .[method] directly using the needle library)
    var requestMethod = networkRequest.method || "get";
    delete networkRequest.method;

    // extract the required URL
    var requestURL = networkRequest.url;
    if (!requestURL) return Promise.reject(`No URL defined for ${requestMethod} request`);
    delete networkRequest.url;

    var requestData = networkRequest.data || networkRequest.body || {};
    delete networkRequest.data;
    delete networkRequest.body;

    // build-in retires into this wrapper (default 3)
    var retries = networkRequest.retries || 3;
    // un-set retries in-case request suddenly supports this or something!
    delete networkRequest.retries;

    // default delay of 2 seconds for each retry attempt
    var retryDelay = networkRequest.retryDelay || 2000;
    delete networkRequest.retryDelay;

    // we will default to returning the body, but can return the full response object if we want
    var returnFullResponse = networkRequest.returnFullResponse || false;
    delete networkRequest.returnFullResponse;

    // add ability to force responses into JSON objects, even if they don't return application/json content header
    var forceJSON = networkRequest.forceJSON || false;
    delete networkRequest.forceJSON;

    // return result as a Promise!
    return new Promise(function(resolve, reject) {
        var attempt = 0;

        // make request in an anonymouse function so we can make multiple requests to it easily
        var attemptRequest = function() {
            Log(`Calling ${requestMethod}:${requestURL}`);

            // build Needle request
            needle.request(requestMethod, requestURL, requestData, networkRequest, function(err, resp) {
                if (err || resp.statusCode >= 400 || (resp.statusCode == 200 && !resp.body)) {
                    Log(`Network request failed attempt ${attempt}/${retries} for URL ${requestURL}`);
                    Log(err || (resp.statusCode + ": " + JSON.stringify(resp.body, null, 2)));

                    // if we have retires left, try again!
                    attempt++;
                    if (attempt < retries) {
                        // try again after retryDelay milliseconds
                        setTimeout(attemptRequest, retryDelay);
                        return;
                    } else {
                        return reject(err || (resp.statusCode + ": " + JSON.stringify(resp.body, null, 2)), resp.statusCode);
                    }
                }

                // no error! return the result
                if (returnFullResponse) {
                    Log(`Successfully fetched response for URL ${requestURL}`);
                    return resolve(resp);
                } else {
                    // enable "forceJSON" if the return header type is "application/json"
                    if (resp.headers && resp.headers["content-type"] && resp.headers["content-type"].indexOf("application/json") >= 0) {
                        Log("Found 'application/json' header from in HTTP request, parsing JSON data");
                        forceJSON = true;
                    }

                    // if we want to force JSON (and we're not already a JSON object!)
                    if (forceJSON && resp.body.constructor !== {}.constructor && resp.body.constructor !== [].constructor) {
                        var JSONData;
                        try {
                            JSONData = JSON.parse(resp.body);
                        } catch (e) {
                            return reject(`Unable to parse ${resp.body} into a JSON object: ${e}`);
                        }
                        Log(`Successfully fetched and parsed JSON from response at ${requestURL}`);
                        return resolve(JSONData);
                    } else {
                        Log(`Successfully fetched body for URL ${requestURL}`);
                        return resolve(resp.body);
                    }
                }
            });
        };

        // make first request attempt
        process.nextTick(attemptRequest);
    }.bind(this));
}

module.exports = MakeRequest;<commit_msg>Don't return statusCode here, it may not be valid if an actual error was returned.<commit_after>"use strict";

// this is a basic wrapper for making Request() requests
//  we wrap this so we can have the same debug information for all requests

var needle = require("needle");

// get our project Log function for writing log output
var Log = require("./debugPrint");

// include our Promise library
var Promise = require("./promise");

/**
 * Make a network request
 * @private
 * @param parameters to pass to request library
 */
function MakeRequest(networkRequest) {
    if (arguments.length != 1) {
        return Promise.reject("HTTP requires 1 argument. The network object configuration");
    }

    // debug log if we're in debug mode
    Log(`Making request to ${networkRequest.url}`);

    // grab method from the request (we'll call .[method] directly using the needle library)
    var requestMethod = networkRequest.method || "get";
    delete networkRequest.method;

    // extract the required URL
    var requestURL = networkRequest.url;
    if (!requestURL) return Promise.reject(`No URL defined for ${requestMethod} request`);
    delete networkRequest.url;

    var requestData = networkRequest.data || networkRequest.body || {};
    delete networkRequest.data;
    delete networkRequest.body;

    // build-in retires into this wrapper (default 3)
    var retries = networkRequest.retries || 3;
    // un-set retries in-case request suddenly supports this or something!
    delete networkRequest.retries;

    // default delay of 2 seconds for each retry attempt
    var retryDelay = networkRequest.retryDelay || 2000;
    delete networkRequest.retryDelay;

    // we will default to returning the body, but can return the full response object if we want
    var returnFullResponse = networkRequest.returnFullResponse || false;
    delete networkRequest.returnFullResponse;

    // add ability to force responses into JSON objects, even if they don't return application/json content header
    var forceJSON = networkRequest.forceJSON || false;
    delete networkRequest.forceJSON;

    // return result as a Promise!
    return new Promise(function(resolve, reject) {
        var attempt = 0;

        // make request in an anonymouse function so we can make multiple requests to it easily
        var attemptRequest = function() {
            Log(`Calling ${requestMethod}:${requestURL}`);

            // build Needle request
            needle.request(requestMethod, requestURL, requestData, networkRequest, function(err, resp) {
                if (err || resp.statusCode >= 400 || (resp.statusCode == 200 && !resp.body)) {
                    Log(`Network request failed attempt ${attempt}/${retries} for URL ${requestURL}`);
                    Log(err || (resp.statusCode + ": " + JSON.stringify(resp.body, null, 2)));

                    // if we have retires left, try again!
                    attempt++;
                    if (attempt < retries) {
                        // try again after retryDelay milliseconds
                        setTimeout(attemptRequest, retryDelay);
                        return;
                    } else {
                        return reject(err || (resp.statusCode + ": " + JSON.stringify(resp.body, null, 2)));
                    }
                }

                // no error! return the result
                if (returnFullResponse) {
                    Log(`Successfully fetched response for URL ${requestURL}`);
                    return resolve(resp);
                } else {
                    // enable "forceJSON" if the return header type is "application/json"
                    if (resp.headers && resp.headers["content-type"] && resp.headers["content-type"].indexOf("application/json") >= 0) {
                        Log("Found 'application/json' header from in HTTP request, parsing JSON data");
                        forceJSON = true;
                    }

                    // if we want to force JSON (and we're not already a JSON object!)
                    if (forceJSON && resp.body.constructor !== {}.constructor && resp.body.constructor !== [].constructor) {
                        var JSONData;
                        try {
                            JSONData = JSON.parse(resp.body);
                        } catch (e) {
                            return reject(`Unable to parse ${resp.body} into a JSON object: ${e}`);
                        }
                        Log(`Successfully fetched and parsed JSON from response at ${requestURL}`);
                        return resolve(JSONData);
                    } else {
                        Log(`Successfully fetched body for URL ${requestURL}`);
                        return resolve(resp.body);
                    }
                }
            });
        };

        // make first request attempt
        process.nextTick(attemptRequest);
    }.bind(this));
}

module.exports = MakeRequest;<|endoftext|>


<commit_before>export default {
  'protocol_version': '5.0',
  'implementation': 'nodejs',

  'implementation_version': '1.0',
  'language': 'javascript',

  'language_info': {
    'name': 'nodejs',
    'version': '0.10',
    'mimetype': 'text/javascript',
    'file_extension': 'js',
    'pygments_lexer': 'javascript',
    'codemirror_mode': 'javascript',
  },
  'banner' : 'NodeJS For your Jupyter experience!',
  'help_links': [
    // {'text': str, 'url': str}
  ],
}
<commit_msg>Use correct file_extension format<commit_after>export default {
  'protocol_version': '5.0',
  'implementation': 'nodejs',

  'implementation_version': '1.0',
  'language': 'javascript',

  'language_info': {
    'name': 'nodejs',
    'version': '0.10',
    'mimetype': 'text/javascript',
    'file_extension': '.js',
    'pygments_lexer': 'javascript',
    'codemirror_mode': 'javascript',
  },
  'banner' : 'NodeJS For your Jupyter experience!',
  'help_links': [
    // {'text': str, 'url': str}
  ],
}
<|endoftext|>


<commit_before>var _ = require('lodash');

module.exports = function(grunt) {
  var module = {};

  // Allow projects to insert config into the gdt namespace before loading GDT bootstrap.
  // This will take precedence over environment or project-shipped config.
  module.magic = function (name, envName) {
    envName = envName || name;
    return grunt.config(['gdt', name])
      || process.env['GDT_' + envName.toUpperCase()]
      || grunt.config(['config', name]);
  }

  // Ensure a default URL for the project.
  module.siteUrls = function() {
    return grunt.config('config.siteUrls.default') || "http://<%= config.domain %>";
  }

  module.buildPaths = function() {
    // Set implicit global configuration.
    var buildPaths = grunt.config('config.buildPaths');
    buildPaths = _.extend({
      build: 'build',
      html: 'build/html',
      package: 'build/packages',
      reports: 'build/reports',
      temp: 'build/temp'
    }, buildPaths);

    return buildPaths;
  }

  module.themes = function(themes) {
    // If the theme path is not set give it a sane default.
    for (var key in themes) {
      if (!themes[key].path) {
        grunt.config(['themes', key, 'path'], "<%= config.srcPaths.drupal %>/themes/" + key);
      }
    }
  }

  module.init = function() {
    if (grunt.config('config.siteUrls') === undefined)
      grunt.config('config.siteUrls', {});

    grunt.config('config.domain', module.magic('domain') || require('os').hostname());
    grunt.config('config.alias', module.magic('alias', 'SITE_ALIAS'));
    grunt.config('config.profile', module.magic('profile', 'INSTALL_PROFILE') || 'standard');
    grunt.config('config.siteUrls.default', module.siteUrls());
    grunt.config('config.buildPaths', module.buildPaths());

    module.buildPaths(grunt.config('config.themes'))
  };

  return module;
};
<commit_msg>Add support for siteUrls to magic configuration.<commit_after>var _ = require('lodash');

module.exports = function(grunt) {
  var module = {};

  // Allow projects to insert config into the gdt namespace before loading GDT bootstrap.
  // This will take precedence over environment or project-shipped config.
  module.magic = function (name, envName) {
    envName = envName || name;
    return grunt.config(['gdt', name])
      || process.env['GDT_' + envName.toUpperCase()]
      || grunt.config(['config', name]);
  }

  // Ensure a default URL for the project.
  module.siteUrls = function() {
    return grunt.config('config.siteUrls.default') || "http://<%= config.domain %>";
  }

  module.buildPaths = function() {
    // Set implicit global configuration.
    var buildPaths = grunt.config('config.buildPaths');
    buildPaths = _.extend({
      build: 'build',
      html: 'build/html',
      package: 'build/packages',
      reports: 'build/reports',
      temp: 'build/temp'
    }, buildPaths);

    return buildPaths;
  }

  module.themes = function(themes) {
    // If the theme path is not set give it a sane default.
    for (var key in themes) {
      if (!themes[key].path) {
        grunt.config(['themes', key, 'path'], "<%= config.srcPaths.drupal %>/themes/" + key);
      }
    }
  }

  module.init = function() {
    if (grunt.config('config.siteUrls') === undefined)
      grunt.config('config.siteUrls', {});

    grunt.config('config.domain', module.magic('domain') || require('os').hostname());
    grunt.config('config.alias', module.magic('alias', 'SITE_ALIAS') || '@' + grunt.config('config.domain'));
    grunt.config('config.profile', module.magic('profile', 'INSTALL_PROFILE') || 'standard');
    grunt.config('config.siteUrls', module.magic('siteUrls') || {default: module.siteUrls});
    grunt.config('config.siteUrls.default', module.siteUrls());
    grunt.config('config.buildPaths', module.buildPaths());

    module.buildPaths(grunt.config('config.themes'))
  };

  return module;
};
<|endoftext|>


<commit_before>const
path = require('path'),
loadMods = function(keys, context, cb){
    if (!keys || !keys.length) { return cb(null, context) }

    const
    config = context.config, app = config.app, mods = config.mods,
    key = keys.shift(),
    value = mods[key],
    mod=value.mod

    if (!mod) return loadMods(keys, context, cb) //ignore empty mod

    const module = require('.' === mod.charAt(0) ? mod : path.resolve(app.path, 'mod', mod))

    module.create(app, value, (err, mod)=>{
        if (err) console.error('failed to load modules', value.mod, err)
        context[key] = mod
        loadMods(keys, context, cb)
    })
},
loadDeps = function(cwd, keys, deps, context, cb){
    if (!keys.length) return cb()

    const
    k=keys.shift(),
    v=deps[k]

    if (Array.isArray(v)){
        deps[k]=context[v[1]]
        return loadDeps(cwd, keys, deps, context, cb)
    }
    const m=require(path.resolve(cwd, v))
    deps[k]=m
    m.setup(context, (err)=>{
        if (err) return cb(err)
        loadDeps(cwd, keys, deps, context, cb)
    })
},
// pico counterpart of loadAction is in lib/app.js
loadAction = function(cwd, action, context, cb){
    loadDeps(cwd, Object.keys(action.deps), action.deps, context, (err)=>{
        if (err) return cb(err)
        context.sigslot.load(action.deps, action.routes, cb)
    })
},
loadActions = function(cwd, actionPaths, context, cb){
    if (!actionPaths || !actionPaths.length) { return cb(null, context) }

    const
    actionPath = actionPaths.shift(),
    p=path.resolve(cwd,actionPath)

	let action

    try{
        action = require(p)
    }catch(ex){
        console.error('failed to load actions %s, exception: %s',actionPath,ex.message)
        return loadActions(cwd, actionPaths, context, cb)
    }

    loadAction(path.dirname(p), action, context, ()=>{
        return loadActions(cwd, actionPaths, context, cb)
    })
}

module.exports = {
    load(config, cb){
		const app=config.app
        console.log('load modules',app.name,app.id)

		loadMods(config.mods ? Object.keys(config.mods) : undefined, {config: config, sigslot:app.sigslot}, (err, context)=>{
			if (err) return cb(err)
			if (!app.actions) return cb(null, context, app)
			loadActions(process.cwd(),app.actions, context, (err)=>{
				return cb(err, context, app)
			})
		})
    }
}
<commit_msg>fixed external mod loading<commit_after>const
path = require('path'),
loadMods = function(keys, context, cb){
    if (!keys || !keys.length) { return cb(null, context) }

    const
    config = context.config, app = config.app, mods = config.mods,
    key = keys.shift(),
    value = mods[key],
    mod=value.mod

    if (!mod) return loadMods(keys, context, cb) //ignore empty mod

    let module
	try { module = require(path.resolve(app.path, 'mod', mod)) }
	catch(e) { module = require(mod) }

    module.create(app, value, (err, m)=>{
        if (err) console.error('failed to load modules', mod, err)
        context[key] = m
        loadMods(keys, context, cb)
    })
},
loadDeps = function(cwd, keys, deps, context, cb){
    if (!keys.length) return cb()

    const
    k=keys.shift(),
    v=deps[k]

    if (Array.isArray(v)){
        deps[k]=context[v[1]]
        return loadDeps(cwd, keys, deps, context, cb)
    }
    const m=require(path.resolve(cwd, v))
    deps[k]=m
    m.setup(context, (err)=>{
        if (err) return cb(err)
        loadDeps(cwd, keys, deps, context, cb)
    })
},
// pico counterpart of loadAction is in lib/app.js
loadAction = function(cwd, action, context, cb){
    loadDeps(cwd, Object.keys(action.deps), action.deps, context, (err)=>{
        if (err) return cb(err)
        context.sigslot.load(action.deps, action.routes, cb)
    })
},
loadActions = function(cwd, actionPaths, context, cb){
    if (!actionPaths || !actionPaths.length) { return cb(null, context) }

    const
    actionPath = actionPaths.shift(),
    p=path.resolve(cwd,actionPath)

	let action

    try{
        action = require(p)
    }catch(ex){
        console.error('failed to load actions %s, exception: %s',actionPath,ex.message)
        return loadActions(cwd, actionPaths, context, cb)
    }

    loadAction(path.dirname(p), action, context, ()=>{
        return loadActions(cwd, actionPaths, context, cb)
    })
}

module.exports = {
    load(config, cb){
		const app=config.app
        console.log('load modules',app.name,app.id)

		loadMods(config.mods ? Object.keys(config.mods) : undefined, {config: config, sigslot:app.sigslot}, (err, context)=>{
			if (err) return cb(err)
			if (!app.actions) return cb(null, context, app)
			loadActions(process.cwd(),app.actions, context, (err)=>{
				return cb(err, context, app)
			})
		})
    }
}
<|endoftext|>