Task Automation CLI Tool C++
👤 Sharing: AI
```cpp
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <chrono>
#include <thread>
#include <cstdlib> // For system()
#include <iomanip> // For setw and setfill
// Configuration structure
struct Config {
std::string task_name;
std::string command;
int delay; // Delay in seconds
bool run_once; // Run only once
bool verbose; // Verbose output
bool enabled; // Enable or disable the task
std::string log_file; // log file name
std::string shell_command; //run it through shell or not
};
// Function prototypes
bool loadConfig(const std::string& filename, std::vector<Config>& configs);
void runTask(const Config& config);
void printHelp();
void listTasks(const std::vector<Config>& configs);
void enableTask(std::vector<Config>& configs, const std::string& taskName);
void disableTask(std::vector<Config>& configs, const std::string& taskName);
void saveConfig(const std::string& filename, const std::vector<Config>& configs);
void editTask(std::vector<Config>& configs, const std::string& taskName);
void addTask(std::vector<Config>& configs);
void removeTask(std::vector<Config>& configs, const std::string& taskName);
void printConfig(const Config& config); // Function to print a single config
void runSingleTask(const std::vector<Config>& configs, const std::string& taskName);
bool isValidTaskName(const std::string& taskName); // Validation function
// Global Configuration file name
const std::string CONFIG_FILE = "tasks.config";
int main(int argc, char* argv[]) {
std::vector<Config> configs;
if (!loadConfig(CONFIG_FILE, configs)) {
std::cerr << "Error: Could not load configuration from " << CONFIG_FILE << ". Using default configuration.\n";
}
if (argc == 1) {
// Run all enabled tasks
std::cout << "Running all enabled tasks. Press Ctrl+C to stop.\n";
while (true) {
for (auto& config : configs) {
if (config.enabled) {
runTask(config);
if (config.run_once) {
config.enabled = false; // Disable after running once
saveConfig(CONFIG_FILE, configs); //Persist the change.
}
}
}
std::this_thread::sleep_for(std::chrono::seconds(1)); // Check tasks every second
}
} else {
std::string command = argv[1];
if (command == "help") {
printHelp();
} else if (command == "list") {
listTasks(configs);
} else if (command == "enable") {
if (argc > 2) {
enableTask(configs, argv[2]);
saveConfig(CONFIG_FILE, configs);
} else {
std::cerr << "Error: Task name required.\n";
printHelp();
}
} else if (command == "disable") {
if (argc > 2) {
disableTask(configs, argv[2]);
saveConfig(CONFIG_FILE, configs);
} else {
std::cerr << "Error: Task name required.\n";
printHelp();
}
} else if (command == "edit") {
if (argc > 2) {
editTask(configs, argv[2]);
saveConfig(CONFIG_FILE, configs);
} else {
std::cerr << "Error: Task name required.\n";
printHelp();
}
} else if (command == "add") {
addTask(configs);
saveConfig(CONFIG_FILE, configs);
} else if (command == "remove") {
if (argc > 2) {
removeTask(configs, argv[2]);
saveConfig(CONFIG_FILE, configs);
} else {
std::cerr << "Error: Task name required.\n";
printHelp();
}
}
else if (command == "run") {
if (argc > 2) {
runSingleTask(configs, argv[2]);
} else {
std::cerr << "Error: Task name required.\n";
printHelp();
}
}
else {
std::cerr << "Error: Invalid command.\n";
printHelp();
}
}
return 0;
}
bool isValidTaskName(const std::string& taskName) {
if (taskName.empty()) return false;
for (char c : taskName) {
if (!isalnum(c) && c != '_' && c != '-') {
return false;
}
}
return true;
}
bool loadConfig(const std::string& filename, std::vector<Config>& configs) {
std::ifstream file(filename);
if (!file.is_open()) {
// If the file doesn't exist, create a default configuration
std::ofstream outfile(filename);
if (!outfile.is_open()) {
std::cerr << "Error creating config file. Check permissions.\n";
return false;
}
outfile << "task1:command=echo \"Hello, world!\",delay=5,run_once=false,verbose=true,enabled=true,log_file=task1.log,shell_command=false\n";
outfile.close();
// Now that we've created the file, try to load it again.
file.open(filename);
if (!file.is_open()) return false;
}
std::string line;
while (std::getline(file, line)) {
std::stringstream ss(line);
std::string token;
Config config;
// Parse the task name
std::getline(ss, token, ':');
config.task_name = token;
// Parse the attributes
while (std::getline(ss, token, ',')) {
size_t pos = token.find('=');
if (pos != std::string::npos) {
std::string key = token.substr(0, pos);
std::string value = token.substr(pos + 1);
if (key == "command") {
config.command = value;
} else if (key == "delay") {
try {
config.delay = std::stoi(value);
} catch (const std::invalid_argument& e) {
std::cerr << "Error: Invalid delay value for task " << config.task_name << ". Using default value (0).\n";
config.delay = 0;
}
} else if (key == "run_once") {
config.run_once = (value == "true");
} else if (key == "verbose") {
config.verbose = (value == "true");
} else if (key == "enabled") {
config.enabled = (value == "true");
}
else if (key == "log_file") {
config.log_file = value;
}
else if (key == "shell_command") {
config.shell_command = (value == "true");
}
else {
std::cerr << "Warning: Unknown attribute '" << key << "' in task " << config.task_name << ".\n";
}
} else {
std::cerr << "Warning: Invalid format in line: " << line << "\n";
}
}
configs.push_back(config);
}
file.close();
return true;
}
void runTask(const Config& config) {
if (!config.enabled) return;
if (config.verbose) {
std::cout << "Running task: " << config.task_name << "\n";
}
std::string command_to_execute = config.command;
if(config.shell_command){
command_to_execute = "sh -c \"" + config.command + "\""; // Wrap the command for execution in the shell
}
std::ofstream logFile(config.log_file, std::ios::app); // Open log file in append mode
if (!logFile.is_open()) {
std::cerr << "Error opening log file: " << config.log_file << "\n";
return;
}
auto now = std::chrono::system_clock::now();
auto time_now = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&time_now);
char timestamp[30];
std::strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now_tm);
logFile << "[" << timestamp << "] Running command: " << config.command << "\n";
int result = system(command_to_execute.c_str());
if (result == 0) {
logFile << "[" << timestamp << "] Task " << config.task_name << " completed successfully.\n";
if (config.verbose) {
std::cout << "Task " << config.task_name << " completed successfully.\n";
}
} else {
logFile << "[" << timestamp << "] Task " << config.task_name << " failed with exit code: " << result << "\n";
std::cerr << "Task " << config.task_name << " failed with exit code: " << result << "\n";
}
logFile.close();
if (config.delay > 0) {
if (config.verbose) {
std::cout << "Waiting " << config.delay << " seconds before next run.\n";
}
std::this_thread::sleep_for(std::chrono::seconds(config.delay));
}
}
void printHelp() {
std::cout << "Task Automation CLI Tool\n";
std::cout << "Usage: task_automation [command] [options]\n";
std::cout << "Commands:\n";
std::cout << " help Display this help message.\n";
std::cout << " list List all tasks and their status.\n";
std::cout << " enable <task_name> Enable a task.\n";
std::cout << " disable <task_name> Disable a task.\n";
std::cout << " edit <task_name> Edit a task's configuration.\n";
std::cout << " add Add a new task.\n";
std::cout << " remove <task_name> Remove a task.\n";
std::cout << " run <task_name> Run a single task immediately.\n";
std::cout << " (none) Run all enabled tasks in a loop.\n";
}
void listTasks(const std::vector<Config>& configs) {
std::cout << "Tasks:\n";
std::cout << std::setw(20) << std::left << "Task Name" << std::setw(10) << "Enabled" << std::setw(10) << "Run Once" << std::setw(5) << "Delay" << std::endl;
std::cout << std::setfill('-') << std::setw(50) << "-" << std::setfill(' ') << std::endl; // Separator line
for (const auto& config : configs) {
std::cout << std::setw(20) << std::left << config.task_name
<< std::setw(10) << (config.enabled ? "Yes" : "No")
<< std::setw(10) << (config.run_once ? "Yes" : "No")
<< std::setw(5) << config.delay << std::endl;
}
}
void enableTask(std::vector<Config>& configs, const std::string& taskName) {
auto it = std::find_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == taskName;
});
if (it != configs.end()) {
it->enabled = true;
std::cout << "Task '" << taskName << "' enabled.\n";
} else {
std::cerr << "Error: Task '" << taskName << "' not found.\n";
}
}
void disableTask(std::vector<Config>& configs, const std::string& taskName) {
auto it = std::find_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == taskName;
});
if (it != configs.end()) {
it->enabled = false;
std::cout << "Task '" << taskName << "' disabled.\n";
} else {
std::cerr << "Error: Task '" << taskName << "' not found.\n";
}
}
void saveConfig(const std::string& filename, const std::vector<Config>& configs) {
std::ofstream file(filename);
if (!file.is_open()) {
std::cerr << "Error: Could not open " << filename << " for writing.\n";
return;
}
for (const auto& config : configs) {
file << config.task_name << ":command=" << config.command
<< ",delay=" << config.delay
<< ",run_once=" << (config.run_once ? "true" : "false")
<< ",verbose=" << (config.verbose ? "true" : "false")
<< ",enabled=" << (config.enabled ? "true" : "false")
<< ",log_file=" << config.log_file
<< ",shell_command=" << (config.shell_command ? "true" : "false")
<< "\n";
}
file.close();
}
void editTask(std::vector<Config>& configs, const std::string& taskName) {
auto it = std::find_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == taskName;
});
if (it == configs.end()) {
std::cerr << "Error: Task '" << taskName << "' not found.\n";
return;
}
Config& config = *it; // Get a reference to the config
std::cout << "Editing task: " << config.task_name << "\n";
printConfig(config); // Print current configuration
std::cout << "Enter new values (leave blank to keep current value):\n";
std::string input;
std::cout << "Command (" << config.command << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.command = input;
}
std::cout << "Delay (" << config.delay << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
try {
config.delay = std::stoi(input);
} catch (const std::invalid_argument& e) {
std::cerr << "Invalid input. Keeping original value.\n";
}
}
std::cout << "Run Once (" << (config.run_once ? "true" : "false") << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.run_once = (input == "true");
}
std::cout << "Verbose (" << (config.verbose ? "true" : "false") << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.verbose = (input == "true");
}
std::cout << "Enabled (" << (config.enabled ? "true" : "false") << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.enabled = (input == "true");
}
std::cout << "Log File (" << config.log_file << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.log_file = input;
}
std::cout << "Run in shell (" << (config.shell_command ? "true" : "false") << "): ";
std::getline(std::cin, input);
if (!input.empty()) {
config.shell_command = (input == "true");
}
std::cout << "Task '" << config.task_name << "' updated.\n";
printConfig(config);
}
void printConfig(const Config& config) {
std::cout << " Task Name: " << config.task_name << "\n";
std::cout << " Command: " << config.command << "\n";
std::cout << " Delay: " << config.delay << "\n";
std::cout << " Run Once: " << (config.run_once ? "true" : "false") << "\n";
std::cout << " Verbose: " << (config.verbose ? "true" : "false") << "\n";
std::cout << " Enabled: " << (config.enabled ? "true" : "false") << "\n";
std::cout << " Log File: " << config.log_file << "\n";
std::cout << " Run in Shell: " << (config.shell_command ? "true" : "false") << "\n";
}
void addTask(std::vector<Config>& configs) {
Config newConfig;
std::cout << "Adding a new task.\n";
std::cout << "Enter task name: ";
std::getline(std::cin, newConfig.task_name);
if (!isValidTaskName(newConfig.task_name)) {
std::cerr << "Error: Invalid task name. Task names must be alphanumeric and can contain underscores or hyphens.\n";
return;
}
// Check for duplicate task names
auto it = std::find_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == newConfig.task_name;
});
if (it != configs.end()) {
std::cerr << "Error: Task with name '" << newConfig.task_name << "' already exists.\n";
return;
}
std::cout << "Enter command: ";
std::getline(std::cin, newConfig.command);
std::string input;
std::cout << "Enter delay (seconds): ";
std::getline(std::cin, input);
try {
newConfig.delay = std::stoi(input);
} catch (const std::invalid_argument& e) {
std::cerr << "Invalid input. Setting delay to 0.\n";
newConfig.delay = 0;
}
std::cout << "Run Once (true/false): ";
std::getline(std::cin, input);
newConfig.run_once = (input == "true");
std::cout << "Verbose (true/false): ";
std::getline(std::cin, input);
newConfig.verbose = (input == "true");
std::cout << "Enabled (true/false): ";
std::getline(std::cin, input);
newConfig.enabled = (input == "true");
std::cout << "Enter Log File name: ";
std::getline(std::cin, newConfig.log_file);
std::cout << "Run in shell (true/false): ";
std::getline(std::cin, input);
newConfig.shell_command = (input == "true");
configs.push_back(newConfig);
std::cout << "Task '" << newConfig.task_name << "' added.\n";
printConfig(newConfig);
}
void removeTask(std::vector<Config>& configs, const std::string& taskName) {
auto it = std::remove_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == taskName;
});
if (it != configs.end()) {
configs.erase(it, configs.end());
std::cout << "Task '" << taskName << "' removed.\n";
} else {
std::cerr << "Error: Task '" << taskName << "' not found.\n";
}
}
void runSingleTask(const std::vector<Config>& configs, const std::string& taskName) {
auto it = std::find_if(configs.begin(), configs.end(), [&](const Config& c) {
return c.task_name == taskName;
});
if (it != configs.end()) {
runTask(*it);
} else {
std::cerr << "Error: Task '" << taskName << "' not found.\n";
}
}
```
👁️ Viewed: 7
Comments