11const chalk = require ( 'chalk' )
22const { join, sep, resolve } = require ( 'node:path' )
3+ const fs = require ( 'fs' ) ;
4+ const path = require ( 'node:path' ) ;
35const os = require ( 'os' )
46const { mkdirSync, readFile } = require ( 'fs' )
57const { cwd, chdir, exit, platform } = require ( 'node:process' )
6- const { existsSync, statSync, readdirSync, writeFileSync, readFileSync, rmSync } = require ( 'node:fs' ) ;
8+ const { existsSync, statSync, readdirSync, writeFileSync, readFileSync, rmSync, rm } = require ( 'node:fs' ) ;
79let { exec, spawn } = require ( 'node:child_process' ) ;
810const { writeFile } = require ( 'node:fs/promises' ) ;
911const assets = require ( './assets' )
@@ -1643,7 +1645,7 @@ const scaffoldGateways = async ({ answers }) => {
16431645 const { projectName } = readFileContent ( { currentDir : cwd ( ) } ) ;
16441646 let { apps } = answers ;
16451647 const project_root = generatRootPath ( { currentDir : cwd ( ) } ) ;
1646- const service_objects = getExistingComponent ( { key :'services' , currentDir : cwd ( ) } ) ;
1648+ const service_objects = getExistingComponent ( { key : 'services' , currentDir : cwd ( ) } ) ;
16471649 // add port to services in each app eg ['auth']=>[{name:'auth',port:9001}]
16481650 apps = apps . map ( ( app ) => {
16491651 app . services . map ( ( name , i ) => {
@@ -1705,6 +1707,244 @@ const scaffoldGateway = ({ project_root, app, answers, webserver, projectName })
17051707
17061708}
17071709
1710+ /**
1711+ * Removes a microservice and all associated files.
1712+ * @param {Object } options - Options for removing the microservice.
1713+ * @param {string } options.project_root - The root directory of the project.
1714+ * @param {string } options.service_name - The name of the microservice to be removed.
1715+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1716+ */
1717+ const removeResource = async ( { answers } ) => {
1718+ const { resource, resource_name, options } = answers ;
1719+ let project_root ;
1720+
1721+ try {
1722+ project_root = generatRootPath ( { currentDir : cwd ( ) } ) ;
1723+ } catch ( error ) {
1724+ // Not within a suite repo
1725+ if ( error . message && error . message === 'suite.json and(or) .git not found' ) {
1726+ ora ( 'This does not look like a suite repo' ) . warn ( )
1727+ ora ( ) . info ( 'If it is run <suite init> from project root to reinitialize suite project and try again' )
1728+ exit ( 1 )
1729+ }
1730+ else {
1731+ // rethrow the error
1732+ throw new Error ( 'Error code 10005.Kindly raise an issue at https://github.com/microservices-suite/node-microservices-suite/issues' )
1733+ }
1734+ }
1735+ const spinner = ora ( ) ;
1736+ if ( options . all ) {
1737+ // Logic to remove all resources of the given type
1738+
1739+ const resourceEnum = {
1740+ library : [ 'shared' ] ,
1741+ app : [ 'gateways' , 'apps' ] ,
1742+ service : [ 'microservices' ] ,
1743+ gateway : [ 'gateways' , 'apps' ]
1744+ }
1745+ if ( ! resourceEnum [ resource ] ) return ora ( ) . warn ( `Unkown resource name ${ resource } ` )
1746+ const allResourceChildrenPath = path . join ( project_root , ...( resourceEnum [ resource ] ) ) ;
1747+ if ( ! fs . existsSync ( allResourceChildrenPath ) ) {
1748+ spinner . warn ( `No ${ resource } (s) found.` ) ;
1749+ return ;
1750+ }
1751+
1752+ // Remove all resources
1753+ const services = fs . readdirSync ( allResourceChildrenPath ) ;
1754+ if ( services . length === 0 ) {
1755+ spinner . warn ( `No ${ resource } (s) found.` ) ;
1756+ return ;
1757+ }
1758+
1759+ // Synchronous removal of all services
1760+ services . forEach ( service => {
1761+ const fullPath = path . join ( allResourceChildrenPath , service ) ;
1762+ fs . rmSync ( fullPath , { recursive : true , force : true } ) ;
1763+ } ) ;
1764+ spinner . succeed ( `All ${ resource } (s) have been removed.` ) ;
1765+
1766+ return ;
1767+ }
1768+
1769+ // Call the appropriate action handler based on the resource type
1770+ switch ( resource ) {
1771+ case 'service' :
1772+ await removeService ( { service_name : resource_name , project_root, sync : true } ) ;
1773+ break ;
1774+ case 'app' :
1775+ await removeApp ( { app_name : resource_name , project_root, sync : true } ) ;
1776+ break ;
1777+ case 'library' :
1778+ await removeLibrary ( { library_name : resource_name , project_root, sync : true } ) ;
1779+ break ;
1780+ case 'gateway' :
1781+ await removeGateway ( { gateway_name : resource_name , project_root, sync : true } ) ;
1782+ break ;
1783+ default :
1784+ throw new Error ( `Unknown resource type: ${ resource } ` ) ;
1785+ }
1786+
1787+ } ;
1788+ /**
1789+ * Removes a microservice and all associated files.
1790+ * @param {Object } options - Options for removing the microservice.
1791+ * @param {string } options.project_root - The root directory of the project.
1792+ * @param {string } options.service_name - The name of the microservice to be removed.
1793+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1794+ * @param {boolean } [options.all] - If true, remove all services of the specified type.
1795+ */
1796+ const removeService = async ( { service_name, project_root, sync } ) => {
1797+ const servicePath = path . join ( project_root , 'microservices' , service_name ) ;
1798+ const spinner = ora ( `Removing microservice "${ service_name } "...` ) . start ( ) ;
1799+
1800+ try {
1801+ // Check if the specific service exists
1802+ if ( ! fs . existsSync ( servicePath ) ) {
1803+ spinner . warn ( `Microservice "${ service_name } " not found.` ) ;
1804+ return ;
1805+ }
1806+
1807+ if ( sync ) {
1808+ // Synchronous removal of the specific service
1809+ fs . rmSync ( servicePath , { recursive : true , force : true } ) ;
1810+ spinner . succeed ( `Microservice "${ service_name } " and all associated files have been removed.` ) ;
1811+ } else {
1812+ // Asynchronous removal of the specific service
1813+ fs . rm ( servicePath , { recursive : true , force : true } , ( err ) => {
1814+ if ( err ) throw err ;
1815+ spinner . succeed ( `Microservice "${ service_name } " and all associated files have been removed.` ) ;
1816+ } ) ;
1817+ }
1818+ } catch ( error ) {
1819+ spinner . fail ( `Error while removing microservice "${ service_name } ": ${ error . message } ` ) ;
1820+ }
1821+ } ;
1822+
1823+
1824+ /**
1825+ * Removes a microservice and all associated files.
1826+ * @param {Object } options - Options for removing the microservice.
1827+ * @param {string } options.project_root - The root directory of the project.
1828+ * @param {string } options.app_name - The name of the microapp to be removed.
1829+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1830+ */
1831+ /**
1832+ * Removes an app from both Docker and Kubernetes directories.
1833+ * @param {Object } options - Options for removing the app.
1834+ * @param {string } options.app_name - The name of the app to be removed.
1835+ * @param {string } options.project_root - The root directory of the project.
1836+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1837+ */
1838+ const removeApp = async ( { app_name, project_root, sync = true } ) => {
1839+ const appDockerPath = path . join ( project_root , 'gateways' , 'apps' , app_name ) ;
1840+ const appKubePath = path . join ( project_root , 'k8s' , app_name ) ;
1841+
1842+ // Check if the app exists in either Docker or Kubernetes directories
1843+ const dockerExists = existsSync ( appDockerPath ) ;
1844+ const kubeExists = existsSync ( appKubePath ) ;
1845+
1846+ if ( ! dockerExists && ! kubeExists ) {
1847+ ora ( ) . warn ( `App "${ app_name } " not found in Docker or Kubernetes.` ) ;
1848+ return ;
1849+ }
1850+
1851+ try {
1852+ if ( sync ) {
1853+ // Use synchronous removal
1854+ if ( dockerExists ) {
1855+ rmSync ( appDockerPath , { recursive : true , force : true } ) ;
1856+ ora ( ) . info ( `Docker files for app "${ app_name } " have been removed.` ) ;
1857+ }
1858+
1859+ if ( kubeExists ) {
1860+ rmSync ( appKubePath , { recursive : true , force : true } ) ;
1861+ ora ( ) . info ( `Kubernetes files for app "${ app_name } " have been removed.` ) ;
1862+ }
1863+ } else {
1864+ // Use asynchronous removal
1865+ if ( dockerExists ) {
1866+ rm ( appDockerPath , { recursive : true , force : true } , ( err ) => {
1867+ if ( err ) throw err ;
1868+ ora ( ) . info ( `Docker files for app "${ app_name } " have been removed.` ) ;
1869+ } ) ;
1870+ }
1871+
1872+ if ( kubeExists ) {
1873+ rm ( appKubePath , { recursive : true , force : true } , ( err ) => {
1874+ if ( err ) throw err ;
1875+ ora ( ) . info ( `Kubernetes files for app "${ app_name } " have been removed.` ) ;
1876+ } ) ;
1877+ }
1878+ }
1879+
1880+ ora ( ) . succeed ( `App "${ app_name } " removed successfully.` ) ;
1881+ } catch ( error ) {
1882+ ora ( ) . fail ( `Error while removing app "${ app_name } ": ${ error . message } ` ) ;
1883+ }
1884+ } ;
1885+
1886+ /**
1887+ * Removes a microservice and all associated files.
1888+ * @param {Object } options - Options for removing the microservice.
1889+ * @param {string } options.project_root - The root directory of the project.
1890+ * @param {string } options.library_name - The name of the microlibrary to be removed.
1891+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1892+ */
1893+ const removeLibrary = async ( { library_name, project_root, sync } ) => {
1894+ const libraryPath = path . join ( project_root , 'shared' , library_name ) ;
1895+ // Check if the microservice directory exists
1896+ if ( ! existsSync ( libraryPath ) ) {
1897+ ora ( ) . warn ( `Library "${ library_name } " not found.` ) ;
1898+ return ;
1899+ }
1900+ try {
1901+ if ( sync ) {
1902+ // Use synchronous removal
1903+ rmSync ( libraryPath , { recursive : true , force : true } ) ;
1904+ ora ( ) . info ( `Library "${ library_name } " and all associated files have been removed.` ) ;
1905+ } else {
1906+ // Use asynchronous removal
1907+ rm ( libraryPath , { recursive : true , force : true } , ( err ) => {
1908+ if ( err ) throw err ;
1909+ ora ( ) . info ( `Library "${ library_name } " and all associated files have been removed.` ) ;
1910+ } ) ;
1911+ }
1912+ ora ( ) . succeed ( `Library "${ library_name } " removed successfully.` ) ;
1913+ } catch ( error ) {
1914+ ora ( ) . fail ( `Error while removing Library "${ library_name } ":` , error . message ) ;
1915+ }
1916+ } ;
1917+
1918+ /**
1919+ * Removes a microservice and all associated files.
1920+ * @param {Object } options - Options for removing the microservice.
1921+ * @param {string } options.project_root - The root directory of the project.
1922+ * @param {string } options.gateway - The name of the microgateway to be removed.
1923+ * @param {boolean } [options.sync] - If true, use synchronous file removal.
1924+ */
1925+ const removeGateway = async ( { gateway, project_root, sync } ) => {
1926+ const gatewayPath = path . join ( project_root , 'apps' , gateway ) ;
1927+ if ( ! existsSync ( gatewayPath ) ) {
1928+ ora ( ) . warn ( `Gateway "${ gateway } " not found.` ) ;
1929+ return ;
1930+ }
1931+ try {
1932+ if ( sync ) {
1933+ // Use synchronous removal
1934+ rmSync ( gatewayPath , { recursive : true , force : true } ) ;
1935+ ora ( ) . info ( `Gateway "${ gateway } " and all associated files have been removed.` ) ;
1936+ } else {
1937+ // Use asynchronous removal
1938+ rm ( gatewayPath , { recursive : true , force : true } , ( err ) => {
1939+ if ( err ) throw err ;
1940+ ora ( ) . info ( `Gateway "${ gateway } " and all associated files have been removed.` ) ;
1941+ } ) ;
1942+ }
1943+ ora ( ) . succeed ( `Gateway "${ gateway } " removed successfully.` ) ;
1944+ } catch ( error ) {
1945+ ora ( ) . fail ( `Error while removing Gateway "${ gateway } ":` , error . message ) ;
1946+ }
1947+ } ;
17081948module . exports = {
17091949 generateDirectoryPath,
17101950 changeDirectory,
@@ -1737,5 +1977,8 @@ module.exports = {
17371977 scaffoldApp,
17381978 scaffoldGateways,
17391979 getExistingApps,
1740- readFileContent
1980+ readFileContent,
1981+ removeResource,
1982+ removeService,
1983+ removeApp
17411984}
0 commit comments