sourcecontrol
Version:
A modern TypeScript CLI application for source control
144 lines • 5.12 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitIndex = void 0;
const index_entry_1 = require("./index-entry");
const utils_1 = require("../../utils");
const crypto_1 = require("crypto");
const exceptions_1 = require("../exceptions");
class GitIndex {
constructor(version = GitIndex.VERSION, entries = []) {
this.version = version;
this.entries = entries;
this.sortEntries();
}
static async read(indexPath) {
if (!(await utils_1.FileUtils.exists(indexPath))) {
return new GitIndex();
}
const data = await utils_1.FileUtils.readFile(indexPath);
return GitIndex.deserialize(new Uint8Array(data));
}
async write(indexPath) {
const data = this.serialize();
await utils_1.FileUtils.createFile(indexPath, data);
}
entryNames() {
return this.entries.map((e) => e.filePath);
}
removeEntry(path) {
this.entries = this.entries.filter((e) => e.filePath !== path);
}
hasEntry(path) {
return this.entries.some((e) => e.filePath === path);
}
add(entry) {
this.entries.push(entry);
}
getEntry(path) {
return this.entries.find((e) => e.filePath === path);
}
clear() {
this.entries = [];
}
serialize() {
const entriesSize = this.entries.reduce((sum, entry) => {
const entryData = entry.serialize();
return sum + entryData.length;
}, 0);
const totalSize = GitIndex.HEADER_SIZE + entriesSize + GitIndex.CHECKSUM_SIZE;
const buffer = new Uint8Array(totalSize);
const view = new DataView(buffer.buffer);
let offset = 0;
buffer[offset++] = 0x44;
buffer[offset++] = 0x49;
buffer[offset++] = 0x52;
buffer[offset++] = 0x43;
view.setUint32(offset, this.version, false);
offset += 4;
view.setUint32(offset, this.entries.length, false);
offset += 4;
this.entries.forEach((entry) => {
const entryData = entry.serialize();
buffer.set(entryData, offset);
offset += entryData.length;
});
const contentHash = buffer.slice(0, offset);
const checksum = (0, crypto_1.createHash)('sha1').update(contentHash).digest();
buffer.set(checksum, offset);
return buffer;
}
static deserialize(data) {
const view = new DataView(data.buffer, data.byteOffset);
let offset = 0;
const validateSignature = () => {
const signature = new TextDecoder().decode(data.slice(0, 4));
if (signature !== GitIndex.SIGNATURE) {
throw new exceptions_1.ObjectException(`Invalid index signature: ${signature}`);
}
offset += 4;
};
const validateVersion = () => {
const version = view.getUint32(offset, false);
offset += 4;
if (version !== GitIndex.VERSION) {
throw new exceptions_1.ObjectException(`Unsupported index version: ${version}`);
}
};
const readEntries = () => {
const entryCount = view.getUint32(offset, false);
offset += 4;
const entries = [];
for (let i = 0; i < entryCount; i++) {
const { entry, nextOffset } = index_entry_1.IndexEntry.deserialize(data, offset);
entries.push(entry);
offset = nextOffset;
}
return entries;
};
const validateChecksum = () => {
const contentSize = data.length - GitIndex.CHECKSUM_SIZE;
const content = data.slice(0, contentSize);
const expectedChecksum = data.slice(contentSize);
const actualChecksum = (0, crypto_1.createHash)('sha1').update(content).digest();
if (!GitIndex.compareChecksums(expectedChecksum, actualChecksum)) {
throw new exceptions_1.ObjectException('Index checksum mismatch');
}
};
validateSignature();
validateVersion();
const entries = readEntries();
validateChecksum();
return new GitIndex(GitIndex.VERSION, entries);
}
isEntryModified(entry, stats) {
if (entry.fileSize !== stats.size) {
return true;
}
const mtimeSeconds = Math.floor(stats.mtimeMs / 1000);
if (entry.modificationTime.seconds !== mtimeSeconds) {
return true;
}
if (entry.assumeValid) {
return false;
}
return false;
}
static compareChecksums(a, b) {
if (a.length !== b.length)
return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i])
return false;
}
return true;
}
sortEntries() {
this.entries.sort((a, b) => a.compareTo(b));
}
}
exports.GitIndex = GitIndex;
GitIndex.SIGNATURE = 'DIRC';
GitIndex.VERSION = 2;
GitIndex.HEADER_SIZE = 12;
GitIndex.CHECKSUM_SIZE = 20;
//# sourceMappingURL=git-index.js.map
;