I’m stuck on Stage 5.
I’ve tried to use process.cwd() to get correct path. I am calling writeTreeObject(process.cwd()). Everything seems fine but it is saying “Git object file doesn’t match official Git implementation. Diff after zlib decompression”:
Here are my logs:
remote: [your_program] b3d30995c2638c42354040fb1384cad77c2e638d
remote: [tester::#FE4] Found git object file written at .git/objects/b3/d30995c2638c42354040fb1384cad77c2e638d.
remote: [tester::#FE4] Git object file doesn't match official Git implementation. Diff after zlib decompression:
remote: [tester::#FE4]
remote: [tester::#FE4] Expected (bytes 0-100), hexadecimal: | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 31 30 31 00 31 30 30 36 34 34 20 68 6f 72 73 | tree 101.100644 hors
remote: [tester::#FE4] 65 79 00 99 72 15 fe 2f 05 08 88 d0 96 ff 68 6a 47 d5 be a6 | ey..r../......hjG...
remote: [tester::#FE4] 18 3e 69 34 30 30 30 30 20 68 75 6d 70 74 79 00 f8 72 16 d6 | .>i40000 humpty..r..
remote: [tester::#FE4] 49 7e b0 29 b0 a8 69 09 e8 6c 0a 25 22 6b 3e f0 34 30 30 30 | I~.)..i..l.%"k>.4000
remote: [tester::#FE4] 30 20 76 61 6e 69 6c 6c 61 00 6e 41 88 88 4d 92 98 e9 11 54 | 0 vanilla.nA..M....T
remote: [tester::#FE4]
remote: [tester::#FE4] Actual (bytes 0-100), hexadecimal: | ASCII:
remote: [tester::#FE4] 74 72 65 65 20 31 30 33 00 31 30 30 36 34 34 20 68 6f 72 73 | tree 103.100644 hors
remote: [tester::#FE4] 65 79 00 99 72 15 fe 2f 05 08 88 d0 96 ff 68 6a 47 d5 be a6 | ey..r../......hjG...
remote: [tester::#FE4] 18 3e 69 30 34 30 37 35 35 20 68 75 6d 70 74 79 00 f8 72 16 | .>i040755 humpty..r.
remote: [tester::#FE4] d6 49 7e b0 29 b0 a8 69 09 e8 6c 0a 25 22 6b 3e f0 30 34 30 | .I~.)..i..l.%"k>.040
remote: [tester::#FE4] 37 35 35 20 76 61 6e 69 6c 6c 61 00 6e 41 88 88 4d 92 98 e9 | 755 vanilla.nA..M...
remote: [tester::#FE4]
remote: [tester::#FE4] Git object file doesn't match official Git implementation
remote: [tester::#FE4] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)
And here’s a snippet of my code:
async writeTreeObject(root: string): Promise<string> {
const files = fs.readdirSync(path.resolve(root))
.sort((a, b) => a.localeCompare(b));
// console.log(files);
let contentToWrite = Buffer.alloc(0);
for(let file of files) {
if(file === GitPath.Git) {
continue;
}
let shaHash: string = "";
const resolvedPath = path.join(root, file);
const stat = fs.lstatSync(resolvedPath);
if(stat.isDirectory()) {
// console.log(`${file} is a directory.`);
shaHash = await this.writeTreeObject(resolvedPath);
} else if(stat.isFile()) {
// console.log(`${file} is a file.`);
shaHash = await this.writeBlobObject(resolvedPath);
}
contentToWrite = Buffer.concat([contentToWrite,
Buffer.from(`${this.#getFileMode(resolvedPath)} ${file}\0`),
Buffer.from(shaHash, 'hex')]);
}
let dataToWrite = Buffer.concat([Buffer.from(`tree ${contentToWrite.length}\0`), contentToWrite]);
// console.log(dataToWrite);
return await this.#writeData(dataToWrite);
}
/**
* Writes the blob object to the file system.
* @param data The data to write.
*/
async writeBlobObject(file: string): Promise<string> {
let data = fs.readFileSync(file);
let dataToWrite = Buffer.concat([Buffer.from(`blob ${data.length}\0`), data]);
return await this.#writeData(dataToWrite);
}
#getFileMode(path: string): string {
const fileMode = fs.statSync(path).mode
// console.log(fileMode);
const fileType = +(fileMode & 0o170000).toString(8)
const permissions = +(fileMode & 0o777).toString(8)
const mode = fileType + permissions
// console.log(mode.toString().padStart(6, '0'));
return mode.toString().padStart(6, '0')
}
#writeData(data: Buffer): Promise<string> {
let shaDigest = this.#calculateShaDigest(data);
let pathToFileURL = this.#createPathFrom(shaDigest);
let stream = Readable.from(data);
return new Promise((resolve, reject) => {
stream.pipe(
zlib.createDeflate()
).pipe(
fs.createWriteStream(pathToFileURL)
).on('finish', () => {
resolve(shaDigest);
}).on('error', (error: Error) => {
reject(error);
});
});
}
#calculateShaDigest(data: Buffer): string {
let shaDigest = require('crypto').createHash('sha1');
shaDigest.update(data);
return shaDigest.digest('hex');
}
#createPathFrom(shaDigest: string): string {
let objectPath = path.join(GitPath.Objects, shaDigest.slice(0, 2));
if (!fs.existsSync(objectPath)) {
fs.mkdirSync(objectPath, { recursive: true });
}
let pathToFileURL = path.join(objectPath, shaDigest.slice(2));
if(!fs.existsSync(pathToFileURL)) {
fs.openSync(pathToFileURL, 'w+');
}
// console.log(pathToFileURL);
return pathToFileURL;
}