Skip to content

Instantly share code, notes, and snippets.

@FridayCandour
Created November 8, 2023 20:31
Show Gist options
  • Save FridayCandour/75f8c7abb7fed21c3d6aad8366aa9ae7 to your computer and use it in GitHub Desktop.
Save FridayCandour/75f8c7abb7fed21c3d6aad8366aa9ae7 to your computer and use it in GitHub Desktop.
A node script to position your node projects
#!/usr/bin/env node
import util from "node:util";
import path from "node:path";
import fs from "node:fs";
import child_process from "node:child_process";
// Parse command line arguments
const P_args = process.argv.slice(2);
const seen_p = {};
// Utility functions
const exec = util.promisify(child_process.exec);
// Function to run a command and handle errors
async function runCmd(command) {
try {
return await exec(command);
} catch (error) {
console.log(error.stderr);
return error;
}
}
// Function to handle and suppress errors gracefully
async function AvoidErrorInCB(cb) {
try {
return (await cb()) || true;
} catch (e) {
// Handle errors or log them as needed
// console.log(e);
return false;
}
}
// Parse command line arguments and extract relevant options
const parseInput = async () => {
if (P_args.length) {
if (P_args.join("").includes("--port=")) {
const a = P_args.join(" ").split("--port=")[1].split(" ")[0];
seen_p.port = a;
}
if (P_args.join("").includes("--mode=")) {
const a = P_args.join(" ").split("--mode=")[1].split(" ")[0];
if (a === "install" || a === "position") {
seen_p.mode = a;
}
}
if (P_args.join("").includes("--appDir=")) {
const a = P_args.join(" ").split("--appDir=")[1].split(" ")[0];
if (a) {
seen_p.folderName = a;
}
}
if (seen_p.mode === "position") {
return;
}
if (P_args.join("").includes("--repoLink=") && seen_p.mode === "install") {
const a = P_args.join(" ").split("--repoLink=")[1].split(" ")[0];
// Extract username and token from the repoLink
// Note: This code assumes a specific format for the repoLink
const ks = a.indexOf("https:");
const kz = a.indexOf(".git");
const ghurl = a.slice(ks, kz) + ".git";
const urlWithoutCredentials = ghurl.replace(
/https:\/\/(.*?):(.*?)@/g,
"https://"
);
const repo = await AvoidErrorInCB(async () => {
let yut = ghurl.split(":");
const username = yut[1].split("//")[1];
const token = yut[2].split("@")[0];
seen_p.token = token;
seen_p.username = username;
const ghs = await fetch(urlWithoutCredentials, {
method: "HEAD",
headers: {
Authorization: `Basic ${Buffer.from(
`${username}:${token}`
).toString("base64")}`,
},
});
if (ghs.ok) {
return true;
}
console.log(ghs);
return false;
});
if (repo) {
seen_p.repoLink = a;
seen_p.repo = urlWithoutCredentials;
seen_p.repo_retrieved = true;
} else {
seen_p.repo = "repo verification failed";
seen_p.repo_retrieved = false;
}
}
}
};
// Parse input options
await parseInput();
// Display parsed options
console.log("OPTIONS:");
console.table(seen_p);
// Check if required options are present
if (
!seen_p.mode ||
!seen_p.folderName ||
(seen_p.mode === "install" && !seen_p.repoLink)
) {
console.log("OPTIONS TO RUN SCRIPT CANNOT BE DETERMINED FOR ARGS GIVEN");
process.exit(89);
}
// Define constants
const ownPath = process.cwd();
const appPath = path.join(ownPath, seen_p.folderName);
// Function to set up the project
async function setup() {
try {
// Check if directory already exists
let makeAppDir = await AvoidErrorInCB(() => {
fs.mkdirSync(appPath);
});
if (!makeAppDir) {
await runCmd("rm -rf " + seen_p.folderName);
}
// Clone the repository
console.log(`cloning app from repo ${seen_p.repoLink}`);
await runCmd(`git clone --depth 1 ${seen_p.repoLink} ${seen_p.folderName}`);
console.log("Cloned successfully.");
console.log("");
// Change directory to the appPath
process.chdir(seen_p.folderName);
// Install dependencies
console.log("Installing dependencies ...");
await runCmd("npm run install"); // You can use "npm install" or "bun install" as needed
console.log("Dependencies installed successfully.");
// Delete the .git folder
await runCmd("rm -rf .git");
console.log("Installation is now complete!");
console.log("");
} catch (error) {
console.log(error);
}
}
// Function to launch the application
async function launch() {
console.log("Running...");
const { stderr } = await runCmd("npm run start &");
prob(stderr);
}
// Function to handle port-related issues
async function prob(stderr) {
if (stderr.includes("EADDRINUSE:")) {
console.log(stderr);
console.log("Port is in use.");
const { stdout } = await runCmd(`lsof -i :${seen_p.port}`);
const outers = stdout.split(" ");
const pid = outers.find((s, r) => {
if (Number(s) && outers[r - 1] === "") {
return s;
}
});
if (Number(pid)) {
console.log("Killing port " + seen_p.port + " on PID '" + pid + "' ...");
await runCmd(`kill -15 ${pid}`);
launch();
}
}
}
// Function to start the application in 'position' mode
async function running() {
try {
const fex = await AvoidErrorInCB(() => {
fs.mkdirSync(appPath);
});
if (!fex) {
console.log("App folder '" + seen_p.folderName + "' located!");
} else {
// Handle the case where the app directory is not found
console.log("Error: Could not find app directory - " + seen_p.folderName);
process.exit(1);
}
process.chdir(seen_p.folderName);
await launch();
// Further handle issues like port already in use
} catch (error) {
console.log(error);
process.exit(1);
}
}
// Main execution based on 'mode' option
if (seen_p.mode === "install") {
setup();
}
if (seen_p.mode === "position") {
running();
}
// repoLink=https://<username>:<gh-token>github.com/<username>/<repo>.git <-b <branch> if needed>
// repoLink=https://github.com/<username>/<repo>.git <-b <branch> if needed>
@FridayCandour
Copy link
Author

Example Usage:

mode: install

node positioner.js --mode=install --appDir=app --repoLink="https:
//fridaycandour:[email protected]/fridaycandour/positioner.git -b main"

mode: position

node positioner.js --mode=position --appDir=app --port=3000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment