<commit_before>
var gitStream = require('./stream-git');
var es = require('event-stream');
var fs = require('fs');
var formidable = require('formidable');
var path = require('path');

var decoders = require('js-git/lib/decoders');
var pktLine = require('git-pkt-line');
var repos = require('./repos');

function fileList (req) {
  var keys = [ ];
  for (var key in req.files) {
    keys.push(req.files[key]);
  }
  return keys;
}

function fileStream (req) {
  return es.readArray(fileList(req));
}

function fileContentBlob ( ) {
  function writer (chunk, cb) {
    var input = fs.createReadStream(chunk.path);
    input.pipe(es.writeArray(function (err, content) {
      content = content[0].toString( );
      var blob = { chunk: chunk, name: chunk.name, content: content };
      console.log(chunk.name, 'content', blob);
      cb(null, blob);
    }));
  }
  var stream = es.map(writer);
  return stream;
}

function uploads (req, res, next) {
  var form = new formidable.IncomingForm();
  console.log('parsing');
  req.form = form.parse(req, function(err, fields, files) {
    req.body = fields;
    console.log('err', err);
    console.log('found files', files);
    console.log('found fields', fields);
    req.files = files;
  });
  next( );
}

function getRepo (opts) {
  var createRepo = repos(opts);
  return (function (req, res, next) {
    req.repo = createRepo(req.repo_path);
    next( );
  });

}

function repo_name (req, res, next) {
  req.repo_name = req.params.repo + '.git';
  next( );
};

function getPath (opts) {
  var path = require('path');
  return function (req, res, next) {
    req.repo_path = path.join(opts.base, req.params.owner, req.repo_name);
    console.log("GIT PATH", req.repo_path);
    next( );
  };
}

function fixGitRequest (opts) {
  var candidate = /\.git\.git$/;
  return  function (req, res, next) {
    console.log("GIT REQUEST", req.repo_name, candidate.test(req.repo_name), req.url);
    if (candidate.test(req.repo_name)) {
      req.repo_name = req.repo_name.replace(candidate, '.git');
      console.log("GIT REQUEST REPLACED:", req.repo_name);
    }
    next( );
  };
};

function install (server, opts) {
  console.log('installing routes');
  var createRepo = repos(opts);
  var version = require('../package.json').version;
  server.get('/status', function (req, res, next) {
    res.send(200, "OK@" + version);
  });

  var middleware = [ repo_name, getPath(opts), getRepo(opts) ];
  var gitMiddleWare = [ repo_name, fixGitRequest(opts), getPath(opts),  getRepo(opts) ];
  server.get('/repos/:owner/:repo', repo_name, getPath(opts), getRepo(opts), function (req, res, next) {
    req.repo.listRefs("refs/heads", function (err, refs) {
      res.send(200, {params: req.params, msg: 'hmm', name: req.repo_name, path: req.repo_path, repo: req.repo, body: refs});

    });
  });

  server.get('/repos/:owner/', function (req, res, next) {
    res.send(["ha", req.params]);
  });
  server.post('/repo/test', opts.bodyParser( ), function (req, res, next) {
    var name = './out/test.git';
    console.log('files', req.files, req.body);
    var input = fileStream(req);
    var git = gitStream(name);
    es.pipeline(input, fileContentBlob( ), git,  es.writeArray( function (err, results) {
      console.log('error or results FINISH', err, results);

      res.send(201, {err: err, body: results})
    }));
    next( );
  });

  server.post('/repos/:owner/:repo/upload', repo_name, getPath(opts), getRepo(opts), opts.bodyParser( ), function (req, res, next) {
    console.log(req.repo_path, req.repo_name, 'files', req.files, req.body, 'to repo', req.repo);
    var input = fileStream(req);
    var git = gitStream(req.repo);
    es.pipeline(input, fileContentBlob( ), git,  es.writeArray( function (err, results) {
      console.log('error or results FINISH', err, results);

      res.send(201, {err: err, body: results})
    }));
    next( );
  });

  server.get('/repos/:owner/:repo/git/refs', middleware, function (req, res, next) {
    console.log('REPO', req.repo);
    req.repo.db.keys('refs/', console.log);
    req.repo.listRefs('refs/',  function (err, refs) {
      console.log("REFS", err, refs);
      var keys = Object.keys(refs);
      console.log('keys', keys);
      refs.url = server.url + path.join(req.path( ));
      var results = [ ];
      keys.forEach(function (key) {
        var item = refs[key];
        console.log('each', key, item);
        var r = {
          ref: key,
          sha: item,
          url: server.url + path.join('/repos', req.params.owner, req.params.repo, 'git', key)
        };
        results.push(r);
        // item.url  = path.join(server.url, item.type + 's', item.body.tree);
      });
      res.send(200, {err: err, body: results});

    });
  });

  server.get('/repos/:owner/:repo/git/refs/(.*)', middleware, function (req, res, next) {
    var ref = 'refs';
    var pattern = /refs\/(.*)/;
    var hashish = req.path( ).match(pattern);
    if (hashish && hashish.length > 1) ref = hashish[0];
    console.log('result', hashish);
    console.log('ref', ref, 'url', req.url, req.path(/refs/), 'params', req.params, req.params[0]);
    // req.repo.load(ref, function (err, refs) {
    req.repo.readRef(ref, function (err, hash) {
      req.repo.load(hash, function (err, refs) {
        console.log("REFS", refs);
        var inspect = server.url + path.join('/repos', req.params.owner,
                            req.params.repo, 'git', refs.type + 's', hash);
        var o = {type: refs.type, sha: refs.body.tree, url: inspect};
        res.send(200, {err: err, body: o});
      });

    });
  });

  server.get('/repos/:owner/:repo/git/commits/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    console.log('load commit', hash, 'repo', req.repo);
    var p = hash.slice(0, 2) + '/' + hash.slice(2);
    req.repo.load(hash,  function (err, commit) {
    // req.repo.load( hash, function (err, commit) {
      var inspect = server.url + path.join('/repos', req.params.owner,
                          req.params.repo, 'git', 'trees', commit.body.tree);
      commit.url = inspect;
      console.log('FOUND COMMIT', err, commit);
      res.send(200, {err: err, body: commit});

    });
    next( );
  });

  server.get('/repos/:owner/:repo/git/trees/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    console.log('hash', hash, req.params, req);
    var inspect = path.join(req.url);
    req.repo.loadAs("tree", hash, function (err, tree) {
      console.log('FOUND COMMIT', tree);
      Object.keys(tree).forEach(function (blob) {
        var inspect = path.join('/repos', req.params.owner, req.params.repo, 'git', 'blobs', blob.hash )
        blob.url = inspect;
      });
      res.send(200, {err: err, body: tree, url: inspect});

    });
  });

  server.get('/repos/:owner/:repo/git/blobs/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    req.repo.loadAs('text', hash, function (err, blob) {
      console.log('blob', blob);
      var b = blob;
      var o = {err: err, content: b, size: blob.length, encoding: 'utf-8' };
      res.send(o);
    });
  });

  server.get('/repos/:owner/:repo/info/refs', gitMiddleWare, function (req, res, next) {
    res.setHeader('Expires', 'Fri, 01 Jan 1980 00:00:00 GMT');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
    if (req.params.service) {
      var service = req.params.service;
      res.setHeader('Content-Type', 'application/x-git-' + service + '-pack-advertisement');
      console.log('SERVICE', service);
      var packet = "# service=" + service + "\n";
      var length = packet.length + 4;
      var hex = "0123456789abcdef";
      var prefix = hex.charAt((length >> 12) & 0xf);
      prefix = prefix + hex.charAt((length >> 8) & 0xf);
      prefix = prefix + hex.charAt((length >> 4) & 0xf);
      prefix = prefix + hex.charAt(length & 0xf);
      var head = prefix + packet + "\u0000";
      var result = [ ];
      // result.push(head);
      var tr = es.through( ).pause( );
      es.pipeline(tr, res);
      // tr.pipe(res);
      tr.resume( );
      if (service == 'git-upload-pack') {
        console.log("REPO", req.repo);

        var writePkt = pktLine.framer(function (item) {
          console.log('framed', item);
          tr.write(item);
        });
        writePkt('line', '# service=' + service + "\n");
        // req.repo.listRefs("refs", function (err, refs) {
        req.repo.listRefs("refs/", function (err, refs) {
          console.log('REFS', err, refs);
          Object.keys(refs).forEach(function (ref) {
            var item = refs[ref] + " " + ref;
            result.push(item);
            console.log('EACH ITEM', item);
            writePkt('line', item + "\n");
            // tr.write(item);
          });
          writePkt('line', null);
          writePkt('line', null);
          tr.end( );
            // result.push('\u0000');
        });
      }
      // res.end( );
      var incoming = es.through( );
      reader = pktLine.deframer(function (item) {
        incoming.write(item);
      });
      res.pipe(es.map(function (data, cb) {
        console.log('incoming', data);
        cb(null, reader('line', data));
      }));
    }
    console.log("REQ", req.url);
    // next( );
    // res.send(200, req.params);
  });
  return server;
}
install.install = install;
module.exports = install;
<commit_msg>A bit closer?<commit_after>
var gitStream = require('./stream-git');
var es = require('event-stream');
var fs = require('fs');
var formidable = require('formidable');
var path = require('path');

var decoders = require('js-git/lib/decoders');
var pktLine = require('git-pkt-line');
var repos = require('./repos');

function fileList (req) {
  var keys = [ ];
  for (var key in req.files) {
    keys.push(req.files[key]);
  }
  return keys;
}

function fileStream (req) {
  return es.readArray(fileList(req));
}

function fileContentBlob ( ) {
  function writer (chunk, cb) {
    var input = fs.createReadStream(chunk.path);
    input.pipe(es.writeArray(function (err, content) {
      content = content[0].toString( );
      var blob = { chunk: chunk, name: chunk.name, content: content };
      console.log(chunk.name, 'content', blob);
      cb(null, blob);
    }));
  }
  var stream = es.map(writer);
  return stream;
}

function uploads (req, res, next) {
  var form = new formidable.IncomingForm();
  console.log('parsing');
  req.form = form.parse(req, function(err, fields, files) {
    req.body = fields;
    console.log('err', err);
    console.log('found files', files);
    console.log('found fields', fields);
    req.files = files;
  });
  next( );
}

function getRepo (opts) {
  var createRepo = repos(opts);
  return (function (req, res, next) {
    req.repo = createRepo(req.repo_path);
    next( );
  });

}

function repo_name (req, res, next) {
  req.repo_name = req.params.repo + '.git';
  next( );
};

function getPath (opts) {
  var path = require('path');
  return function (req, res, next) {
    req.repo_path = path.join(opts.base, req.params.owner, req.repo_name);
    console.log("GIT PATH", req.repo_path);
    next( );
  };
}

function fixGitRequest (opts) {
  var candidate = /\.git\.git$/;
  return  function (req, res, next) {
    console.log("GIT REQUEST", req.repo_name, candidate.test(req.repo_name), req.url);
    if (candidate.test(req.repo_name)) {
      req.repo_name = req.repo_name.replace(candidate, '.git');
      console.log("GIT REQUEST REPLACED:", req.repo_name);
    }
    next( );
  };
};

function install (server, opts) {
  console.log('installing routes');
  var createRepo = repos(opts);
  var version = require('../package.json').version;
  server.get('/status', function (req, res, next) {
    res.send(200, "OK@" + version);
  });

  var middleware = [ repo_name, getPath(opts), getRepo(opts) ];
  var gitMiddleWare = [ repo_name, fixGitRequest(opts), getPath(opts),  getRepo(opts) ];
  server.get('/repos/:owner/:repo', repo_name, getPath(opts), getRepo(opts), function (req, res, next) {
    req.repo.listRefs("refs/heads", function (err, refs) {
      res.send(200, {params: req.params, msg: 'hmm', name: req.repo_name, path: req.repo_path, repo: req.repo, body: refs});

    });
  });

  server.get('/repos/:owner/', function (req, res, next) {
    res.send(["ha", req.params]);
  });
  server.post('/repo/test', opts.bodyParser( ), function (req, res, next) {
    var name = './out/test.git';
    console.log('files', req.files, req.body);
    var input = fileStream(req);
    var git = gitStream(name);
    es.pipeline(input, fileContentBlob( ), git,  es.writeArray( function (err, results) {
      console.log('error or results FINISH', err, results);

      res.send(201, {err: err, body: results})
    }));
    next( );
  });

  server.post('/repos/:owner/:repo/upload', repo_name, getPath(opts), getRepo(opts), opts.bodyParser( ), function (req, res, next) {
    console.log(req.repo_path, req.repo_name, 'files', req.files, req.body, 'to repo', req.repo);
    var input = fileStream(req);
    var git = gitStream(req.repo);
    es.pipeline(input, fileContentBlob( ), git,  es.writeArray( function (err, results) {
      console.log('error or results FINISH', err, results);

      res.send(201, {err: err, body: results})
    }));
    next( );
  });

  server.get('/repos/:owner/:repo/git/refs', middleware, function (req, res, next) {
    console.log('REPO', req.repo);
    req.repo.db.keys('refs/', console.log);
    req.repo.listRefs('refs/',  function (err, refs) {
      console.log("REFS", err, refs);
      var keys = Object.keys(refs);
      console.log('keys', keys);
      refs.url = server.url + path.join(req.path( ));
      var results = [ ];
      keys.forEach(function (key) {
        var item = refs[key];
        console.log('each', key, item);
        var r = {
          ref: key,
          sha: item,
          url: server.url + path.join('/repos', req.params.owner, req.params.repo, 'git', key)
        };
        results.push(r);
        // item.url  = path.join(server.url, item.type + 's', item.body.tree);
      });
      res.send(200, {err: err, body: results});

    });
  });

  server.get('/repos/:owner/:repo/git/refs/(.*)', middleware, function (req, res, next) {
    var ref = 'refs';
    var pattern = /refs\/(.*)/;
    var hashish = req.path( ).match(pattern);
    if (hashish && hashish.length > 1) ref = hashish[0];
    console.log('result', hashish);
    console.log('ref', ref, 'url', req.url, req.path(/refs/), 'params', req.params, req.params[0]);
    // req.repo.load(ref, function (err, refs) {
    req.repo.readRef(ref, function (err, hash) {
      req.repo.load(hash, function (err, refs) {
        console.log("REFS", refs);
        var inspect = server.url + path.join('/repos', req.params.owner,
                            req.params.repo, 'git', refs.type + 's', hash);
        var o = {type: refs.type, sha: refs.body.tree, url: inspect};
        res.send(200, {err: err, body: o});
      });

    });
  });

  server.get('/repos/:owner/:repo/git/commits/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    console.log('load commit', hash, 'repo', req.repo);
    var p = hash.slice(0, 2) + '/' + hash.slice(2);
    req.repo.load(hash,  function (err, commit) {
    // req.repo.load( hash, function (err, commit) {
      var inspect = server.url + path.join('/repos', req.params.owner,
                          req.params.repo, 'git', 'trees', commit.body.tree);
      commit.url = inspect;
      console.log('FOUND COMMIT', err, commit);
      res.send(200, {err: err, body: commit});

    });
    next( );
  });

  server.get('/repos/:owner/:repo/git/trees/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    console.log('hash', hash, req.params, req);
    var inspect = path.join(req.url);
    req.repo.loadAs("tree", hash, function (err, tree) {
      console.log('FOUND COMMIT', tree);
      Object.keys(tree).forEach(function (blob) {
        var inspect = path.join('/repos', req.params.owner, req.params.repo, 'git', 'blobs', blob.hash )
        blob.url = inspect;
      });
      res.send(200, {err: err, body: tree, url: inspect});

    });
  });

  server.get('/repos/:owner/:repo/git/blobs/:sha', middleware, function (req, res, next) {
    var hash = req.params.sha;
    req.repo.loadAs('text', hash, function (err, blob) {
      console.log('blob', blob);
      var b = blob;
      var o = {err: err, content: b, size: blob.length, encoding: 'utf-8' };
      res.send(o);
    });
  });

  server.post('/repos/:owner/:repo/info/refs', gitMiddleWare, function (req, res, next) {
    console.log("WTF??");
  });
  server.get('/repos/:owner/:repo/info/refs', gitMiddleWare, function (req, res, next) {
    res.setHeader('Expires', 'Fri, 01 Jan 1980 00:00:00 GMT');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate');
    if (req.params.service) {
      var service = req.params.service;
      res.setHeader('Content-Type', 'application/' + service + '-advertisement');
      console.log('SERVICE', service);
      var packet = "# service=" + service + "\n";
      var length = packet.length + 4;
      var hex = "0123456789abcdef";
      var prefix = hex.charAt((length >> 12) & 0xf);
      prefix = prefix + hex.charAt((length >> 8) & 0xf);
      prefix = prefix + hex.charAt((length >> 4) & 0xf);
      prefix = prefix + hex.charAt(length & 0xf);
      var head = prefix + packet + "\u0000";
      var result = [ ];
      // result.push(head);
      var tr = es.through( ).pause( );
      tr.on('end', function ( ) { });
      es.pipeline(tr, res);
      // tr.pipe(res);
      tr.resume( );
      var firstref = 'true';
      if (service == 'git-upload-pack') {
        console.log("REPO", req.repo);

        var writePkt = pktLine.framer(function (item) {
          console.log('framed', item);
          tr.write(item);
        });
        writePkt('line', '# service=' + service + "\n");
        // req.repo.listRefs("refs", function (err, refs) {
        var read = (function () {
        });
        req.repo.listRefs("refs/", function (err, refs) {
          console.log('REFS', err, refs);
          var keys = Object.keys(refs);
          keys.forEach(function (ref, i) {
            var item = refs[ref] + " " + ref;
            if (i == 0) {
              firstref = false;
              item = item + '\000multi_ack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done';
            }
            if (i == keys.length - 1) {
              item = item + '^{}';
            }
            result.push(item);
            console.log('EACH ITEM', i, item);
            writePkt('line', item + "\n");
            // tr.write(item);
          });
          // writePkt('line', null);
          // writePkt('line', null);
          tr.end( );
          next( );
            // result.push('\u0000');
        });
      }
      // res.end( );
      var incoming = es.through( );
      reader = pktLine.deframer(function (item) {
        incoming.write(item);
      });
      res.pipe(es.map(function (data, cb) {
        console.log('incoming', data);
        cb(null, reader('line', data));
      }));
    }
    console.log("REQ", req.url);
    // next( );
    // res.send(200, req.params);
  });
  return server;
}
install.install = install;
module.exports = install;
<|endoftext|>


<commit_before>// @flow

var temp = require("temp"),
  fs = require("fs-extra"),
  path = require("path"),
  child_process = require("child_process");

function install(pathToElmBinary/*:string*/, packageName/*:string*/) {
  var oldSourceDirectories;

  // Automatically track and cleanup files at exit
  temp.track();

  try {
    var dirPath = temp.mkdirSync("elm-test-install-");

    var elmJson = JSON.parse(fs.readFileSync("elm.json"));
    var tmpElmJsonPath = path.join(dirPath, "elm.json");
    var isPackage;

    switch (elmJson["type"]) {
      case "package":
        isPackage = true;
        break;

      case "application":
        isPackage = false;
        break;

      default:
        console.error("Unrecognized elm.json type:", elmJson["type"]);
        process.exit(1);
    }

    // This mirrors the behavior of `elm install` passing a package that is
    // already installed. Say it's already installed, then exit 0.
    if ((isPackage && elmJson["test-dependencies"].hasOwnProperty(packageName))
      || (!isPackage && elmJson["test-dependencies"]["direct"].hasOwnProperty(packageName))) {

      console.log("It is already installed!");
      return;
    }

    oldSourceDirectories = elmJson["source-directories"];

    // Without this, `elm install` will complain about missing source dirs
    // in the temp dir. This way we don't have to create them!
    elmJson["source-directories"] = ["."];

    fs.writeFileSync(tmpElmJsonPath, JSON.stringify(elmJson), "utf8");

    var cmd = [pathToElmBinary, "install"].concat([packageName]).join(" ");

    child_process.execSync(cmd, { stdio: "inherit", cwd: dirPath });

    var newElmJson = JSON.parse(fs.readFileSync(tmpElmJsonPath, "utf8"));

    if(isPackage) {
      Object.keys(newElmJson["dependencies"]).forEach(function(key) {
        if (!elmJson["dependencies"].hasOwnProperty(key)) {
          // If we didn't have this dep before, move it to test-dependencies.
          newElmJson["test-dependencies"][key] =
            newElmJson["dependencies"][key];

          delete newElmJson["dependencies"][key];
        }
      });
    } else {
      function moveToTestDeps(directness) {
        Object.keys(newElmJson["dependencies"][directness]).forEach(function(key) {
          if (!elmJson["dependencies"][directness].hasOwnProperty(key)) {
            // If we didn't have this dep before, move it to test-dependencies.
            newElmJson["test-dependencies"][directness][key] =
              newElmJson["dependencies"][directness][key];

            delete newElmJson["dependencies"][directness][key];
          }
        });
      }

      moveToTestDeps("direct");
      moveToTestDeps("indirect");
    }

    // Restore the old source-directories value.
    newElmJson["source-directories"] = oldSourceDirectories;

    fs.writeFileSync("elm.json", JSON.stringify(newElmJson, null, 4) + "\n", "utf8");
  } catch (err) {
    console.error("Unable to create temporary directory for elm-test install.", err);
    process.exit(1);
  }
}

module.exports = {
  install: install
};
<commit_msg>Don't install a dep to indirect if it's in direct<commit_after>// @flow

var temp = require("temp"),
  fs = require("fs-extra"),
  path = require("path"),
  child_process = require("child_process");

function install(pathToElmBinary/*:string*/, packageName/*:string*/) {
  var oldSourceDirectories;

  // Automatically track and cleanup files at exit
  temp.track();

  try {
    var dirPath = temp.mkdirSync("elm-test-install-");

    var elmJson = JSON.parse(fs.readFileSync("elm.json"));
    var tmpElmJsonPath = path.join(dirPath, "elm.json");
    var isPackage;

    switch (elmJson["type"]) {
      case "package":
        isPackage = true;
        break;

      case "application":
        isPackage = false;
        break;

      default:
        console.error("Unrecognized elm.json type:", elmJson["type"]);
        process.exit(1);
    }

    // This mirrors the behavior of `elm install` passing a package that is
    // already installed. Say it's already installed, then exit 0.
    if ((isPackage && elmJson["test-dependencies"].hasOwnProperty(packageName))
      || (!isPackage && elmJson["test-dependencies"]["direct"].hasOwnProperty(packageName))) {

      console.log("It is already installed!");
      return;
    }

    oldSourceDirectories = elmJson["source-directories"];

    // Without this, `elm install` will complain about missing source dirs
    // in the temp dir. This way we don't have to create them!
    elmJson["source-directories"] = ["."];

    fs.writeFileSync(tmpElmJsonPath, JSON.stringify(elmJson), "utf8");

    var cmd = [pathToElmBinary, "install"].concat([packageName]).join(" ");

    child_process.execSync(cmd, { stdio: "inherit", cwd: dirPath });

    var newElmJson = JSON.parse(fs.readFileSync(tmpElmJsonPath, "utf8"));

    if(isPackage) {
      Object.keys(newElmJson["dependencies"]).forEach(function(key) {
        if (!elmJson["dependencies"].hasOwnProperty(key)) {
          // If we didn't have this dep before, move it to test-dependencies.
          newElmJson["test-dependencies"][key] =
            newElmJson["dependencies"][key];

          delete newElmJson["dependencies"][key];
        }
      });
    } else {
      function moveToTestDeps(directness) {
        Object.keys(newElmJson["dependencies"][directness]).forEach(function(key) {
          // If we didn't have this dep before, move it to test-dependencies.
          if (!elmJson["dependencies"][directness].hasOwnProperty(key)) {
            // Don't put things in indirect test-dependencies if they
            // are already present in direct test-dependencies! See this issue:
            // https://github.com/rtfeldman/node-test-runner/issues/282
            if (directness === "direct" || !newElmJson["test-dependencies"]["direct"].hasOwnProperty(key)) {
              newElmJson["test-dependencies"][directness][key] =
                newElmJson["dependencies"][directness][key];
            }

            delete newElmJson["dependencies"][directness][key];
          }
        });
      }

      moveToTestDeps("direct");
      moveToTestDeps("indirect");
    }

    // Restore the old source-directories value.
    newElmJson["source-directories"] = oldSourceDirectories;

    fs.writeFileSync("elm.json", JSON.stringify(newElmJson, null, 4) + "\n", "utf8");
  } catch (err) {
    console.error("Unable to create temporary directory for elm-test install.", err);
    process.exit(1);
  }
}

module.exports = {
  install: install
};
<|endoftext|>


<commit_before>var path = require('path');

require.paths.unshift(path.join(__dirname, 'vendor'),
                      path.join(__dirname, 'journey'));

var sys = require("sys"),
   http = require("http"),
 events = require('events'),
     fs = require("fs"),
    url = require('url');

var querystring = require('querystring');
var proto = require('proto');

var journey = exports;

var BadRequest = function (msg) {
    this.status = 400;
    this.headers = {};
    this.body = { error: msg };
};
var NotFound = function (msg) {
    this.status = 404;
    this.headers = {};
    this.body = { error: msg };
};
var MethodNotAllowed = function (allowed) {
    this.status = 405;
    this.headers = { allow: allowed };
    this.body = { error: "method not allowed." };
};
var NotAcceptable = function (msg) {
    this.status = 406;
    this.headers = {};
    this.body = { error: msg, only: "application/json" };
};

journey.env = 'development';
journey.version = [0, 1, 0];

//
// Logging & Debugging functions
//

journey.logger = {
    info: function (s) {
        if (journey.env === 'development') sys.puts(s);
    },

    err: function (s) {
        if (journey.env === 'development') sys.puts(s.stylize('red'));
    }
};
journey.log = journey.logger.info;
journey.debug = function (s) {
    sys.puts((s || 'false').toString().stylize('magenta'));
};

//
// The Router
//

journey.Router = function Router(routes) {
    var map = journey.map(this);
    this.routes = [];

    // Call map() in the context of `this.map`, so `this`
    // can be used instead of the passed argument.
    routes.call(map, map);
};

journey.map = function (context) {
    return {
        get:  function (pattern, opts) { return this.route('GET',    pattern, opts) },
        put:  function (pattern, opts) { return this.route('PUT',    pattern, opts) },
        post: function (pattern, opts) { return this.route('POST',   pattern, opts) },
        del:  function (pattern, opts) { return this.route('DELETE', pattern, opts) },

        route: function (/* variable arguments */) {
            var args = Array.prototype.slice.call(arguments).compact(),
                // Defaults
                pattern     = /.*/,
                method      = journey.Router.prototype.methods,
                constraints = {};

            args.forEach(function (arg) {
                if (typeof(arg) === "object") {
                    constraints = arg;
                } else if (journey.Router.prototype.methods.indexOf(arg) !== -1) {
                    method = arg;
                } else if (typeof(arg) === "string" || arg.exec) {
                    pattern = arg;
                } else {
                    throw new(Error)("cannot understand route.");
                }
            });

            return {
                bind: function (handler, success) {
                    return context.routes.push({
                        patterns: Array.isArray(pattern) ? pattern : [pattern],
                        method:   method,  handler: handler,
                        success:  success, constraints: constraints
                    });
                }
            };
        },
        trail: function (from, to) {
            // Logging
        }
    };
};

journey.Router.prototype = {
    methods: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'],

    // Called when the HTTP request is 'complete'
    // and ready to be processed.
    route: function (request, body, callback) {
        var promise = new(events.EventEmitter);
        var that = this;

        request.url = url.parse(request.url);

        // Call the router asynchronously, so we can return a promise
        process.nextTick(function () {
            // Dispatch the HTTP request:
            // As the last argument, we send the function to be called when the response is ready
            // to be sent back to the client -- this allows us to keep our entry and exit point
            // in the same spot. `outcome` is an object with a `status`, a `body` and `headers`
            that.dispatch(request, body || "", function (outcome) {
                outcome.headers["Content-Type"] = "application/json";
                outcome.headers["Date"] = new(Date)().toUTCString();
                outcome.headers["Server"] = "journey/" + journey.version.join('.');

                if (typeof(outcome.body) !== 'string') {
                    outcome.body = JSON.stringify(outcome.body);
                }

                outcome.body += '\n';

                if (outcome.status >= 300) {
                    outcome.headers['Content-Length'] = outcome.body.length.toString();
                }

                if (callback) { callback(outcome) }
                else          { promise.emit("success", outcome) }

                promise.emit("log", new(Date)().toUTCString() +
                             " -- " + request.method +  " "   +
                             request.url.href + " - HTTP " + outcome.status);
            });
        });
        return promise;
    },

    constraints: {
        //
        // Check if the request has a non-empty body
        //
        payload: function (payload, request, body) {
            return Boolean(body) === payload;
        },

        //
        // Run a function, and check return value
        //
        assert: function (assert, request, body) {
            return Boolean(assert(request, body));
        }
    },

    resolve: function (request, body) {
        var that = this, allowedMethods = [];
        //
        // Return the first matching route
        //
        var found = this.routes.find(function (route) {
            // Match the pattern with the url
            var match = route.patterns.find(function (pattern) {
                var path = request.url.pathname, ignoreCase;

                if (! path) { throw new(BadRequest) }

                // Trim trailing slashes and add ^$ markers to strings
                if (typeof(pattern) === "string") {
                    pattern = '^' + pattern.match(/^(\/)$|^\/?(.*?)\/?$/)
                                           .slice(1).join('') + '$';
                } else {
                    ignoreCase = pattern.ignoreCase;
                    pattern = pattern.source.match(/^(\^)?\/?(.*?)\/?(\$)?$/)
                                            .slice(1).join('');
                }

                pattern = new(RegExp)(pattern, ignoreCase ? 'i' : '');

                return (path.length > 1 ? path.slice(1) : path).match(pattern);
            });

            //
            // Run through the specified constraints,
            // making sure everything passes.
            //
            var constraints = Object.keys(route.constraints).length === 0 ? true :
                Object.keys(route.constraints).every(function (key) {
                // Check if the constraint has been defined, then run it.
                if (that.constraints.hasOwnProperty(key)) {
                    return that.constraints[key](route.constraints[key], request, body);
                } else {
                    throw new(Error)("constraint '" + key + "' not found.");
                }
            });

            if (match && constraints) {
                if ((Array.isArray(route.method) && route.method.hasOwnProperty(request.method)) ||
                    (route.method === request.method)) {
                    return function (res, params) {
                        return route.handler.apply(this, [res].concat(match.slice(1), params));
                    };
                } else {
                    allowedMethods.push(route.method);
                    return false;
                }
            }
            return false;
        });

        if (found) {
            return found;
        } else if (allowedMethods.length) {
            throw new(MethodNotAllowed)(allowedMethods.join(','));
        } else {
            return false;
        }
    },

    // This function glues together the request resolver, with the responder.
    // It creates a new `route` context, in which the response will be generated.
    dispatch: function (request, body, respond) {
        var resolved, route, parser, params = request.url.query || {};

        try {
            resolved = this.resolve(request, body);
        } catch (e) {
            if (e.status) return respond({ headers: e.headers || {}, status: e.status, body: e.message });
            else throw e;
        }

        route = this.route(request, respond);

        if (resolved) {
            if (body) {
                if (request.headers["Content-Type"] === "application/json") { parser = JSON.parse }
                else { parser = querystring.parse }

                try {
                    Object.mixin(params, parser(body));
                } catch (e) {
                    return respond(new(BadRequest)("malformed data"));
                }
            }
            return route.go(resolved, params);
        } else { return respond({ status: 404, body: "request not found" }) }
    },

    // A constructor of sorts, which returns a 'Routing context', in which the response
    // status is evaluated.
    route: function (req, respond) {
        return {
            request:   req,
            respond:   respond,
            baseResponse: {
                status: 200,
                body: "",
                headers: {"Content-Type" : "application/json"}
            },

            // A wrapper around `respond()`, it allows us to respond in a variety of
            // ways, such as: `201`, `"Hello World"`, `[201, "Hello", {'Content-Type':'text/html'}]`, etc.
            // All parameters are optional.
            responder: function (response) {
                // If more than one argument was received, treat it as if it was an array.
                if (arguments.length > 1) { response = Array.prototype.slice.apply(arguments) }

                this.respond((function (baseResponse) {
                    switch (Object.typeOf(response)) {
                        case "object":
                            return Object.mixin({}, baseResponse, response);
                        case "string":
                            return Object.mixin({}, baseResponse, { body: response });
                        case "number":
                            return Object.mixin({}, baseResponse, { status: response });
                        case "array":
                            switch (response.length) {
                                case 3: return {
                                    status:  response[0],
                                    headers: response[1],
                                    body:    response[2]
                                };
                                case 2: return Object.mixin({}, baseResponse, {
                                    status: response[0],
                                    body:   response[1]
                                });
                                default: throw new(Error)("expected 2 or 3 elements in response");
                            }
                        case "undefined": return baseResponse;
                        default: throw "wrong response type";
                    }
                })(this.baseResponse));
            },

            go: function (destination, params) {
                this.send = this.responder;

                try {
                    destination.call(this, this, params) || {};
                } catch (err) {
                    journey.logger.err(err.stack || err.toString() + "\n");
                    this.responder({
                        body: JSON.stringify({ error: err.message || err }),
                        status: err.status || 500
                    });
                }
            }
        }
    }
};

<commit_msg>resond properly to an unacceptable Accept header<commit_after>var path = require('path');

require.paths.unshift(path.join(__dirname, 'vendor'),
                      path.join(__dirname, 'journey'));

var sys = require("sys"),
   http = require("http"),
 events = require('events'),
     fs = require("fs"),
    url = require('url');

var querystring = require('querystring');
var proto = require('proto');

var journey = exports;

var BadRequest = function (msg) {
    this.status = 400;
    this.headers = {};
    this.body = { error: msg };
};
var NotFound = function (msg) {
    this.status = 404;
    this.headers = {};
    this.body = { error: msg };
};
var MethodNotAllowed = function (allowed) {
    this.status = 405;
    this.headers = { allow: allowed };
    this.body = { error: "method not allowed." };
};
var NotAcceptable = function (msg) {
    this.status = 406;
    this.headers = {};
    this.body = { error: msg, only: "application/json" };
};

journey.env = 'development';
journey.version = [0, 1, 0];

//
// Logging & Debugging functions
//

journey.logger = {
    info: function (s) {
        if (journey.env === 'development') sys.puts(s);
    },

    err: function (s) {
        if (journey.env === 'development') sys.puts(s.stylize('red'));
    }
};
journey.log = journey.logger.info;
journey.debug = function (s) {
    sys.puts((s || 'false').toString().stylize('magenta'));
};

//
// The Router
//

journey.Router = function Router(routes) {
    var map = journey.map(this);
    this.routes = [];

    // Call map() in the context of `this.map`, so `this`
    // can be used instead of the passed argument.
    routes.call(map, map);
};

journey.map = function (context) {
    return {
        get:  function (pattern, opts) { return this.route('GET',    pattern, opts) },
        put:  function (pattern, opts) { return this.route('PUT',    pattern, opts) },
        post: function (pattern, opts) { return this.route('POST',   pattern, opts) },
        del:  function (pattern, opts) { return this.route('DELETE', pattern, opts) },

        route: function (/* variable arguments */) {
            var args = Array.prototype.slice.call(arguments).compact(),
                // Defaults
                pattern     = /.*/,
                method      = journey.Router.prototype.methods,
                constraints = {};

            args.forEach(function (arg) {
                if (typeof(arg) === "object") {
                    constraints = arg;
                } else if (journey.Router.prototype.methods.indexOf(arg) !== -1) {
                    method = arg;
                } else if (typeof(arg) === "string" || arg.exec) {
                    pattern = arg;
                } else {
                    throw new(Error)("cannot understand route.");
                }
            });

            return {
                bind: function (handler, success) {
                    return context.routes.push({
                        patterns: Array.isArray(pattern) ? pattern : [pattern],
                        method:   method,  handler: handler,
                        success:  success, constraints: constraints
                    });
                }
            };
        },
        trail: function (from, to) {
            // Logging
        }
    };
};

journey.Router.prototype = {
    methods: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'],

    // Called when the HTTP request is 'complete'
    // and ready to be processed.
    route: function (request, body, callback) {
        var promise = new(events.EventEmitter);
        var that = this;

        request.url = url.parse(request.url);

        // Call the router asynchronously, so we can return a promise
        process.nextTick(function () {
            // Dispatch the HTTP request:
            // As the last argument, we send the function to be called when the response is ready
            // to be sent back to the client -- this allows us to keep our entry and exit point
            // in the same spot. `outcome` is an object with a `status`, a `body` and `headers`
            that.dispatch(request, body || "", function (outcome) {
                outcome.headers["Content-Type"] = "application/json";
                outcome.headers["Date"] = new(Date)().toUTCString();
                outcome.headers["Server"] = "journey/" + journey.version.join('.');

                if (typeof(outcome.body) !== 'string') {
                    outcome.body = JSON.stringify(outcome.body);
                }

                outcome.body += '\n';

                if (outcome.status >= 300) {
                    outcome.headers['Content-Length'] = outcome.body.length.toString();
                }

                if (callback) { callback(outcome) }
                else          { promise.emit("success", outcome) }

                promise.emit("log", new(Date)().toUTCString() +
                             " -- " + request.method +  " "   +
                             request.url.href + " - HTTP " + outcome.status);
            });
        });
        return promise;
    },

    constraints: {
        //
        // Check if the request has a non-empty body
        //
        payload: function (payload, request, body) {
            return Boolean(body) === payload;
        },

        //
        // Run a function, and check return value
        //
        assert: function (assert, request, body) {
            return Boolean(assert(request, body));
        }
    },

    resolve: function (request, body) {
        var that = this, allowedMethods = [];
        //
        // Return the first matching route
        //
        var found = this.routes.find(function (route) {
            // Match the pattern with the url
            var match = route.patterns.find(function (pattern) {
                var path = request.url.pathname, ignoreCase;

                if (! path) { throw new(BadRequest) }

                // Trim trailing slashes and add ^$ markers to strings
                if (typeof(pattern) === "string") {
                    pattern = '^' + pattern.match(/^(\/)$|^\/?(.*?)\/?$/)
                                           .slice(1).join('') + '$';
                } else {
                    ignoreCase = pattern.ignoreCase;
                    pattern = pattern.source.match(/^(\^)?\/?(.*?)\/?(\$)?$/)
                                            .slice(1).join('');
                }

                pattern = new(RegExp)(pattern, ignoreCase ? 'i' : '');

                return (path.length > 1 ? path.slice(1) : path).match(pattern);
            });

            //
            // Run through the specified constraints,
            // making sure everything passes.
            //
            var constraints = Object.keys(route.constraints).length === 0 ? true :
                Object.keys(route.constraints).every(function (key) {
                // Check if the constraint has been defined, then run it.
                if (that.constraints.hasOwnProperty(key)) {
                    return that.constraints[key](route.constraints[key], request, body);
                } else {
                    throw new(Error)("constraint '" + key + "' not found.");
                }
            });

            if (match && constraints) {
                if ((Array.isArray(route.method) && route.method.hasOwnProperty(request.method)) ||
                    (route.method === request.method)) {
                    return function (res, params) {
                        return route.handler.apply(this, [res].concat(match.slice(1), params));
                    };
                } else {
                    allowedMethods.push(route.method);
                    return false;
                }
            }
            return false;
        });

        if (found) {
            return found;
        } else if (allowedMethods.length) {
            throw new(MethodNotAllowed)(allowedMethods.join(','));
        } else {
            return false;
        }
    },

    // This function glues together the request resolver, with the responder.
    // It creates a new `route` context, in which the response will be generated.
    dispatch: function (request, body, respond) {
        var resolved, route, parser, params = request.url.query || {};

        // Journey being a JSON-only server, we expect the 'Accept' header to be set accordingly
        if (["application/json", "*/*"].indexOf(request.headers.accept) === -1) {
            return respond(new(NotAcceptable)(
                "cannot generate " + request.headers.accept + " response")
            );
        }

        try {
            resolved = this.resolve(request, body);
        } catch (e) {
            if (e.status) return respond({ headers: e.headers || {}, status: e.status, body: e.message });
            else throw e;
        }

        route = this.route(request, respond);

        if (resolved) {
            if (body) {
                if (request.headers["Content-Type"] === "application/json") { parser = JSON.parse }
                else { parser = querystring.parse }

                try {
                    Object.mixin(params, parser(body));
                } catch (e) {
                    return respond(new(BadRequest)("malformed data"));
                }
            }
            return route.go(resolved, params);
        } else { return respond({ status: 404, body: "request not found" }) }
    },

    // A constructor of sorts, which returns a 'Routing context', in which the response
    // status is evaluated.
    route: function (req, respond) {
        return {
            request:   req,
            respond:   respond,
            baseResponse: {
                status: 200,
                body: "",
                headers: {"Content-Type" : "application/json"}
            },

            // A wrapper around `respond()`, it allows us to respond in a variety of
            // ways, such as: `201`, `"Hello World"`, `[201, "Hello", {'Content-Type':'text/html'}]`, etc.
            // All parameters are optional.
            responder: function (response) {
                // If more than one argument was received, treat it as if it was an array.
                if (arguments.length > 1) { response = Array.prototype.slice.apply(arguments) }

                this.respond((function (baseResponse) {
                    switch (Object.typeOf(response)) {
                        case "object":
                            return Object.mixin({}, baseResponse, response);
                        case "string":
                            return Object.mixin({}, baseResponse, { body: response });
                        case "number":
                            return Object.mixin({}, baseResponse, { status: response });
                        case "array":
                            switch (response.length) {
                                case 3: return {
                                    status:  response[0],
                                    headers: response[1],
                                    body:    response[2]
                                };
                                case 2: return Object.mixin({}, baseResponse, {
                                    status: response[0],
                                    body:   response[1]
                                });
                                default: throw new(Error)("expected 2 or 3 elements in response");
                            }
                        case "undefined": return baseResponse;
                        default: throw "wrong response type";
                    }
                })(this.baseResponse));
            },

            go: function (destination, params) {
                this.send = this.responder;

                try {
                    destination.call(this, this, params) || {};
                } catch (err) {
                    journey.logger.err(err.stack || err.toString() + "\n");
                    this.responder({
                        body: JSON.stringify({ error: err.message || err }),
                        status: err.status || 500
                    });
                }
            }
        }
    }
};

<|endoftext|>


<commit_before>var sys    = require("sys"),
    http   = require("http"),
    events = require('events'),
    posix  = require("posix"),
    url    = require('url');

require('../../proto');

var journey = exports;

var BadRequest = function (msg) {
    this.name = "BadRequest";
    this.code = 400;
    this.message = msg;
};
var NotFound = function (msg) {
    this.name = "NotFound";
    this.code = 404;
    this.message = msg;
};
var MethodNotAllowed = function (allowed) {
    this.code = 405;
    this.headers = { allow: allowed };
    this.message = "Method not allowed.";
};

journey.env = 'development';

//
// Logging & Debugging functions
//

journey.logger = {
    info: function (s) {
        if (journey.env === 'development') sys.puts(s);
    },

    err: function (s) {
        if (journey.env === 'development') sys.puts(s.stylize('red'));
    }
};
journey.log = journey.logger.info;
journey.debug = function (s) {
    sys.puts((s || 'false').toString().stylize('magenta'));
};

//
// The Router
//

journey.router = {
    routes: [],

    draw: function (map) {
        this.map.resources = journey.resources;
        return map(this.map);
    },

    methods: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'],

    map: {
        get:  function (pattern, opts) { return this.route('GET',    pattern, opts) },
        put:  function (pattern, opts) { return this.route('PUT',    pattern, opts) },
        post: function (pattern, opts) { return this.route('POST',   pattern, opts) },
        del:  function (pattern, opts) { return this.route('DELETE', pattern, opts) },

        route: function (/* variable arguments */) {
            var args = Array.prototype.slice.call(arguments).compact(),
                // Defaults
                pattern     = /.*/,
                method      = journey.router.methods,
                constraints = {};

            args.each(function (arg) {
                if (Object.is(arg)) {
                    constraints = arg;
                } else if (journey.router.methods.indexOf(arg) !== -1) {
                    method = arg;
                } else if (String.is(arg) || RegExp.is(arg)) {
                    pattern = arg;
                } else {
                    throw new(Error)("cannot understand route.");
                }
            });

            return {
                to: function (handler, success) {
                    return journey.router.routes.push({
                        patterns: Array.is(pattern) ? pattern : [pattern],
                        method:   method,  handler: handler,
                        success:  success, constraints: constraints
                    });
                },

                toResource: function (handler, success) {
                    var to;

                    if (Function.is(handler)) {
                        to = handler();
                    } else {

                    }

                    return journey.router.routes.push({
                        pattern: pattern, method: method,
                        handler: handler, constraints: constraints,
                        success: success
                    })
                }
            };
        },
        trail: function (from, to) {
            // Logging
        },
        resources: journey.resources
    },

    constraints: {
        //
        // Check if the request has a non-empty body
        //
        payload: function (payload, request, body) {
            return Boolean(body) === payload;
        }
    },

    resolve: function (request, body) {
        var that = this, allowedMethods = [];
        //
        // Return the first matching route
        //
        var found = this.routes.find(function (route) {
            // Match the pattern with the url
            var match = route.patterns.find(function (pattern) {
                var path = request.url.pathname;
                if (! path) throw new(BadRequest);
                if (String.is(pattern)) pattern = new(RegExp)('^' + pattern + '$');
                return (path.length > 1 ? path.slice(1) : path).match(pattern);
            });

            //
            // Run through the specified constraints,
            // making sure everything passes.
            //
            var constraints = Object.isEmpty(route.constraints) ? true :
                Object.keys(route.constraints).every(function (key) {
                // Check if the constraint has been defined, then run it.
                if (that.constraints.hasOwnProperty(key)) {
                    return that.constraints[key](route.constraints[key], request, body);
                } else {
                    throw new(Error)("constraint '" + key + "' not found.");
                }
            });

            if (match && constraints) {
                if ((Array.is(route.method) && route.method.hasOwnProperty(request.method)) ||
                    (route.method === request.method)) {
                    return function (res, params) {
                        return route.handler.apply(this, [res].concat(match.slice(1), params));
                    };
                } else {
                    allowedMethods.push(route.method);
                    return false;
                }
            }
            return false;
        });

        if (found) {
            return found;
        } else if (allowedMethods.length) {
            throw new(MethodNotAllowed)(allowedMethods.join(','));
        } else {
            return false;
        }
    },

    // This function glues together the request resolver, with the responder.
    // It creates a new `Route` context, in which the response will be generated.
    dispatch: function (request, response, body, respond) {
        var resolved, route, parser, params = request.url.query || {};

        try {
            resolved = this.resolve(request, body);
        } catch (e) {
            if (e.code) return respond({ headers: e.headers || {}, code: e.code, body: e.message });
            else throw e;
        }

        route = new(this.Route)(request, response, respond);

        this.map.resources = journey.resources;

        if (resolved) {
            if (body) {
                if (request.headers["Content-Type"] === "application/json") { parser = JSON.parse }
                else { parser = querystring.parse }
                process.mixin(params, parser(body));
            }
            return route.go(resolved, params);
        } else { return respond({ code: 400, body: "request not found" }) }
    },

    // A constructor of sorts, which returns a 'Routing context', in which the response
    // code is evaluated.
    Route: function (req, res, respond) {
        return {
            request:   req,
            response:  res,
            resources: journey.resources,
            respond:   respond,
            baseResponse: {
                code: 200,
                body: "",
                headers: {"Content-Type" : "application/json"}
            },

            // A wrapper around `respond()`, it allows us to respond in a variety of
            // ways, such as: `201`, `"Hello World"`, `[201, "Hello", {'Content-Type':'text/html'}]`, etc.
            // All parameters are optional.
            responder: function (response) {
                // If more than one argument was received, treat it as if it was an array.
                if (arguments.length > 1) { response = Array.prototype.slice.apply(arguments) }

                this.respond((function (baseResponse) {
                    switch (process.typeOf(response)) {
                        case "object":
                            return process.mixin({}, baseResponse, response);
                        case "string":
                            return process.mixin({}, baseResponse, { body: response });
                        case "number":
                            return process.mixin({}, baseResponse, { code: response });
                        case "array":
                            switch (response.length) {
                                case 3: return {
                                    code:    response[0],
                                    headers: response[1],
                                    body:    response[2]
                                };
                                case 2: return process.mixin({}, baseResponse, {
                                    code: response[0],
                                    body: response[1]
                                });
                                default: throw new(Error)("expected 2 or 3 elements in response");
                            }
                        case "undefined": return baseResponse;
                        default: throw "wrong response type";
                    }
                })(this.baseResponse));
            },

            go: function (destination, params) {
                this.send = this.responder;

                try {
                    destination.call(this, this, params) || {};
                } catch (err) {
                    journey.logger.err(err.stack || err.toString() + "\n");
                    this.responder({ body: err.message || err, code: err.code || 500 });
                }
            }
        }
    }
};

journey.begin = function (resources, port) {
    if (resources && Object.is(resources)) {
        this.resources = resources;
        return this.server.listen(port || 8080);
    } else {
        throw "couldn't read `resources`";
    }
};

journey.end = function (code, msg) {
    if (msg) { process.stdio.write(msg) }
    this.server.close();
    return process.exit(code || 0);
};

journey.server = {
    instance: null, // The http.createServer instance

    listen: function (port) {
        var that = this;
        this.instance = http.createServer(function (request, response) {
            var body = "";
            request.addListener('body',     function (chunk) { body += chunk });
            request.addListener('complete', that.handler(request, response, body));
        }).listen(port);
        sys.puts("Journey running on 127.0.0.1:" + port);
        return this.instance;
    },

    close: function () { return this.instance ? this.instance.close() : false },

    // Called when the HTTP request is 'complete'
    // and ready to be processed.
    handler: function (request, response, body) {
        var promise = new(events.Promise);
        request.url = url.parse(request.url);

        // Call the router asynchronously, so we can return a promise
        process.nextTick(function () {
            // Dispatch the HTTP request:
            // As the last argument, we send the function to be called when the response is ready
            // to be sent back to the client -- this allows us to keep our entry and exit point
            // in the same spot. `outcome` is an object with a `code`, a `body` and `headers`
            journey.router.dispatch(request, response, body || "", function (outcome) {
                // Journey being a JSON-only server, we expect the 'Accept' header to be set accordingly
                var code = (request.headers.accept === "application/json") ? outcome.code : 400;

                response.sendHeader(code, outcome.headers || {"Content-Type" : "text/html"});

                if (outcome.code >= 400) {
                    if (journey.env === 'development') {
                        response.sendBody(outcome.body);
                    }
                } else {
                    response.sendBody(outcome.body);
                }

                response.finish();

                journey.log((new(Date)).toGMTString() + " -- " + request.method + " " + request.url.href + " - HTTP " + code);
                return promise.emitSuccess(response);
            });
        });
        return promise;
    }
};

<commit_msg>cleaned up requires<commit_after>var path = require('path');

require.paths.unshift(path.join(__dirname, 'vendor'),
                      path.join(__dirname, 'journey'));

var sys = require("sys"),
   http = require("http"),
 events = require('events'),
  posix = require("posix"),
    url = require('url');

var querystring = require('querystring');
var proto = require('proto');

var journey = exports;

var BadRequest = function (msg) {
    this.name = "BadRequest";
    this.code = 400;
    this.message = msg;
};
var NotFound = function (msg) {
    this.name = "NotFound";
    this.code = 404;
    this.message = msg;
};
var MethodNotAllowed = function (allowed) {
    this.code = 405;
    this.headers = { allow: allowed };
    this.message = "Method not allowed.";
};

journey.env = 'development';

//
// Logging & Debugging functions
//

journey.logger = {
    info: function (s) {
        if (journey.env === 'development') sys.puts(s);
    },

    err: function (s) {
        if (journey.env === 'development') sys.puts(s.stylize('red'));
    }
};
journey.log = journey.logger.info;
journey.debug = function (s) {
    sys.puts((s || 'false').toString().stylize('magenta'));
};

//
// The Router
//

journey.router = {
    routes: [],

    draw: function (map) {
        this.map.resources = journey.resources;
        return map(this.map);
    },

    methods: ['GET', 'PUT', 'POST', 'DELETE', 'HEAD'],

    map: {
        get:  function (pattern, opts) { return this.route('GET',    pattern, opts) },
        put:  function (pattern, opts) { return this.route('PUT',    pattern, opts) },
        post: function (pattern, opts) { return this.route('POST',   pattern, opts) },
        del:  function (pattern, opts) { return this.route('DELETE', pattern, opts) },

        route: function (/* variable arguments */) {
            var args = Array.prototype.slice.call(arguments).compact(),
                // Defaults
                pattern     = /.*/,
                method      = journey.router.methods,
                constraints = {};

            args.each(function (arg) {
                if (Object.is(arg)) {
                    constraints = arg;
                } else if (journey.router.methods.indexOf(arg) !== -1) {
                    method = arg;
                } else if (String.is(arg) || RegExp.is(arg)) {
                    pattern = arg;
                } else {
                    throw new(Error)("cannot understand route.");
                }
            });

            return {
                to: function (handler, success) {
                    return journey.router.routes.push({
                        patterns: Array.is(pattern) ? pattern : [pattern],
                        method:   method,  handler: handler,
                        success:  success, constraints: constraints
                    });
                },

                toResource: function (handler, success) {
                    var to;

                    if (Function.is(handler)) {
                        to = handler();
                    } else {

                    }

                    return journey.router.routes.push({
                        pattern: pattern, method: method,
                        handler: handler, constraints: constraints,
                        success: success
                    })
                }
            };
        },
        trail: function (from, to) {
            // Logging
        },
        resources: journey.resources
    },

    constraints: {
        //
        // Check if the request has a non-empty body
        //
        payload: function (payload, request, body) {
            return Boolean(body) === payload;
        }
    },

    resolve: function (request, body) {
        var that = this, allowedMethods = [];
        //
        // Return the first matching route
        //
        var found = this.routes.find(function (route) {
            // Match the pattern with the url
            var match = route.patterns.find(function (pattern) {
                var path = request.url.pathname;
                if (! path) throw new(BadRequest);
                if (String.is(pattern)) pattern = new(RegExp)('^' + pattern + '$');
                return (path.length > 1 ? path.slice(1) : path).match(pattern);
            });

            //
            // Run through the specified constraints,
            // making sure everything passes.
            //
            var constraints = Object.isEmpty(route.constraints) ? true :
                Object.keys(route.constraints).every(function (key) {
                // Check if the constraint has been defined, then run it.
                if (that.constraints.hasOwnProperty(key)) {
                    return that.constraints[key](route.constraints[key], request, body);
                } else {
                    throw new(Error)("constraint '" + key + "' not found.");
                }
            });

            if (match && constraints) {
                if ((Array.is(route.method) && route.method.hasOwnProperty(request.method)) ||
                    (route.method === request.method)) {
                    return function (res, params) {
                        return route.handler.apply(this, [res].concat(match.slice(1), params));
                    };
                } else {
                    allowedMethods.push(route.method);
                    return false;
                }
            }
            return false;
        });

        if (found) {
            return found;
        } else if (allowedMethods.length) {
            throw new(MethodNotAllowed)(allowedMethods.join(','));
        } else {
            return false;
        }
    },

    // This function glues together the request resolver, with the responder.
    // It creates a new `Route` context, in which the response will be generated.
    dispatch: function (request, response, body, respond) {
        var resolved, route, parser, params = request.url.query || {};

        try {
            resolved = this.resolve(request, body);
        } catch (e) {
            if (e.code) return respond({ headers: e.headers || {}, code: e.code, body: e.message });
            else throw e;
        }

        route = new(this.Route)(request, response, respond);

        this.map.resources = journey.resources;

        if (resolved) {
            if (body) {
                if (request.headers["Content-Type"] === "application/json") { parser = JSON.parse }
                else { parser = querystring.parse }
                process.mixin(params, parser(body));
            }
            return route.go(resolved, params);
        } else { return respond({ code: 400, body: "request not found" }) }
    },

    // A constructor of sorts, which returns a 'Routing context', in which the response
    // code is evaluated.
    Route: function (req, res, respond) {
        return {
            request:   req,
            response:  res,
            resources: journey.resources,
            respond:   respond,
            baseResponse: {
                code: 200,
                body: "",
                headers: {"Content-Type" : "application/json"}
            },

            // A wrapper around `respond()`, it allows us to respond in a variety of
            // ways, such as: `201`, `"Hello World"`, `[201, "Hello", {'Content-Type':'text/html'}]`, etc.
            // All parameters are optional.
            responder: function (response) {
                // If more than one argument was received, treat it as if it was an array.
                if (arguments.length > 1) { response = Array.prototype.slice.apply(arguments) }

                this.respond((function (baseResponse) {
                    switch (process.typeOf(response)) {
                        case "object":
                            return process.mixin({}, baseResponse, response);
                        case "string":
                            return process.mixin({}, baseResponse, { body: response });
                        case "number":
                            return process.mixin({}, baseResponse, { code: response });
                        case "array":
                            switch (response.length) {
                                case 3: return {
                                    code:    response[0],
                                    headers: response[1],
                                    body:    response[2]
                                };
                                case 2: return process.mixin({}, baseResponse, {
                                    code: response[0],
                                    body: response[1]
                                });
                                default: throw new(Error)("expected 2 or 3 elements in response");
                            }
                        case "undefined": return baseResponse;
                        default: throw "wrong response type";
                    }
                })(this.baseResponse));
            },

            go: function (destination, params) {
                this.send = this.responder;

                try {
                    destination.call(this, this, params) || {};
                } catch (err) {
                    journey.logger.err(err.stack || err.toString() + "\n");
                    this.responder({ body: err.message || err, code: err.code || 500 });
                }
            }
        }
    }
};

journey.begin = function (resources, port) {
    if (resources && Object.is(resources)) {
        this.resources = resources;
        return this.server.listen(port || 8080);
    } else {
        throw "couldn't read `resources`";
    }
};

journey.end = function (code, msg) {
    if (msg) { process.stdio.write(msg) }
    this.server.close();
    return process.exit(code || 0);
};

journey.server = {
    instance: null, // The http.createServer instance

    listen: function (port) {
        var that = this;
        this.instance = http.createServer(function (request, response) {
            var body = "";
            request.addListener('body',     function (chunk) { body += chunk });
            request.addListener('complete', that.handler(request, response, body));
        }).listen(port);
        sys.puts("Journey running on 127.0.0.1:" + port);
        return this.instance;
    },

    close: function () { return this.instance ? this.instance.close() : false },

    // Called when the HTTP request is 'complete'
    // and ready to be processed.
    handler: function (request, response, body) {
        var promise = new(events.Promise);
        request.url = url.parse(request.url);

        // Call the router asynchronously, so we can return a promise
        process.nextTick(function () {
            // Dispatch the HTTP request:
            // As the last argument, we send the function to be called when the response is ready
            // to be sent back to the client -- this allows us to keep our entry and exit point
            // in the same spot. `outcome` is an object with a `code`, a `body` and `headers`
            journey.router.dispatch(request, response, body || "", function (outcome) {
                // Journey being a JSON-only server, we expect the 'Accept' header to be set accordingly
                var code = (request.headers.accept === "application/json") ? outcome.code : 400;

                response.sendHeader(code, outcome.headers || {"Content-Type" : "text/html"});

                if (outcome.code >= 400) {
                    if (journey.env === 'development') {
                        response.sendBody(outcome.body);
                    }
                } else {
                    response.sendBody(outcome.body);
                }

                response.finish();

                journey.log((new(Date)).toGMTString() + " -- " + request.method + " " + request.url.href + " - HTTP " + code);
                return promise.emitSuccess(response);
            });
        });
        return promise;
    }
};

<|endoftext|>