This commit is contained in:
157
src/commands/sync.ts
Normal file
157
src/commands/sync.ts
Normal file
@@ -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<void> {
|
||||||
|
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<void> {
|
||||||
|
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 <layout-file>
|
||||||
|
\`\`\`
|
||||||
|
`;
|
||||||
|
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<boolean> {
|
||||||
|
const result = await shellUtils.exec('git rev-parse --git-dir', { cwd: dirPath });
|
||||||
|
return result.success;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function commitLayouts(message?: string): Promise<boolean> {
|
||||||
|
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<void> {
|
||||||
|
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<void> {
|
||||||
|
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<string | null> {
|
||||||
|
const result = await shellUtils.exec('git remote get-url origin', { cwd: dirPath });
|
||||||
|
return result.success ? result.stdout.trim() : null;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user