235 lines
7.2 KiB
TypeScript
235 lines
7.2 KiB
TypeScript
import * as plugins from './meta.plugins.js';
|
|
import * as paths from '../paths.js';
|
|
import * as interfaces from './meta.interfaces.js';
|
|
|
|
import { logger } from '../gitzone.logging.js';
|
|
|
|
export class Meta {
|
|
public cwd: string;
|
|
public dirName: string;
|
|
public filePaths: {
|
|
metaJson: string;
|
|
gitIgnore: string;
|
|
packageJson: string;
|
|
};
|
|
|
|
constructor(cwdArg: string) {
|
|
this.cwd = cwdArg;
|
|
this.dirName = plugins.path.basename(this.cwd);
|
|
this.filePaths = {
|
|
metaJson: plugins.path.join(this.cwd, './.meta.json'),
|
|
gitIgnore: plugins.path.join(this.cwd, './.gitignore'),
|
|
packageJson: plugins.path.join(this.cwd, './package.json'),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* the meta repo data
|
|
*/
|
|
public metaRepoData: interfaces.IMetaRepoData;
|
|
public smartshellInstance = new plugins.smartshell.Smartshell({
|
|
executor: 'bash',
|
|
});
|
|
|
|
/**
|
|
* sorts the metaRepoData
|
|
*/
|
|
public async sortMetaRepoData() {
|
|
const stringifiedMetadata = plugins.smartjson.stringify(this.metaRepoData, []);
|
|
this.metaRepoData = plugins.smartjson.parse(stringifiedMetadata);
|
|
}
|
|
|
|
/**
|
|
* reads the meta file from disk
|
|
*/
|
|
public async readDirectory() {
|
|
await this.syncToRemote(true);
|
|
logger.log('info', `reading directory`);
|
|
const metaFileExists = plugins.smartfile.fs.fileExistsSync(this.filePaths.metaJson);
|
|
if (!metaFileExists) {
|
|
throw new Error(`meta file does not exist at ${this.filePaths.metaJson}`);
|
|
}
|
|
this.metaRepoData = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson);
|
|
}
|
|
|
|
/**
|
|
* generates the gitignore file and stores it on disk
|
|
*/
|
|
public async generateGitignore(): Promise<string> {
|
|
await this.sortMetaRepoData();
|
|
let gitignoreString = `# ignored repo directories\n`;
|
|
gitignoreString += `.nogit/\n`;
|
|
gitignoreString += `.pnpm-store/\n`;
|
|
for (const key of Object.keys(this.metaRepoData.projects)) {
|
|
gitignoreString = `${gitignoreString}${key}\n`;
|
|
}
|
|
return gitignoreString;
|
|
}
|
|
|
|
/**
|
|
* write to disk
|
|
*/
|
|
public async writeToDisk() {
|
|
// write .meta.json to disk
|
|
plugins.smartfile.memory.toFsSync(
|
|
JSON.stringify(this.metaRepoData, null, 2),
|
|
this.filePaths.metaJson,
|
|
);
|
|
// write .gitignore to disk
|
|
plugins.smartfile.memory.toFsSync(await this.generateGitignore(), this.filePaths.gitIgnore);
|
|
}
|
|
|
|
/**
|
|
* push to remote
|
|
*/
|
|
public async syncToRemote(gitCleanArg = false) {
|
|
logger.log('info', `syncing from origin master`);
|
|
await this.smartshellInstance.exec(`cd ${this.cwd} && git pull origin master`);
|
|
if (gitCleanArg) {
|
|
logger.log('info', `cleaning the repository from old directories`);
|
|
await this.smartshellInstance.exec(`cd ${this.cwd} && git clean -fd`);
|
|
}
|
|
logger.log('info', `syncing to remote origin master`);
|
|
await this.smartshellInstance.exec(`cd ${this.cwd} && git push origin master`);
|
|
}
|
|
|
|
/**
|
|
* update the locally cloned repositories
|
|
*/
|
|
public async updateLocalRepos() {
|
|
await this.syncToRemote();
|
|
const projects = plugins.smartfile.fs.toObjectSync(this.filePaths.metaJson).projects;
|
|
const preExistingFolders = plugins.smartfile.fs.listFoldersSync(this.cwd);
|
|
for (const preExistingFolderArg of preExistingFolders) {
|
|
if (
|
|
preExistingFolderArg !== '.git' &&
|
|
!Object.keys(projects).find((projectFolder) =>
|
|
projectFolder.startsWith(preExistingFolderArg),
|
|
)
|
|
) {
|
|
const response = await plugins.smartinteraction.SmartInteract.getCliConfirmation(
|
|
`Do you want to delete superfluous directory >>${preExistingFolderArg}<< ?`,
|
|
true,
|
|
);
|
|
if (response) {
|
|
logger.log('warn', `Deleting >>${preExistingFolderArg}<<!`);
|
|
} else {
|
|
logger.log('warn', `Not deleting ${preExistingFolderArg} by request!`);
|
|
}
|
|
}
|
|
}
|
|
|
|
await this.readDirectory();
|
|
await this.sortMetaRepoData();
|
|
const missingRepos: string[] = [];
|
|
for (const key of Object.keys(this.metaRepoData.projects)) {
|
|
plugins.smartfile.fs.isDirectory(key)
|
|
? logger.log('ok', `${key} -> is already cloned`)
|
|
: missingRepos.push(key);
|
|
}
|
|
|
|
logger.log('info', `found ${missingRepos.length} missing repos`);
|
|
for (const missingRepo of missingRepos) {
|
|
await this.smartshellInstance.exec(
|
|
`cd ${this.cwd} && git clone ${this.metaRepoData.projects[missingRepo]} ${missingRepo}`,
|
|
);
|
|
}
|
|
|
|
logger.log('info', `write changes to disk`);
|
|
await this.writeToDisk();
|
|
|
|
logger.log('info', `persist changes with a git commit`);
|
|
await this.smartshellInstance.exec(
|
|
`cd ${this.cwd} && git add -A && git commit -m "updated structure"`,
|
|
);
|
|
await this.syncToRemote();
|
|
|
|
// go recursive
|
|
const folders = await plugins.smartfile.fs.listFolders(this.cwd);
|
|
const childMetaRepositories: string[] = [];
|
|
for (const folder of folders) {
|
|
logger.log('info', folder);
|
|
}
|
|
console.log('Recursion still needs to be implemented');
|
|
}
|
|
|
|
// project manipulation
|
|
|
|
/**
|
|
* init a new meta project
|
|
*/
|
|
public async initProject() {
|
|
await this.syncToRemote(true);
|
|
const fileExists = await plugins.smartfile.fs.fileExists(this.filePaths.metaJson);
|
|
if (!fileExists) {
|
|
await plugins.smartfile.memory.toFs(
|
|
JSON.stringify({
|
|
projects: {},
|
|
}),
|
|
this.filePaths.metaJson,
|
|
);
|
|
logger.log(`success`, `created a new .meta.json in directory ${this.cwd}`);
|
|
await plugins.smartfile.memory.toFs(
|
|
JSON.stringify({
|
|
name: this.dirName,
|
|
version: '1.0.0',
|
|
}),
|
|
this.filePaths.packageJson,
|
|
);
|
|
logger.log(`success`, `created a new package.json in directory ${this.cwd}`);
|
|
} else {
|
|
logger.log(`error`, `directory ${this.cwd} already has a .metaJson file. Doing nothing.`);
|
|
}
|
|
await this.smartshellInstance.exec(
|
|
`cd ${this.cwd} && git add -A && git commit -m "feat(project): init meta project for ${this.dirName}"`,
|
|
);
|
|
await this.updateLocalRepos();
|
|
}
|
|
|
|
/**
|
|
* adds a project
|
|
*/
|
|
public async addProject(projectNameArg: string, gitUrlArg) {
|
|
await this.readDirectory();
|
|
|
|
const existingProject = this.metaRepoData.projects[projectNameArg];
|
|
|
|
if (existingProject) {
|
|
throw new Error('Project already exists! Please remove it first before adding it again.');
|
|
}
|
|
|
|
this.metaRepoData.projects[projectNameArg] = gitUrlArg;
|
|
|
|
await this.sortMetaRepoData();
|
|
await this.writeToDisk();
|
|
await this.smartshellInstance.exec(
|
|
`cd ${this.cwd} && git add -A && git commit -m "feat(project): add ${projectNameArg}"`,
|
|
);
|
|
await this.updateLocalRepos();
|
|
}
|
|
|
|
/**
|
|
* removes a project
|
|
*/
|
|
public async removeProject(projectNameArg: string) {
|
|
await this.readDirectory();
|
|
|
|
const existingProject = this.metaRepoData.projects[projectNameArg];
|
|
|
|
if (!existingProject) {
|
|
logger.log('error', `Project ${projectNameArg} does not exist! So it cannot be removed`);
|
|
return;
|
|
}
|
|
|
|
delete this.metaRepoData.projects[projectNameArg];
|
|
|
|
logger.log('info', 'removing project from .meta.json');
|
|
await this.sortMetaRepoData();
|
|
await this.writeToDisk();
|
|
|
|
logger.log('info', 'removing directory from cwd');
|
|
await plugins.smartfile.fs.remove(plugins.path.join(paths.cwd, projectNameArg));
|
|
await this.updateLocalRepos();
|
|
}
|
|
}
|