|  | @@ -1,12 +1,13 @@
 | 
	
		
			
				|  |  |  "use strict";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -var NodeGit = require("nodegit"),
 | 
	
		
			
				|  |  | +var Git = require("git-wrapper2-promise"),
 | 
	
		
			
				|  |  |  	Promise = require('bluebird'),
 | 
	
		
			
				|  |  |  	path = require('path'),
 | 
	
		
			
				|  |  |  	os = require('os'),
 | 
	
		
			
				|  |  |  	fs = Promise.promisifyAll(require("fs")),
 | 
	
		
			
				|  |  |  	moment = require('moment'),
 | 
	
		
			
				|  |  | -	_ = require('lodash');
 | 
	
		
			
				|  |  | +	_ = require('lodash'),
 | 
	
		
			
				|  |  | +	URL = require('url');
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  |   * Git Model
 | 
	
	
		
			
				|  | @@ -14,11 +15,11 @@ var NodeGit = require("nodegit"),
 | 
	
		
			
				|  |  |  module.exports = {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	_git: null,
 | 
	
		
			
				|  |  | +	_url: '',
 | 
	
		
			
				|  |  |  	_repo: {
 | 
	
		
			
				|  |  |  		path: '',
 | 
	
		
			
				|  |  |  		branch: 'master',
 | 
	
		
			
				|  |  |  		exists: false,
 | 
	
		
			
				|  |  | -		inst: null,
 | 
	
		
			
				|  |  |  		sync: true
 | 
	
		
			
				|  |  |  	},
 | 
	
		
			
				|  |  |  	_signature: {
 | 
	
	
		
			
				|  | @@ -42,16 +43,15 @@ module.exports = {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		//-> Build repository path
 | 
	
		
			
				|  |  |  		
 | 
	
		
			
				|  |  | -		if(_.isEmpty(appconfig.git.path) || appconfig.git.path === 'auto') {
 | 
	
		
			
				|  |  | +		if(_.isEmpty(appconfig.datadir.repo)) {
 | 
	
		
			
				|  |  |  			self._repo.path = path.join(ROOTPATH, 'repo');
 | 
	
		
			
				|  |  |  		} else {
 | 
	
		
			
				|  |  | -			self._repo.path = appconfig.git.path;
 | 
	
		
			
				|  |  | +			self._repo.path = appconfig.datadir.repo;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		//-> Initialize repository
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		self._initRepo(appconfig).then((repo) => {
 | 
	
		
			
				|  |  | -			self._repo.inst = repo;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  			if(self._repo.sync) {
 | 
	
		
			
				|  |  |  				self.resync();
 | 
	
	
		
			
				|  | @@ -61,8 +61,8 @@ module.exports = {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		// Define signature
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		self._signature.name = appconfig.git.userinfo.name || 'Wiki';
 | 
	
		
			
				|  |  | -		self._signature.email = appconfig.git.userinfo.email || 'user@example.com';
 | 
	
		
			
				|  |  | +		self._signature.name = appconfig.git.signature.name || 'Wiki';
 | 
	
		
			
				|  |  | +		self._signature.email = appconfig.git.signature.email || 'user@example.com';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		return self;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -78,7 +78,7 @@ module.exports = {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		let self = this;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		winston.info('[GIT] Initializing Git repository...');
 | 
	
		
			
				|  |  | +		winston.info('[GIT] Checking Git repository...');
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		//-> Check if path is accessible
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -88,209 +88,94 @@ module.exports = {
 | 
	
		
			
				|  |  |  			}
 | 
	
		
			
				|  |  |  		}).then(() => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +			self._git = new Git({ 'git-dir': self._repo.path });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  			//-> 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();
 | 
	
		
			
				|  |  | +			return self._git.isRepo().then((isRepo) => {
 | 
	
		
			
				|  |  | +				self._repo.exists = isRepo;
 | 
	
		
			
				|  |  | +				return (!isRepo) ? self._git.exec('init') : true;
 | 
	
		
			
				|  |  |  			}).catch((err) => {
 | 
	
		
			
				|  |  |  				self._repo.exists = false;
 | 
	
		
			
				|  |  |  			});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		}).then(() => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			//-> Init repository
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			let repoInitOperation = null;
 | 
	
		
			
				|  |  | -			self._repo.branch = appconfig.git.branch;
 | 
	
		
			
				|  |  | -			self._repo.sync = appconfig.git.remote;
 | 
	
		
			
				|  |  | -			self._opts.clone = self._generateCloneOptions(appconfig);
 | 
	
		
			
				|  |  | -			self._opts.push = self._generatePushOptions(appconfig);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			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...');
 | 
	
		
			
				|  |  | -				repoInitOperation = NodeGit.Clone(appconfig.git.url, self._repo.path, self._opts.clone);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			} else {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				winston.info('[GIT] Using offline local repository...');
 | 
	
		
			
				|  |  | -				repoInitOperation = NodeGit.Repository.init(self._repo.path, 0);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return repoInitOperation;
 | 
	
		
			
				|  |  | +			// Initialize remote
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			let urlObj = URL.parse(appconfig.git.url);
 | 
	
		
			
				|  |  | +			urlObj.auth = appconfig.git.auth.username + ((appconfig.git.auth.type !== 'ssh') ? ':' + appconfig.git.auth.password : '');
 | 
	
		
			
				|  |  | +			self._url = URL.format(urlObj);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			return self._git.exec('remote', 'show').then((cProc) => {
 | 
	
		
			
				|  |  | +				let out = cProc.stdout.toString();
 | 
	
		
			
				|  |  | +				if(_.includes(out, 'origin')) {
 | 
	
		
			
				|  |  | +					return true;
 | 
	
		
			
				|  |  | +				} else {
 | 
	
		
			
				|  |  | +					return Promise.join(
 | 
	
		
			
				|  |  | +						self._git.exec('config', ['--local', 'user.name', self._signature.name]),
 | 
	
		
			
				|  |  | +						self._git.exec('config', ['--local', 'user.email', self._signature.email])
 | 
	
		
			
				|  |  | +					).then(() => {
 | 
	
		
			
				|  |  | +						return self._git.exec('remote', ['add', 'origin', self._url]);
 | 
	
		
			
				|  |  | +					})
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +			});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		}).catch((err) => {
 | 
	
		
			
				|  |  | -			winston.error('Unable to open or clone Git repository!');
 | 
	
		
			
				|  |  | -			winston.error(err);
 | 
	
		
			
				|  |  | -		}).then((repo) => {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			if(self._repo.sync) {
 | 
	
		
			
				|  |  | -				NodeGit.Remote.setPushurl(repo, 'origin', appconfig.git.url);
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			return repo;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +			winston.error('Git remote error!');
 | 
	
		
			
				|  |  | +			throw err;
 | 
	
		
			
				|  |  | +		}).then(() => {
 | 
	
		
			
				|  |  |  			winston.info('[GIT] Git repository is now ready.');
 | 
	
		
			
				|  |  | +			return true;
 | 
	
		
			
				|  |  |  		});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	},
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -	/**
 | 
	
		
			
				|  |  | -	 * Generate Clone Options object
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 * @param      {Object}  appconfig  The application configuration
 | 
	
		
			
				|  |  | -	 * @return     {Object}  CloneOptions object
 | 
	
		
			
				|  |  | -	 */
 | 
	
		
			
				|  |  | -	_generateCloneOptions(appconfig) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		let cloneOptions = new NodeGit.CloneOptions();
 | 
	
		
			
				|  |  | -		cloneOptions.fetchOpts = this._generateFetchOptions(appconfig);
 | 
	
		
			
				|  |  | -		return cloneOptions;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	},
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	_generateFetchOptions(appconfig) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		let fetchOptions = new NodeGit.FetchOptions();
 | 
	
		
			
				|  |  | -		fetchOptions.callbacks = this._generateRemoteCallbacks(appconfig);
 | 
	
		
			
				|  |  | -		return fetchOptions;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	},
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	_generatePushOptions(appconfig) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		let pushOptions = new NodeGit.PushOptions();
 | 
	
		
			
				|  |  | -		pushOptions.callbacks = this._generateRemoteCallbacks(appconfig);
 | 
	
		
			
				|  |  | -		return pushOptions;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	},
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	_generateRemoteCallbacks(appconfig) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		let remoteCallbacks = new NodeGit.RemoteCallbacks();
 | 
	
		
			
				|  |  | -		let credFunc = this._generateCredentials(appconfig);
 | 
	
		
			
				|  |  | -		remoteCallbacks.credentials = () => { return credFunc; };
 | 
	
		
			
				|  |  | -		remoteCallbacks.transferProgress = _.noop;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if(os.type() === 'Darwin') {
 | 
	
		
			
				|  |  | -			remoteCallbacks.certificateCheck = () => { return 1; }; // Bug in OS X, bypass certs check workaround
 | 
	
		
			
				|  |  | -		} else {
 | 
	
		
			
				|  |  | -			remoteCallbacks.certificateCheck = _.noop;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		return remoteCallbacks;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	},
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	_generateCredentials(appconfig) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		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;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	},
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  	resync() {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		let self = this;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		// Fetch
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -		return self._repo.inst.fetch('origin', self._opts.clone.fetchOpts)
 | 
	
		
			
				|  |  | -		.catch((err) => {
 | 
	
		
			
				|  |  | -			winston.error('Unable to fetch from git origin!' + err);
 | 
	
		
			
				|  |  | -		})
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// Merge
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		.then(() => {
 | 
	
		
			
				|  |  | -			return self._repo.inst.mergeBranches(self._repo.branch, 'origin/' + self._repo.branch);
 | 
	
		
			
				|  |  | +		winston.info('[GIT] Performing pull from remote repository...');
 | 
	
		
			
				|  |  | +		return self._git.pull('origin', self._repo.branch).then((cProc) => {
 | 
	
		
			
				|  |  | +			winston.info('[GIT] Pull completed.');
 | 
	
		
			
				|  |  |  		})
 | 
	
		
			
				|  |  |  		.catch((err) => {
 | 
	
		
			
				|  |  | -			winston.error('Unable to merge from remote head!' + err);
 | 
	
		
			
				|  |  | +			winston.error('Unable to fetch from git origin!');
 | 
	
		
			
				|  |  | +			throw err;
 | 
	
		
			
				|  |  |  		})
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		// Push
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  		.then(() => {
 | 
	
		
			
				|  |  | -			return self._repo.inst.getRemote('origin').then((remote) => {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				// Get modified files
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				return self._repo.inst.refreshIndex().then((index) => {
 | 
	
		
			
				|  |  | -					return self._repo.inst.getStatus().then(function(arrayStatusFile) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						let addOp = [];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						// Add to next commit
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						_.forEach(arrayStatusFile, (v) => {
 | 
	
		
			
				|  |  | -							addOp.push(arrayStatusFile[0].path());
 | 
	
		
			
				|  |  | -						});
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						console.log('DUDE1');
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						// Create Commit
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -						let sig = NodeGit.Signature.create(self._signature.name, self._signature.email, moment().utc().unix(),  0);
 | 
	
		
			
				|  |  | -						return self._repo.inst.createCommitOnHead(addOp, sig, sig, "Wiki Sync").then(() => {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -							console.log('DUDE2');
 | 
	
		
			
				|  |  | +			// Check for changes
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -							return remote.connect(NodeGit.Enums.DIRECTION.PUSH, self._opts.push.callbacks).then(() => {
 | 
	
		
			
				|  |  | +			return self._git.exec('status').then((cProc) => {
 | 
	
		
			
				|  |  | +				let out = cProc.stdout.toString();
 | 
	
		
			
				|  |  | +				if(!_.includes(out, 'nothing to commit')) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -								console.log('DUDE3');
 | 
	
		
			
				|  |  | +					// Add, commit and push
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -								// Push to remote
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -								return remote.push( ["refs/heads/master:refs/heads/master"], self._opts.push).then((errNum) => {
 | 
	
		
			
				|  |  | -									console.log('DUDE' + errNum);
 | 
	
		
			
				|  |  | -								}).catch((err) => {
 | 
	
		
			
				|  |  | -									console.log(err);
 | 
	
		
			
				|  |  | -								});
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -							});
 | 
	
		
			
				|  |  | +					winston.info('[GIT] Performing push to remote repository...');
 | 
	
		
			
				|  |  | +					return self._git.add('-A').then(() => {
 | 
	
		
			
				|  |  | +				    return self._git.commit("Resync");
 | 
	
		
			
				|  |  | +				  }).then(() => {
 | 
	
		
			
				|  |  | +				    return self._git.push('origin', self._repo.branch);
 | 
	
		
			
				|  |  | +				  }).then(() => {
 | 
	
		
			
				|  |  | +						return winston.info('[GIT] Push completed.');
 | 
	
		
			
				|  |  | +					});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -						});
 | 
	
		
			
				|  |  | +				} else {
 | 
	
		
			
				|  |  | +					winston.info('[GIT] Repository is already up to date. Nothing to commit.');
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -					});
 | 
	
		
			
				|  |  | -				})
 | 
	
		
			
				|  |  | +				return true;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				/**/
 | 
	
		
			
				|  |  |  			});
 | 
	
		
			
				|  |  | -		}).catch((err) => {
 | 
	
		
			
				|  |  | -			winston.error('Unable to push to git origin!' + err);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +		})
 | 
	
		
			
				|  |  | +		.catch((err) => {
 | 
	
		
			
				|  |  | +			winston.error('Unable to push changes to remote!');
 | 
	
		
			
				|  |  | +			throw err;
 | 
	
		
			
				|  |  |  		});
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	}
 |