iop
Version:
Ship Docker Anywhere
227 lines (224 loc) • 8.15 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.initCommand = initCommand;
const path_1 = __importDefault(require("path"));
const promises_1 = require("node:fs/promises");
const node_fs_1 = require("node:fs");
const readline_1 = require("readline");
const IOP_DIR = ".iop";
const CONFIG_FILE = "iop.yml";
const SECRETS_FILE = "secrets";
const ACTUAL_CONFIG_PATH = CONFIG_FILE; // Config file will be in the root
const ACTUAL_SECRETS_PATH = path_1.default.join(IOP_DIR, SECRETS_FILE);
function prompt(question) {
const rl = (0, readline_1.createInterface)({
input: process.stdin,
output: process.stdout,
});
return new Promise((resolve) => {
rl.question(question, (answer) => {
rl.close();
resolve(answer.trim());
});
});
}
async function promptForConfig() {
console.log("Let's set up your iop configuration!\n");
const projectName = (await prompt("Project name (my-project): ")) || "my-project";
return { projectName };
}
function generateConfigContent(config) {
return `name: ${config.projectName}
ssh:
username: iop
services:
web:
build:
context: .
dockerfile: Dockerfile
server: your-server-ip
environment:
plain:
- NODE_ENV=production
secret:
- DATABASE_URL
proxy:
app_port: 3000
health_check:
path: /api/health
# Example infrastructure service (uncomment and configure as needed)
# db:
# image: postgres:15
# server: your-server-ip
# ports:
# - "5432:5432"
# environment:
# plain:
# - POSTGRES_USER=postgres
# - POSTGRES_DB=${config.projectName}
# secret:
# - POSTGRES_PASSWORD
# volumes:
# - ./pgdata:/var/lib/postgresql/data
`;
}
async function ensureSecretsInGitignore() {
const gitignorePath = ".gitignore";
const secretsPath = ACTUAL_SECRETS_PATH;
try {
// Check if .gitignore exists
let gitignoreContent = "";
try {
gitignoreContent = await (0, promises_1.readFile)(gitignorePath, "utf8");
}
catch {
// .gitignore doesn't exist, create it
gitignoreContent = "";
}
// Check if secrets path is already in .gitignore
const lines = gitignoreContent.split("\n");
const secretsAlreadyIgnored = lines.some((line) => line.trim() === secretsPath ||
line.trim() === `/${secretsPath}` ||
line.trim() === secretsPath.replace(/\\/g, "/"));
if (!secretsAlreadyIgnored) {
const newEntry = gitignoreContent.endsWith("\n") || gitignoreContent === ""
? secretsPath
: `\n${secretsPath}`;
if (gitignoreContent === "") {
await (0, promises_1.writeFile)(gitignorePath, `${secretsPath}\n`, "utf8");
}
else {
await (0, promises_1.appendFile)(gitignorePath, `\n${secretsPath}\n`, "utf8");
}
console.log(`Added ${secretsPath} to .gitignore`);
}
}
catch (e) {
const error = e;
console.error(`Warning: Could not update .gitignore: ${error.message}`);
}
}
async function initCommand(args = []) {
// Check for help flag
if (args.includes("--help") || args.includes("-h")) {
console.log("Initialize iop project");
console.log("============================");
console.log("");
console.log("USAGE:");
console.log(" iop init [flags]");
console.log("");
console.log("DESCRIPTION:");
console.log(" Creates iop.yml configuration file and .iop/secrets file.");
console.log(" Automatically adds secrets file to .gitignore for security.");
console.log("");
console.log("FLAGS:");
console.log(" --help Show this help message");
console.log(" --non-interactive Skip prompts, use defaults");
console.log(" --name <name> Set project name (non-interactive mode)");
console.log("");
console.log("EXAMPLES:");
console.log(" iop init # Interactive setup");
console.log(" iop init --non-interactive # Use defaults");
console.log(" iop init --name my-app # Set name non-interactively");
console.log("");
console.log("FILES CREATED:");
console.log(" iop.yml # Main configuration");
console.log(" .iop/secrets # Environment secrets (gitignored)");
return;
}
const nonInteractive = args.includes("--non-interactive");
// Parse --name flag
let projectName;
const nameIndex = args.findIndex(arg => arg === "--name");
if (nameIndex !== -1 && nameIndex + 1 < args.length) {
projectName = args[nameIndex + 1];
}
let configCreated = false;
let secretsCreated = false;
try {
await (0, promises_1.mkdir)(IOP_DIR, { recursive: true });
}
catch (e) {
const error = e;
if (error.code !== "EEXIST") {
console.error(`Error creating directory ${IOP_DIR}: ${error.message}`);
return;
}
}
// Config file handling
let configExistsInitially = false;
try {
await (0, promises_1.access)(ACTUAL_CONFIG_PATH, node_fs_1.constants.F_OK);
configExistsInitially = true;
}
catch {
// File doesn't exist
}
if (configExistsInitially) {
console.log(`Configuration file ${ACTUAL_CONFIG_PATH} already exists.`);
}
else {
try {
let configData;
if (nonInteractive || projectName) {
// Use provided name or default for non-interactive mode
configData = { projectName: projectName || "my-project" };
console.log(`Creating project with name: ${configData.projectName}`);
}
else {
// Interactive mode
configData = await promptForConfig();
}
const configContent = generateConfigContent(configData);
await (0, promises_1.writeFile)(ACTUAL_CONFIG_PATH, configContent, "utf8");
console.log(`\nCreated configuration file: ${ACTUAL_CONFIG_PATH}`);
configCreated = true;
}
catch (e) {
const error = e;
console.error(`Error creating ${ACTUAL_CONFIG_PATH}: ${error.message}`);
}
}
// Secrets file handling
let secretsExistInitially = false;
try {
await (0, promises_1.access)(ACTUAL_SECRETS_PATH, node_fs_1.constants.F_OK);
secretsExistInitially = true;
}
catch {
// File doesn't exist
}
if (secretsExistInitially) {
console.log(`Secrets file ${ACTUAL_SECRETS_PATH} already exists.`);
}
else {
try {
const secretsContent = `# Add your secret environment variables here
# Example:
# DATABASE_URL=postgres://user:password@localhost:5432/mydb
# POSTGRES_PASSWORD=supersecret
# API_KEY=your-api-key
`;
await (0, promises_1.writeFile)(ACTUAL_SECRETS_PATH, secretsContent, "utf8");
console.log(`Created secrets file with examples: ${ACTUAL_SECRETS_PATH}`);
secretsCreated = true;
}
catch (e) {
const error = e;
console.error(`Error creating ${ACTUAL_SECRETS_PATH}: ${error.message}`);
}
}
// Ensure secrets file is in .gitignore
await ensureSecretsInGitignore();
// Final status messages for files that were attempted to be created but failed
if (!configCreated && !configExistsInitially) {
console.log(`Configuration file ${ACTUAL_CONFIG_PATH} could not be created. Check errors above.`);
}
if (!secretsCreated && !secretsExistInitially) {
console.log(`Secrets file ${ACTUAL_SECRETS_PATH} could not be created. Check errors above.`);
}
}
//# sourceMappingURL=init.js.map