cli/ts/mod_meta/meta.classes.meta.ts

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();
}
}