UNPKG

@git.zone/cli

Version:

A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.

235 lines (206 loc) 7.42 kB
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(); } }