From ca1882a9c394ed55e129072e7eddf01d023ddbc1 Mon Sep 17 00:00:00 2001 From: NGPixel Date: Sat, 20 Aug 2016 00:50:29 -0400 Subject: [PATCH] Git repository handling --- .gitignore | 5 +- config.sample.yml | 23 ++++++ controllers/pages.js | 14 +++- models/git.js | 170 +++++++++++++++++++++++++++++++++++++++++++ server.js | 9 ++- views/pages/view.pug | 2 + 6 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 models/git.js diff --git a/.gitignore b/.gitignore index cceafa60..6ec55ce7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,7 @@ jspm_packages *.sublime-workspace # Config Files -config.yml \ No newline at end of file +config.yml + +# App Repo +repo \ No newline at end of file diff --git a/config.sample.yml b/config.sample.yml index 221a3dbb..a47a2d57 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -38,6 +38,29 @@ redis: port: 6379 db: 0 +# ------------------------------------------------- +# Git Connection Info +# ------------------------------------------------- +# Full explanation + examples in the documentation (https://requarks-wiki.readme.io/) + +git: + path: auto + mode: remote + url: https://github.com/Organization/Repo + auth: + type: ssh + user: gitusername + publickey: /etc/requarkswiki/keys/git.pub + privatekey: /etc/requarkswiki/keys/git.key + passphrase: SomeSshPassphrase + # auth: + # type: oauth + # token: 1234567890abcdefghijklmnopqrstuvxyz + # auth: + # type: basic + # user: johnsmith + # pass: password123 + # ------------------------------------------------- # Secret key to use when encrypting sessions # ------------------------------------------------- diff --git a/controllers/pages.js b/controllers/pages.js index 1dfa9d16..733df64f 100644 --- a/controllers/pages.js +++ b/controllers/pages.js @@ -7,7 +7,19 @@ var router = express.Router(); * Home */ router.get('/', (req, res) => { - res.render('pages/view'); + + var md = require('markdown-it')({ + breaks: true, + linkify: true, + typographer: true + }); + + var Promise = require('bluebird'); + var fs = Promise.promisifyAll(require("fs")); + fs.readFileAsync("repo/Gollum.md", "utf8").then(function(contents) { + res.render('pages/view', { contents: md.render(contents) }); + }); + }); module.exports = router; \ No newline at end of file diff --git a/models/git.js b/models/git.js new file mode 100644 index 00000000..ba8b4f00 --- /dev/null +++ b/models/git.js @@ -0,0 +1,170 @@ +"use strict"; + +var NodeGit = require("nodegit"), + Promise = require('bluebird'), + path = require('path'), + os = require('os'), + fs = Promise.promisifyAll(require("fs")), + _ = require('lodash'); + +/** + * Git Model + */ +module.exports = { + + _git: null, + _repo: { + path: '', + exists: false, + inst: null + }, + + /** + * Initialize Git model + * + * @param {Object} appconfig The application config + * @return {Object} Git model instance + */ + init(appconfig) { + + let self = this; + + //-> Build repository path + + if(_.isEmpty(appconfig.git.path) || appconfig.git.path === 'auto') { + self._repo.path = path.join(ROOTPATH, 'repo'); + } else { + self._repo.path = appconfig.git.path; + } + + //-> Initialize repository + + self._initRepo(appconfig).then((repo) => { + self._repo.inst = repo; + }); + + return self; + + }, + + /** + * Initialize Git repository + * + * @param {Object} appconfig The application config + * @return {Object} Promise + */ + _initRepo(appconfig) { + + let self = this; + + winston.info('[GIT] Initializing Git repository...'); + + //-> Check if path is accessible + + return fs.mkdirAsync(self._repo.path).catch((err) => { + if(err.code !== 'EEXIST') { + winston.error('Invalid Git repository path or missing permissions.'); + } + }).then(() => { + + //-> Check if path already contains a git working folder + + return fs.statAsync(path.join(self._repo.path, '.git')).then((stat) => { + self._repo.exists = stat.isDirectory(); + }).catch((err) => { + self._repo.exists = false; + }); + + }).then(() => { + + //-> Init repository + + let repoInitOperation = null; + + if(self._repo.exists) { + + winston.info('[GIT] Using existing repository...'); + repoInitOperation = NodeGit.Repository.open(self._repo.path); + + } else if(appconfig.git.remote) { + + winston.info('[GIT] Cloning remote repository for first time...'); + let cloneOptions = self._generateCloneOptions(appconfig); + repoInitOperation = NodeGit.Clone(appconfig.git.url, self._repo.path, cloneOptions); + + } else { + + winston.info('[GIT] Using offline local repository...'); + repoInitOperation = NodeGit.Repository.init(self._repo.path, 0); + + } + + return repoInitOperation; + + }).catch((err) => { + winston.error('Unable to open or clone Git repository!'); + winston.error(err); + }).then((repo) => { + + self._repo.inst = repo; + + winston.info('[GIT] Git repository is now ready.'); + }); + + }, + + /** + * Generate Clone Options object + * + * @param {Object} appconfig The application configuration + * @return {Object} CloneOptions object + */ + _generateCloneOptions(appconfig) { + + let cloneOptions = {}; + + cloneOptions.fetchOpts = { + callbacks: { + credentials: () => { + + let cred = null; + switch(appconfig.git.auth.type) { + case 'basic': + cred = NodeGit.Cred.userpassPlaintextNew( + appconfig.git.auth.user, + appconfig.git.auth.pass + ); + break; + case 'oauth': + cred = NodeGit.Cred.userpassPlaintextNew( + appconfig.git.auth.token, + "x-oauth-basic" + ); + break; + case 'ssh': + cred = NodeGit.Cred.sshKeyNew( + appconfig.git.auth.user, + appconfig.git.auth.publickey, + appconfig.git.auth.privatekey, + appconfig.git.auth.passphrase + ); + break; + default: + cred = NodeGit.Cred.defaultNew(); + break; + } + + return cred; + } + } + }; + + if(os.type() === 'Darwin') { + cloneOptions.fetchOpts.callbacks.certificateCheck = () => { return 1; }; // Bug in OS X, bypass certs check workaround + } + + return cloneOptions; + + } + +}; \ No newline at end of file diff --git a/server.js b/server.js index 35dc3a18..a25bffbb 100644 --- a/server.js +++ b/server.js @@ -9,13 +9,14 @@ // ---------------------------------------- global.winston = require('winston'); -winston.info('Requarks Wiki is initializing...'); +winston.info('[SERVER] Requarks Wiki is initializing...'); global.ROOTPATH = __dirname; var appconfig = require('./models/config')('./config.yml'); global.db = require('./models/mongodb')(appconfig); global.red = require('./models/redis')(appconfig); +global.git = require('./models/git').init(appconfig); var _ = require('lodash'); var express = require('express'); @@ -155,9 +156,9 @@ app.use(function(err, req, res, next) { // Start HTTP server // ---------------------------------------- -winston.info('Requarks Wiki has initialized successfully.'); +winston.info('[SERVER] Requarks Wiki has initialized successfully.'); -winston.info('Starting HTTP server on port ' + appconfig.port + '...'); +winston.info('[SERVER] Starting HTTP server on port ' + appconfig.port + '...'); app.set('port', appconfig.port); var server = http.createServer(app); @@ -183,5 +184,5 @@ server.on('error', (error) => { }); server.on('listening', () => { - winston.info('HTTP server started successfully! [RUNNING]'); + winston.info('[SERVER] HTTP server started successfully! [RUNNING]'); }); \ No newline at end of file diff --git a/views/pages/view.pug b/views/pages/view.pug index 9165aad0..98aff840 100644 --- a/views/pages/view.pug +++ b/views/pages/view.pug @@ -49,4 +49,6 @@ block content | Primary bold title h2.subtitle | Primary bold subtitle + .content + != contents