mlgc
Version:
MLGC is a CLI program that allows you to easily copy all Git changes to a folder for easy uploading or sharing.
187 lines (160 loc) • 5.75 kB
JavaScript
const { gitCommand } = require("../core/git");
const { clearCopyFolder } = require("../core/folder");
const { log } = require("../utils/logger");
const fileHelper = require("../helpers/fileHelper");
const settings = require("../../config/settings");
const { loadBoxen } = require("../utils/boxenHelper");
const { ProgressBar } = require("../utils/progressBar");
const { Select, MultiSelect } = require("enquirer");
const path = require("path");
/**
* Filters files by file type
* @param {string[]} files - Array of file paths
* @param {string|string[]} fileTypes - File type(s) to filter by (e.g. '.js' or ['.js', '.ts'])
* @returns {string[]} Filtered files
*/
function filterFilesByType(files, fileTypes) {
if (!fileTypes || fileTypes === "all" || (Array.isArray(fileTypes) && fileTypes.includes("all"))) {
return files;
}
const types = Array.isArray(fileTypes) ? fileTypes : [fileTypes];
return files.filter((file) => {
const ext = path.extname(file).toLowerCase();
return types.some((type) => {
const normalizedType = type.startsWith(".") ? type.toLowerCase() : `.${type.toLowerCase()}`;
return ext === normalizedType;
});
});
}
/**
* Determines available file types from a list of files
* @param {string[]} files - Array of file paths
* @returns {string[]} Array of unique file types
*/
function getAvailableFileTypes(files) {
const types = new Set();
files.forEach((file) => {
const ext = path.extname(file).toLowerCase();
if (ext) {
types.add(ext);
}
});
return Array.from(types).sort();
}
async function copySelective(branchOrCommit, path) {
await clearCopyFolder();
const { exec } = require("child_process");
process.chdir(path);
const command = gitCommand(branchOrCommit);
return new Promise((resolve) => {
exec(command, async (error, stdout) => {
if (error) {
log.warn("No changes found.");
resolve();
return;
}
const files = stdout.split("\n").filter((file) => file !== "");
if (files.length === 0) {
log.info("No changes found.");
resolve();
return;
}
try {
// Step 1: Select file type filter
const availableTypes = getAvailableFileTypes(files);
const filterChoices = [
{ name: "all", message: "All files", value: "all" },
...availableTypes.map((type) => ({
name: type,
message: `${type} files`,
value: type,
})),
];
const filterPrompt = new Select({
name: "fileType",
message: "📋 Select a file type filter:",
choices: filterChoices,
});
const selectedFilter = await filterPrompt.run();
let filteredFiles = files;
if (selectedFilter !== "all") {
filteredFiles = filterFilesByType(files, selectedFilter);
}
if (filteredFiles.length === 0) {
log.info(`No files found for filter: ${selectedFilter}`);
resolve();
return;
}
// Step 2: Select individual files
const fileChoices = filteredFiles.map((file) => ({
name: file,
message: file,
value: file,
}));
const filePrompt = new MultiSelect({
name: "files",
message: `📄 Select files to copy (${filteredFiles.length} available, all pre-selected):`,
choices: fileChoices,
initial: filteredFiles,
limit: Math.min(filteredFiles.length, 10),
hint: "Press <space> to deselect files, <enter> to confirm selection",
instructions: "Press <space> to deselect, <enter> to confirm",
});
const selectedFiles = await filePrompt.run();
if (!selectedFiles || selectedFiles.length === 0) {
log.info("No files selected.");
resolve();
return;
}
// Step 3: Copy selected files
const progressBar = new ProgressBar(selectedFiles.length);
const copiedFiles = [];
const failedFiles = [];
for (const file of selectedFiles) {
try {
await fileHelper.copyFile(
file,
`${settings["upload-folder-name"]}/${file}`
);
copiedFiles.push(file);
progressBar.increment(file);
} catch (err) {
failedFiles.push({ file, error: err.message });
log.warn(`Failed to copy file: ${err.message}`);
progressBar.increment(file);
}
}
progressBar.stop();
// Ergebnis anzeigen
if (copiedFiles.length > 0) {
const fileList = copiedFiles.map((file) => `- ${file}`).join("\n");
const elapsedTime = progressBar.getElapsedTime();
const boxen = await loadBoxen();
const boxContent = boxen(
`Copied the following ${copiedFiles.length} file(s) in ${elapsedTime.toFixed(2)}s:\n\n${fileList}`,
{
padding: 1,
margin: 1,
borderStyle: "round",
borderColor: "cyan",
}
);
console.log(boxContent);
log.success(`Copied ${copiedFiles.length} file(s) in ${elapsedTime.toFixed(2)}s.`);
}
if (failedFiles.length > 0) {
log.warn(`${failedFiles.length} file(s) failed to copy.`);
}
resolve();
} catch (err) {
if (err.name === "ENOENT" || err.message === "cancelled") {
log.info("Selection cancelled.");
} else {
log.error(`Error during selective copy: ${err.message}`);
}
resolve();
}
});
});
}
module.exports = { copySelective, filterFilesByType };