Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | /**
* Git Importer
*
* Imports Hugo sites from git repositories (public and private).
*/
import fs from 'fs-extra';
import path from 'path';
import { InitialWorkspaceConfigBuilder } from '../services/workspace/initial-workspace-config-builder.js';
import { hugoConfigSchema } from '@quiqr/types';
/**
* GitImporter - Imports sites from git repositories
*/
export class GitImporter {
embgit;
pathHelper;
formatProviderResolver;
libraryService;
constructor(embgit, pathHelper, formatProviderResolver, libraryService) {
this.embgit = embgit;
this.pathHelper = pathHelper;
this.formatProviderResolver = formatProviderResolver;
this.libraryService = libraryService;
}
/**
* Build a Git URL from components
* @param baseUrl - The Git host, may include port for HTTPS (e.g., 'github.com', 'localhost:3000')
* @param org - The organization or username
* @param repo - The repository name
* @param protocol - 'ssh' or 'https' (defaults to 'ssh')
* @param sshPort - SSH port (defaults to 22, only used for SSH protocol)
*/
buildGitUrl(baseUrl, org, repo, protocol = 'ssh', sshPort = 22) {
// Ensure repo ends with .git
const repoWithGit = repo.endsWith('.git') ? repo : `${repo}.git`;
if (protocol === 'ssh') {
// Extract host without port for SSH (port is specified separately)
const host = baseUrl.split(':')[0];
if (sshPort === 22) {
// Standard SSH format: git@host:org/repo.git
return `git@${host}:${org}/${repoWithGit}`;
}
else {
// Non-standard port SSH format: ssh://git@host:port/org/repo.git
return `ssh://git@${host}:${sshPort}/${org}/${repoWithGit}`;
}
}
else {
// HTTPS format: https://host:port/org/repo.git
// Use http for localhost, https otherwise
const isLocalhost = baseUrl.startsWith('localhost') || baseUrl.startsWith('127.0.0.1');
const scheme = isLocalhost ? 'http' : 'https';
return `${scheme}://${baseUrl}/${org}/${repoWithGit}`;
}
}
/**
* Import a site from a private git repository
* @param gitBaseUrl - The Git host, may include port for HTTPS (e.g., 'github.com', 'localhost:3000')
* @param gitOrg - The organization or username
* @param gitRepo - The repository name
* @param privKey - SSH private key for authentication
* @param gitEmail - Email for Git commits
* @param saveSyncTarget - Whether to save the sync configuration
* @param siteName - Name for the imported site
* @param protocol - 'ssh' or 'https' (defaults to 'ssh')
* @param sshPort - SSH port (defaults to 22, only used for SSH protocol)
* @param gitProvider - The git provider type for CI configuration (defaults to 'generic')
*/
async importSiteFromPrivateGitRepo(gitBaseUrl, gitOrg, gitRepo, privKey, gitEmail, saveSyncTarget, siteName, protocol = 'ssh', sshPort = 22, gitProvider = 'generic') {
const url = this.buildGitUrl(gitBaseUrl, gitOrg, gitRepo, protocol, sshPort);
console.log('Importing from private repo:', url);
const siteKey = await this.libraryService.createSiteKeyFromName(siteName);
const tempCloneDir = path.join(this.pathHelper.getTempDir(), 'siteFromGit');
// Clean up any existing temp directory
fs.removeSync(tempCloneDir);
await this.embgit.clonePrivateWithKey(url, tempCloneDir, privKey);
// Create the site from the cloned directory
await this.libraryService.createNewSiteWithTempDirAndKey(siteKey, tempCloneDir);
// Save sync target if requested
if (saveSyncTarget) {
const siteConf = await this.libraryService.getSiteConf(siteKey);
const inkey = `publ-${Math.random()}`;
// Derive public key from private key
const deployPublicKey = this.embgit.derivePublicKeyFromPrivate(privKey);
const publConf = {
type: 'git',
gitProvider: gitProvider,
gitBaseUrl: gitBaseUrl,
gitProtocol: protocol,
sshPort: sshPort,
username: gitOrg,
email: gitEmail,
repository: gitRepo,
branch: 'main',
deployPrivateKey: privKey,
deployPublicKey,
publishScope: 'source',
keyPairBusy: false,
overrideBaseURLSwitch: false,
overrideBaseURL: '',
setCIWorkflow: false,
};
if (!siteConf.publish) {
siteConf.publish = [];
}
siteConf.publish.push({ key: inkey, config: publConf });
await this.libraryService.writeSiteConf(siteConf, siteKey);
}
return siteKey;
}
/**
* Import a site from a public git URL
* Used by "Import from Git URL" dialog
*/
async importSiteFromPublicGitUrl(url, siteName) {
const siteKey = await this.libraryService.createSiteKeyFromName(siteName);
const tempCloneDir = path.join(this.pathHelper.getTempDir(), 'siteFromGit');
// Clean up any existing temp directory
fs.removeSync(tempCloneDir);
// Clone the repository
await this.embgit.cloneFromPublicUrl(url, tempCloneDir);
// Create the site from the cloned directory
await this.libraryService.createNewSiteWithTempDirAndKey(siteKey, tempCloneDir);
return siteKey;
}
/**
* Create a new site from a public Hugo theme URL
* Used by "New from Hugo Theme" dialog
*/
async newSiteFromPublicHugoThemeUrl(url, siteName, themeInfo, hugoVersion) {
if (!themeInfo.Name) {
throw new Error('Theme name is required');
}
const themeName = themeInfo.Name.replace(/\s/g, '-').toLowerCase();
const siteKey = await this.libraryService.createSiteKeyFromName(siteName);
const tempDir = path.join(this.pathHelper.getTempDir(), 'siteFromTheme');
const tempCloneThemeDir = path.join(tempDir, 'themes', themeName);
// Clean up any existing temp directory
fs.removeSync(tempDir);
await fs.ensureDir(tempDir);
await fs.ensureDir(path.join(tempDir, 'themes'));
await this.embgit.cloneFromPublicUrl(url, tempCloneThemeDir);
// Copy exampleSite if it exists
if (themeInfo.ExampleSite) {
const exampleSitePath = path.join(tempCloneThemeDir, 'exampleSite');
if (fs.existsSync(exampleSitePath)) {
fs.copySync(exampleSitePath, tempDir);
}
}
// Process Hugo config
let formatProvider;
let hconfig = null;
const hugoConfigFilePath = this.pathHelper.hugoConfigFilePath(tempDir);
if (hugoConfigFilePath) {
const strData = fs.readFileSync(hugoConfigFilePath, { encoding: 'utf-8' });
formatProvider = this.formatProviderResolver.resolveForFilePath(hugoConfigFilePath);
if (formatProvider) {
const rawData = formatProvider.parse(strData);
const parseResult = hugoConfigSchema.safeParse(rawData);
if (parseResult.success) {
hconfig = parseResult.data;
}
}
}
// Set theme and baseURL
if (!hconfig) {
hconfig = {};
}
hconfig.theme = themeName;
hconfig.baseURL = '/';
// Write updated config
if (hugoConfigFilePath && formatProvider) {
fs.writeFileSync(hugoConfigFilePath, formatProvider.dump(hconfig));
}
// Build Quiqr model
const configBuilder = new InitialWorkspaceConfigBuilder(tempDir, this.formatProviderResolver, this.pathHelper);
configBuilder.buildAll('hugo', hugoVersion);
// Create the site
await this.libraryService.createNewSiteWithTempDirAndKey(siteKey, tempDir);
return siteKey;
}
}
|