2019-06-04 03:52:01 +02:00
|
|
|
import _ from 'lodash'
|
2017-09-05 21:19:53 +08:00
|
|
|
|
2017-09-10 19:41:34 +08:00
|
|
|
import { logger } from '../../logger'
|
2016-03-28 13:17:31 +05:30
|
|
|
|
2017-09-14 20:53:36 +08:00
|
|
|
let commits = {}
|
|
|
|
let head = null
|
|
|
|
let branches = { 'master': head }
|
|
|
|
let curBranch = 'master'
|
|
|
|
let direction = 'LR'
|
|
|
|
let seq = 0
|
2016-03-27 11:00:44 +05:30
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
function getRandomInt (min, max) {
|
|
|
|
return Math.floor(Math.random() * (max - min)) + min
|
2016-03-29 20:55:22 +05:30
|
|
|
}
|
2016-04-28 11:27:24 +05:30
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
function getId () {
|
2017-09-14 20:53:36 +08:00
|
|
|
const pool = '0123456789abcdef'
|
|
|
|
let id = ''
|
|
|
|
for (let i = 0; i < 7; i++) {
|
2017-04-11 22:14:25 +08:00
|
|
|
id += pool[getRandomInt(0, 16)]
|
|
|
|
}
|
|
|
|
return id
|
2016-03-26 22:16:47 +05:30
|
|
|
}
|
2016-03-27 11:00:44 +05:30
|
|
|
|
2017-04-11 22:14:25 +08:00
|
|
|
function isfastforwardable (currentCommit, otherCommit) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id)
|
2017-04-13 20:16:38 +08:00
|
|
|
while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit) {
|
2017-04-16 23:48:36 +08:00
|
|
|
// only if other branch has more commits
|
2017-04-11 22:14:25 +08:00
|
|
|
if (otherCommit.parent == null) break
|
|
|
|
if (Array.isArray(otherCommit.parent)) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('In merge commit:', otherCommit.parent)
|
2017-04-11 22:14:25 +08:00
|
|
|
return isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) ||
|
2017-04-16 23:48:36 +08:00
|
|
|
isfastforwardable(currentCommit, commits[otherCommit.parent[1]])
|
2016-03-27 17:53:01 +05:30
|
|
|
} else {
|
2017-04-11 22:14:25 +08:00
|
|
|
otherCommit = commits[otherCommit.parent]
|
2016-03-27 16:13:07 +05:30
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug(currentCommit.id, otherCommit.id)
|
2017-04-13 20:16:38 +08:00
|
|
|
return currentCommit.id === otherCommit.id
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function isReachableFrom (currentCommit, otherCommit) {
|
2017-09-14 20:53:36 +08:00
|
|
|
const currentSeq = currentCommit.seq
|
|
|
|
const otherSeq = otherCommit.seq
|
2017-04-11 22:14:25 +08:00
|
|
|
if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const setDirection = function (dir) {
|
2017-04-11 22:14:25 +08:00
|
|
|
direction = dir
|
|
|
|
}
|
2017-09-14 20:53:36 +08:00
|
|
|
let options = {}
|
2017-09-10 21:23:04 +08:00
|
|
|
export const setOptions = function (rawOptString) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('options str', rawOptString)
|
2017-04-11 22:14:25 +08:00
|
|
|
rawOptString = rawOptString && rawOptString.trim()
|
|
|
|
rawOptString = rawOptString || '{}'
|
|
|
|
try {
|
|
|
|
options = JSON.parse(rawOptString)
|
|
|
|
} catch (e) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.error('error while parsing gitGraph options', e.message)
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const getOptions = function () {
|
2017-04-11 22:14:25 +08:00
|
|
|
return options
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const commit = function (msg) {
|
2017-09-14 20:53:36 +08:00
|
|
|
const commit = {
|
2017-04-16 23:48:36 +08:00
|
|
|
id: getId(),
|
2017-04-11 22:14:25 +08:00
|
|
|
message: msg,
|
|
|
|
seq: seq++,
|
2017-04-16 23:48:36 +08:00
|
|
|
parent: head == null ? null : head.id
|
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
head = commit
|
|
|
|
commits[commit.id] = commit
|
|
|
|
branches[curBranch] = commit.id
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('in pushCommit ' + commit.id)
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const branch = function (name) {
|
2017-04-11 22:14:25 +08:00
|
|
|
branches[name] = head != null ? head.id : null
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('in createBranch')
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const merge = function (otherBranch) {
|
2017-09-14 20:53:36 +08:00
|
|
|
const currentCommit = commits[branches[curBranch]]
|
|
|
|
const otherCommit = commits[branches[otherBranch]]
|
2017-04-11 22:14:25 +08:00
|
|
|
if (isReachableFrom(currentCommit, otherCommit)) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('Already merged')
|
2017-04-11 22:14:25 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if (isfastforwardable(currentCommit, otherCommit)) {
|
|
|
|
branches[curBranch] = branches[otherBranch]
|
|
|
|
head = commits[branches[curBranch]]
|
|
|
|
} else {
|
2017-04-16 23:48:36 +08:00
|
|
|
// create merge commit
|
2017-09-14 20:53:36 +08:00
|
|
|
const commit = {
|
2017-04-11 22:14:25 +08:00
|
|
|
id: getId(),
|
|
|
|
message: 'merged branch ' + otherBranch + ' into ' + curBranch,
|
|
|
|
seq: seq++,
|
|
|
|
parent: [head == null ? null : head.id, branches[otherBranch]]
|
2016-05-07 10:52:24 +05:30
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
head = commit
|
|
|
|
commits[commit.id] = commit
|
|
|
|
branches[curBranch] = commit.id
|
|
|
|
}
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug(branches)
|
|
|
|
logger.debug('in mergeBranch')
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const checkout = function (branch) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('in checkout')
|
2017-04-11 22:14:25 +08:00
|
|
|
curBranch = branch
|
2017-09-14 20:53:36 +08:00
|
|
|
const id = branches[curBranch]
|
2017-04-11 22:14:25 +08:00
|
|
|
head = commits[id]
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const reset = function (commitRef) {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug('in reset', commitRef)
|
2017-09-14 20:53:36 +08:00
|
|
|
const ref = commitRef.split(':')[0]
|
|
|
|
let parentCount = parseInt(commitRef.split(':')[1])
|
|
|
|
let commit = ref === 'HEAD' ? head : commits[branches[ref]]
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug(commit, parentCount)
|
2017-04-11 22:14:25 +08:00
|
|
|
while (parentCount > 0) {
|
|
|
|
commit = commits[commit.parent]
|
|
|
|
parentCount--
|
|
|
|
if (!commit) {
|
2017-09-14 20:53:36 +08:00
|
|
|
const err = 'Critical error - unique parent commit not found during reset'
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.error(err)
|
2017-04-11 22:14:25 +08:00
|
|
|
throw err
|
2016-03-28 13:18:11 +05:30
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
head = commit
|
|
|
|
branches[curBranch] = commit.id
|
|
|
|
}
|
|
|
|
|
|
|
|
function upsert (arr, key, newval) {
|
2017-04-19 20:17:57 +08:00
|
|
|
const index = arr.indexOf(key)
|
|
|
|
if (index === -1) {
|
2017-04-11 22:14:25 +08:00
|
|
|
arr.push(newval)
|
2017-04-19 20:17:57 +08:00
|
|
|
} else {
|
|
|
|
arr.splice(index, 1, newval)
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function prettyPrintCommitHistory (commitArr) {
|
2019-06-04 03:52:01 +02:00
|
|
|
const commit = _.maxBy(commitArr, 'seq')
|
2017-09-14 20:53:36 +08:00
|
|
|
let line = ''
|
2017-04-19 20:17:57 +08:00
|
|
|
commitArr.forEach(function (c) {
|
2017-04-13 20:16:38 +08:00
|
|
|
if (c === commit) {
|
2017-04-11 22:14:25 +08:00
|
|
|
line += '\t*'
|
2016-03-28 13:18:11 +05:30
|
|
|
} else {
|
2017-04-11 22:14:25 +08:00
|
|
|
line += '\t|'
|
2016-03-28 13:18:11 +05:30
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
})
|
2017-09-14 20:53:36 +08:00
|
|
|
const label = [line, commit.id, commit.seq]
|
2019-06-04 03:32:56 +02:00
|
|
|
for (let branch in branches) {
|
|
|
|
if (branches[branch] === commit.id) label.push(branch)
|
|
|
|
}
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug(label.join(' '))
|
2017-04-11 22:14:25 +08:00
|
|
|
if (Array.isArray(commit.parent)) {
|
2017-09-14 20:53:36 +08:00
|
|
|
const newCommit = commits[commit.parent[0]]
|
2017-04-11 22:14:25 +08:00
|
|
|
upsert(commitArr, commit, newCommit)
|
|
|
|
commitArr.push(commits[commit.parent[1]])
|
|
|
|
} else if (commit.parent == null) {
|
|
|
|
return
|
|
|
|
} else {
|
2017-09-14 20:53:36 +08:00
|
|
|
const nextCommit = commits[commit.parent]
|
2017-04-11 22:14:25 +08:00
|
|
|
upsert(commitArr, commit, nextCommit)
|
|
|
|
}
|
2019-06-04 03:52:01 +02:00
|
|
|
commitArr = _.uniqBy(commitArr, 'id')
|
2017-04-11 22:14:25 +08:00
|
|
|
prettyPrintCommitHistory(commitArr)
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const prettyPrint = function () {
|
2017-09-10 19:41:34 +08:00
|
|
|
logger.debug(commits)
|
2017-09-14 20:53:36 +08:00
|
|
|
const node = getCommitsArray()[0]
|
2017-04-11 22:14:25 +08:00
|
|
|
prettyPrintCommitHistory([node])
|
2016-03-27 23:02:31 +05:30
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const clear = function () {
|
2017-04-11 22:14:25 +08:00
|
|
|
commits = {}
|
|
|
|
head = null
|
|
|
|
branches = { 'master': head }
|
|
|
|
curBranch = 'master'
|
|
|
|
seq = 0
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const getBranchesAsObjArray = function () {
|
2019-06-04 03:32:56 +02:00
|
|
|
const branchArr = []
|
|
|
|
for (let branch in branches) {
|
|
|
|
branchArr.push({ name: branch, commit: commits[branches[branch]] })
|
|
|
|
}
|
2017-04-11 22:14:25 +08:00
|
|
|
return branchArr
|
|
|
|
}
|
|
|
|
|
2017-09-10 21:23:04 +08:00
|
|
|
export const getBranches = function () { return branches }
|
|
|
|
export const getCommits = function () { return commits }
|
|
|
|
export const getCommitsArray = function () {
|
2017-09-14 20:53:36 +08:00
|
|
|
const commitArr = Object.keys(commits).map(function (key) {
|
2017-04-11 22:14:25 +08:00
|
|
|
return commits[key]
|
|
|
|
})
|
2017-09-10 19:41:34 +08:00
|
|
|
commitArr.forEach(function (o) { logger.debug(o.id) })
|
2019-06-04 03:52:01 +02:00
|
|
|
return _.orderBy(commitArr, ['seq'], ['desc'])
|
2017-04-11 22:14:25 +08:00
|
|
|
}
|
2017-09-10 21:23:04 +08:00
|
|
|
export const getCurrentBranch = function () { return curBranch }
|
|
|
|
export const getDirection = function () { return direction }
|
|
|
|
export const getHead = function () { return head }
|
2017-09-10 21:51:48 +08:00
|
|
|
|
|
|
|
export default {
|
|
|
|
setDirection,
|
|
|
|
setOptions,
|
|
|
|
getOptions,
|
|
|
|
commit,
|
|
|
|
branch,
|
|
|
|
merge,
|
|
|
|
checkout,
|
|
|
|
reset,
|
|
|
|
prettyPrint,
|
|
|
|
clear,
|
|
|
|
getBranchesAsObjArray,
|
|
|
|
getBranches,
|
|
|
|
getCommits,
|
|
|
|
getCommitsArray,
|
|
|
|
getCurrentBranch,
|
|
|
|
getDirection,
|
|
|
|
getHead
|
|
|
|
}
|