rigjs
Version:
A multi-repos dev tool based on yarn and git.Rigjs is intended to be the simplest way to develop,share and deliver codes between different developers or different projects.
205 lines (187 loc) • 5.77 kB
text/typescript
import {Dep} from '@/classes/dependencies/Dep';
import fsHelper from '@/utils/fsHelper';
import objectHelper from '@/utils/objectHelper';
import print from '@/print';
import shell from 'shelljs';
import semver from 'semver';
import compareVersions from 'compare-versions'
import os from "os";
const JSON5 = require('json5');
interface RigConfigJSON5 {
dependencies: { [name: string]: Dep; };
share:{ [name: string]: string | string[]; };
}
class RigConfig {
dependencies: { [name: string]: Dep; } = {};
isLegacy = false;
share: { [name: string]: string | string[]; } = {};
constructor(rigConfig: RigConfigJSON5 | Dep[]) {
if (Array.isArray(rigConfig)) {
//旧版配置
this.isLegacy = true;
const depArrLegacy = rigConfig as Dep[];
for (let depLegacy of depArrLegacy) {
const dep = new Dep(depLegacy);
this.dependencies[dep.name] = dep;
}
} else {
for (let rigName in rigConfig.dependencies) {
this.dependencies[rigName] = new Dep({...rigConfig.dependencies[rigName], name: rigName})
}
this.share = rigConfig.share;
}
}
/**
* createFromCWD 从当前工作目录创建config对象
* @returns {RigConfig}
*/
static createFromCWD() {
const configJSON5 = fsHelper.readConfig();
return new RigConfig(configJSON5);
}
/**
* createFromPath 从absolute path中创建config对象
* @param {string} path
* @returns {RigConfig}
*/
static createFromPath(path: string) {
const configJSON5 = fsHelper.readConfig(path);
return new RigConfig(configJSON5);
}
validate() {
print.info(`rig validating rig-dependencies...`);
for (let key in this.dependencies) {
const ret = this.dependencies[key].validate();
if (!ret) {
throw new Error(`rig validating:${this.dependencies[key]} is invalid`);
}
}
}
/**
* 检查依赖的之间的依赖(仅包含rig管理下的依赖)
*
*/
validateDeps() {
print.info(`rig validating dependencies' requirements`);
let valid = true;
for (let rigName in this.dependencies) {
const rigDep = this.dependencies[rigName];
let pkgStr: string;
try {
if (rigDep.dev) {
// pkgStr = fsHelper.readPkgStrInRepo(rigName);
print.info(`${rigName} is in deleloping.Skip Validating.`);
continue;
} else {
let cmd = `git fetch ${rigDep.source} refs/tags/${rigDep.version} && git show FETCH_HEAD:package.json`;
if (os.platform() === 'win32') {
print.info(`skip on windows`);
return;
// cmd = `echo (git fetch ${rigDep.source} refs/tags/${rigDep.version}) -and (git show FETCH_HEAD:package.json)`;
}
print.info(`validateDeps:${cmd}`);
let showPackageProcess = shell.exec(cmd,
{silent: true}
);
pkgStr = showPackageProcess.stdout.trim();
}
pkgStr = pkgStr.replace('-and', '');
console.log(pkgStr)
const pkg = JSON.parse(pkgStr);
console.log(pkg);
//获取rig依赖
if (pkg.rig) {
const pkgRig = pkg.rig;
//遍历rig依赖
Object.keys(pkgRig).forEach(key => {
//获取该rig依赖的要求的版本范围
let max = '';
let min = '';
if (Array.isArray(pkgRig[key])) {
//使用数组的情况
if (pkgRig[key].length == 0) {
//依赖该库,但是无版本要求
} else if (pkgRig[key].length == 1) {
min = semver.valid(pkgRig[key][0]) || '';
} else if (pkgRig[key].length == 2) {
min = semver.valid(pkgRig[key][0]) || '';
max = semver.valid(pkgRig[key][1]) || '';
} else {
print.error(`invalid array ${JSON.stringify([key])}`);
valid = false;
}
} else {
//使用字典的情况
min = pkgRig[key]['min'] || '';
max = pkgRig[key]['max'] || '';
}
//从rigJson5获取该依赖的版本号
const dep = this.dependencies[key]
print.info(`checking requirements of ${rigName}: ${key}[${min},${max}]`);
if (dep) {
if (dep.dev) {
valid = true;
} else {
if (min) {
if (!dep.version) throw new Error(`${dep.name}'s version is invalid:${dep.version}`)
valid = compareVersions(dep.version, min) >= 0;
}
if (max) {
if (!dep.version) throw new Error(`${dep.name}'s version is invalid:${dep.version}`)
valid = compareVersions(dep.version, max) <= 0
}
if (!valid) {
throw new Error(`${rigName} requires ${key}[${min},${max}],but ${key} is ${dep.version}!`);
}
}
} else {
print.error(`${key}[${min},${max}] is required`);
valid = false;
}
})
}
} catch (e) {
// @ts-ignore
throw new Error(`rig validateDeps:${rigDep.source} failed:${e.message},${pkgStr}`);
}
}
}
toString() {
return JSON5.stringify(this, null, 2);
}
overwrite(overwritePath: string = '') {
overwritePath ? fsHelper.writeConfig(this, overwritePath) :
fsHelper.writeConfig({
dependencies: this.dependencies
});
}
checkDepExists(name: string) {
return Object.keys(this.dependencies).find((key) => {
return name === key;
}) == name;
}
setDependencyToDev(name: string) {
this.setDependenciesToDev(name);
}
setDependenciesToDev(names: string | string[]) {
let nameArr = [];
if (Array.isArray(names)) {
nameArr.push(...names);
} else {
nameArr.push(names);
}
nameArr.forEach(name => {
this.dependencies[name].dev = true;
this.dependencies[name] = objectHelper.sortKeys(this.dependencies[name]);
});
}
findOrUpsertDep(name: string, dep: Dep) {
if (this.checkDepExists(name)) {
this.dependencies[name].dev = true;
} else {
this.dependencies[name] = dep;
}
this.dependencies[name] = objectHelper.sortKeys(this.dependencies[name]);
}
}
export default RigConfig;