Last active
March 31, 2019 10:39
-
-
Save varjmes/fcf88d69cffcaa5b8d4ed0cb877cb18f to your computer and use it in GitHub Desktop.
Creating the tree!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Blob { | |
constructor(data) { | |
this.data = data | |
} | |
type() { | |
return 'blob' | |
} | |
toString() { | |
return this.data | |
} | |
} | |
module.exports = Blob |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const crypto = require('crypto') | |
const fs = require('fs') | |
const path = require('path') | |
const zlib = require('zlib') | |
class Database { | |
constructor(pathname) { | |
this.pathname = pathname | |
this.tempChars = [ | |
...Array.from({ length: 26 }, (_, i) => | |
String.fromCharCode('A'.charCodeAt(0) + i) | |
), | |
...Array.from({ length: 26 }, (_, i) => | |
String.fromCharCode('a'.charCodeAt(0) + i) | |
), | |
...[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
] | |
} | |
hashIt(string) { | |
return crypto | |
.createHash('sha1') | |
.update(string, 'utf-8') | |
.digest('hex') | |
} | |
writeObject(oid, content) { | |
const dirPath = path.join(this.pathname, oid.slice(0, 2)) | |
const objectPath = path.join(dirPath, oid.slice(2, oid.length)) | |
const tempPath = path.join(this.pathname, this.generateTempName()) | |
const compressed = zlib.deflateSync(content) | |
fs.writeFileSync(tempPath, compressed, { flag: 'wx+' }) | |
if (!fs.existsSync(dirPath)) { | |
fs.mkdirSync(dirPath) | |
} | |
fs.renameSync(tempPath, objectPath) | |
} | |
generateTempName() { | |
const randomString = Array.from( | |
{ length: 6 }, | |
(_, i) => | |
this.tempChars[Math.floor(Math.random() * this.tempChars.length)] | |
).join('') | |
return `tmp_obj_${randomString}` | |
} | |
store(object) { | |
const string = object.toString() | |
const type = Buffer.from(object.type()) | |
const typeByte = Buffer.from(`${type} ${string.byteLength.toString()}\x00`) | |
const content = Buffer.concat([typeByte, string]) | |
object.oid = this.hashIt(content) | |
this.writeObject(object.oid, content) | |
} | |
} | |
module.exports = Database |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Entry { | |
constructor(name, oid) { | |
this.name = name | |
this.oid = oid | |
} | |
} | |
module.exports = Entry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Tree { | |
constructor(entries) { | |
this.entryFormat = 'A7Z*H40' | |
this.mode = '100644' | |
this.entries = entries | |
} | |
type() { | |
return 'tree' | |
} | |
toString() { | |
const entries = this.entries.sort((a, b) => { | |
return -(a.name < b.name) || +(a.name > b.name) | |
}) | |
const packed = entries.map(entry => { | |
let mode = Buffer.from(this.mode.replace(/^0/, '')) | |
let space = Buffer.from(' ') | |
let name = Buffer.from(entry.name, 'utf8') | |
let nullChar = Buffer.from([0]) | |
let oid = Buffer.from(entry.oid.match(/../g).map(n => parseInt(n, 16))) | |
return Buffer.concat([mode, space, name, nullChar, oid]) | |
}) | |
return Buffer.concat(packed) | |
} | |
} | |
module.exports = Tree |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
const path = require('path') | |
const Blob = require('./blob') | |
const Database = require('./database') | |
const Entry = require('./entry') | |
const Tree = require('./tree') | |
const Workspace = require('./workspace') | |
const directories = ['objects', 'refs'] | |
const command = process.argv[2] | |
switch (command) { | |
case 'init': { | |
const repoPath = process.argv[3] || '' | |
const gitPath = path.resolve(repoPath, '.git') | |
directories.map(dir => { | |
const dirPath = path.join(gitPath, dir) | |
fs.mkdirSync(dirPath, { recursive: true }) | |
}) | |
console.info(`Initialised empty vrs repository in ${gitPath}`) | |
process.exit(0) | |
} | |
case 'commit': { | |
const gitPath = path.resolve('.git') | |
const dbPath = path.join(gitPath, 'objects') | |
const workspace = new Workspace(process.cwd()) | |
const database = new Database(dbPath) | |
const entries = [] | |
workspace.listFiles().forEach(filePath => { | |
const data = workspace.readFile(filePath) | |
const blob = new Blob(data) | |
database.store(blob) | |
entries.push(new Entry(filePath, blob.oid)) | |
}) | |
const tree = new Tree(entries) | |
database.store(tree) | |
console.info(`tree: ${tree.oid}`) | |
process.exit(0) | |
} | |
default: | |
console.error(`vrs: '${command}' is not a valid vrs command`) | |
process.exit(1) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fs = require('fs') | |
const path = require('path') | |
class Workspace { | |
constructor(pathname) { | |
this.ignore = ['.', '..', '.git'] | |
this.pathname = pathname | |
} | |
listFiles() { | |
return fs | |
.readdirSync(this.pathname) | |
.filter(item => !this.ignore.includes(item)) | |
} | |
readFile(filePath) { | |
return fs.readFileSync(path.join(this.pathname, filePath)) | |
} | |
} | |
module.exports = Workspace |
My guess if the tree hashes aren't coming out right would be to double check this sort function:
const entries = this.entries.sort((a, b) => { return a.name - b.name })
I'm pretty sure that subtracting two strings results in NaN. In isomorphic-git I use this crazy function I found on stack overflow.
Good to know, I'm now using that, thanks!
I think my problem is encoding on the tree file.
blob file
~/projects/vrs
❯ cat .git/objects/16/213a7070f837cc149955ab811cbf2850169b88 | inflate
blob 160class Blob {
constructor(data) {
this.data = data
}
type() {
return 'blob'
}
toString() {
return this.data
}
}
module.exports = Blob
tree file
❯ cat .git/objects/3b/2504a6517df796a255a8acccf6e1cbee3b8915 | inflate
tree 219100644 blob.js!:pp�7��U���(P��100644 database.js(���}�3�d�ҋ�����100644 entry.js8�j����+�d�HFn
V�d�100644 tree.js;�ĮR���3l�j���?��
]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My guess if the tree hashes aren't coming out right would be to double check this sort function:
I'm pretty sure that subtracting two strings results in NaN. In isomorphic-git I use this crazy function I found on stack overflow.
https://github.com/isomorphic-git/isomorphic-git/blob/741013320582a6c80a70b23d691ae621df2e6c1a/src/utils/compareStrings.js