makit
Version:
Make in JavaScript done right!
102 lines (101 loc) • 3.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MTime = exports.MTIME_EMPTY_DEPENDENCY = exports.MTIME_NOT_EXIST = void 0;
const logger_1 = require("../utils/logger");
/**
* 获取单例日志对象
*/
const l = logger_1.Logger.getOrCreate();
/**
* 表示文件不存在,时间戳设为最旧。让它和它的依赖处于 stale 状态。
*/
exports.MTIME_NOT_EXIST = -2;
/*
* 表示依赖为空时,依赖的 mtime。要比所有存在的文件都旧,
* 但比不存在的文件要新(因为无依赖的不存在文件也需要生成)。
* 因此:
*
* MTIME_NOT_EXIST < MTIME_EMPTY_DEPENDENCY < mtimeNs < #now()
*/
exports.MTIME_EMPTY_DEPENDENCY = -1;
/**
* 文件 mtime 的抽象
*
* 由于文件系统时间和 Node.js 的 Date API 不一致,
* 会影响判断一个 target 是否 stale。
* GNU Make 的 recipe 是独立进程而 makit 中是本地过程调用因此问题严重。
* 一些实现细节:
*
* * mtime 使用正整数实现,特殊值取负数和 Infinity。
* * 按 makit 第一次获知文件的顺序初始化 mtime。
* * 同时提供 mtime 和严格递增的 now(),确保 now 和 mtime 一致。
*/
class MTime {
constructor(db, fs) {
this.db = db;
this.fs = fs;
}
/**
* 获取严格递增的当前时间戳
*
* @return 严格递增的当前时间戳
*/
now() {
const time = +this.db.query('meta', 'now', 0) + 1;
this.db.write('meta', 'now', time);
return time;
}
/**
* 设置文件修改时间,不传则设置为现在
*
* @param fullpath 文件全路径
* @param time 时间戳
*/
setModifiedTime(fullpath, time = this.now()) {
const mtimeMs = this.getModifiedTimeFromFileSystem(fullpath);
if (mtimeMs === exports.MTIME_NOT_EXIST)
return mtimeMs;
this.db.write('mtime', fullpath, { mtimeMs, time });
l.debug('TIME', logger_1.hlTarget(fullpath), `time set to`, time);
return time;
}
/**
* 获取文件修改时间
*
* @param fullpath 文件全路径
* @return 时间戳的 Promise
*/
getModifiedTime(fullpath) {
const mtimeMs = this.getModifiedTimeFromFileSystem(fullpath);
if (mtimeMs === exports.MTIME_NOT_EXIST)
return exports.MTIME_NOT_EXIST;
let entry = this.queryAndValidate(fullpath, mtimeMs);
if (!entry) {
entry = { mtimeMs, time: this.now() };
this.db.write('mtime', fullpath, entry);
}
return entry.time;
}
getModifiedTimeFromFileSystem(fullpath) {
try {
const { mtimeMs } = this.fs.statSync(fullpath);
return mtimeMs;
}
catch (error) {
if (error.code === 'ENOENT') {
return exports.MTIME_NOT_EXIST;
}
throw error;
}
}
/**
* 简单的校验,就可以不依赖数据库的并发一致性。
*/
queryAndValidate(fullpath, mtimeMs) {
const entry = this.db.query('mtime', fullpath);
if (!entry || entry.mtimeMs !== mtimeMs)
return null;
return entry;
}
}
exports.MTime = MTime;