diff --git a/src/commands/sync.ts b/src/commands/sync.ts new file mode 100644 index 0000000..454c731 --- /dev/null +++ b/src/commands/sync.ts @@ -0,0 +1,157 @@ +import * as path from 'path'; +import * as fs from 'fs-extra'; +import { shellUtils } from '../utils/shellUtils'; +import { fileUtils } from '../utils/fileUtils'; + +interface SyncOptions { + remote?: string; + branch?: string; + message?: string; + push?: boolean; + pull?: boolean; + init?: boolean; +} + +export async function syncLayouts(options: SyncOptions): Promise { + const layoutsDir = fileUtils.getLayoutsDir(); + + if (options.init) { + await initializeGitRepo(layoutsDir, options.remote, options.branch); + return; + } + + const isGitRepo = await isGitRepository(layoutsDir); + if (!isGitRepo) { + console.log('Not a git repository. Use --init to initialize one.'); + return; + } + + if (options.pull) { + await pullLayouts(options.message); + } + + if (options.push) { + await pushLayouts(options.message); + } +} + +async function initializeGitRepo( + dirPath: string, + remoteUrl?: string, + branch?: string +): Promise { + console.log(`Initializing git repository in ${dirPath}...`); + + const gitResult = await shellUtils.exec('git init', { cwd: dirPath }); + if (!gitResult.success) { + throw new Error(`Failed to initialize git repository: ${gitResult.stderr}`); + } + + const gitignorePath = path.join(dirPath, '.gitignore'); + const gitignoreContent = [ + '*.lock', + '*.log', + 'node_modules/', + '.DS_Store', + '*.tmp', + 'config.json', + ]; + + if (!fs.existsSync(gitignorePath)) { + fs.writeFileSync(gitignorePath, gitignoreContent.join('\n'), 'utf-8'); + } + + const readmePath = path.join(dirPath, 'README.md'); + if (!fs.existsSync(readmePath)) { + const readmeContent = `# Terminal Layouts + +This repository contains terminal workspace layouts synced by terminal-layout-sync. + +## Usage + +Clone this repository and import layouts using: +\`\`\` +terminal-layout-sync import +\`\`\` +`; + fs.writeFileSync(readmePath, readmeContent, 'utf-8'); + } + + if (remoteUrl) { + const remoteResult = await shellUtils.exec(`git remote add origin ${remoteUrl}`, { cwd: dirPath }); + if (!remoteResult.success) { + throw new Error(`Failed to add remote: ${remoteResult.stderr}`); + } + console.log(`Remote added: ${remoteUrl}`); + } + + const defaultBranch = branch || 'main'; + await shellUtils.exec(`git branch -M ${defaultBranch}`, { cwd: dirPath }); + + console.log('Git repository initialized successfully.'); +} + +async function isGitRepository(dirPath: string): Promise { + const result = await shellUtils.exec('git rev-parse --git-dir', { cwd: dirPath }); + return result.success; +} + +async function commitLayouts(message?: string): Promise { + const layoutsDir = fileUtils.getLayoutsDir(); + const commitMessage = message || `Update layouts - ${new Date().toISOString()}`; + + const statusResult = await shellUtils.exec('git status --porcelain', { cwd: layoutsDir }); + if (!statusResult.stdout.trim()) { + console.log('No changes to commit.'); + return false; + } + + const addResult = await shellUtils.exec('git add .', { cwd: layoutsDir }); + if (!addResult.success) { + throw new Error(`Failed to stage files: ${addResult.stderr}`); + } + + const commitResult = await shellUtils.exec(`git commit -m "${commitMessage}"`, { cwd: layoutsDir }); + if (!commitResult.success) { + throw new Error(`Failed to commit: ${commitResult.stderr}`); + } + + console.log(`Committed changes: ${commitMessage}`); + return true; +} + +async function pushLayouts(message?: string): Promise { + const layoutsDir = fileUtils.getLayoutsDir(); + + const hasChanges = await commitLayouts(message); + if (!hasChanges) { + console.log('Nothing to push.'); + return; + } + + const pushResult = await shellUtils.exec('git push origin main', { cwd: layoutsDir }); + if (!pushResult.success) { + throw new Error(`Failed to push: ${pushResult.stderr}`); + } + + console.log('Layouts pushed successfully.'); +} + +async function pullLayouts(_message?: string): Promise { + const layoutsDir = fileUtils.getLayoutsDir(); + + const pullResult = await shellUtils.exec('git pull origin main', { cwd: layoutsDir }); + if (!pullResult.success) { + console.log(`Failed to pull: ${pullResult.stderr}`); + console.log('You may need to resolve conflicts manually.'); + return; + } + + console.log('Layouts pulled successfully.'); + console.log(pullResult.stdout); +} + +export async function getRemoteUrl(dirPath: string): Promise { + const result = await shellUtils.exec('git remote get-url origin', { cwd: dirPath }); + return result.success ? result.stdout.trim() : null; +}