In this article we'll see how to perform a clean reinstallation of a Node.js application using Python.
We can start from reading the dependency list from the original package.json
file and return the packages names as a list.
import json
import sys
import subprocess
import os
import shutil
def get_packages_names():
names = []
with open('./package.json', 'r') as f:
data = json.load(f)
deps = data.get('dependencies')
if deps:
names = list(deps.keys())
return names
By getting only the key name, we also make sure that we're going to install the latest version of each package. This is useful when we need to update our application to the latest version of its dependencies.
To reinstall our app, we first need to rename our original package.json
file in order to execute a clean npm init -y
command. If this first step succeeds, we move to the actual installation process, otherwise we rename our package.json
file to its original name.
Now we can execute npm install [...] --save
, where [...]
is the list of package names we retrieved from the dependencies
property of our package.json
file. We also need to create a backup copy of our node_modules
directory, if present.
If the installation fails, we restore both the original package.json
file and node_modules
directory. Otherwise, we remove the backup copies of these resources.
def install_packages():
packages_list = get_packages_names()
orig_pkg_file = './package.json'
old_pkg_filename = './package-old.json'
modules_dir = './node_modules'
old_modules_dir_name = './node_modules_old'
if len(packages_list) == 0:
print('No NPM packages to install')
sys.exit(1)
npm_init_cmd = 'npm init -y'.split(' ')
print('Renaming old package.json')
os.rename(orig_pkg_file, old_pkg_filename)
print('Initializing new package.json')
init_cmd = subprocess.run(npm_init_cmd, stdout=subprocess.DEVNULL)
if init_cmd.returncode == 1:
print('Failed to initialize, restoring the old package.json')
os.rename(old_pkg_filename, orig_pkg_file)
sys.exit(1)
install_cmd = ['npm', 'install']
for pkg in packages_list:
install_cmd.append(pkg)
install_cmd.append('--save')
print('Installing packages')
if os.path.isdir(modules_dir):
os.rename(modules_dir, old_modules_dir_name)
install = subprocess.run(install_cmd, stdout=subprocess.DEVNULL)
if install.returncode == 1:
print('Installation failed, cleaning up')
if os.path.isdir(modules_dir):
shutil.rmtree(modules_dir)
os.rename(old_modules_dir_name, modules_dir)
os.unlink(orig_pkg_file)
os.rename(old_pkg_filename, orig_pkg_file)
sys.exit(1)
os.unlink(old_pkg_filename)
shutil.rmtree(old_modules_dir_name)
print('Done')
sys.exit(0)
subprocess.run()
gives us the ability to know whether the executed shell command succeeded or not by exposing the returncode
property, where 1
indicates failure and 0
means that the command has been successfully executed.
This method accepts a command as a list, where the first element represents the command name (here npm
) and the subsequent elements are the command's parameters.
We can run our code as follows:
def main():
install_packages()
if __name__ == '__main__':
main()
This solution is useful when you need to rebuild your application or you just want to get the latest package versions installed without having to manually change their version number within the package.json
file.