From adde47efec8c3684fca91088d37cea33b0e61613 Mon Sep 17 00:00:00 2001 From: tiddlygit-test Date: Sat, 25 Jul 2020 22:44:25 +0800 Subject: [PATCH] feat: clone a repo --- public/libs/git.js | 28 +++++++++++ public/libs/{ => wiki}/create-wiki.js | 47 +++++++++++++------ public/listeners/index.js | 22 ++++++++- .../clone-wiki-done-button.js | 7 +-- .../existed-wiki-done-button.js | 2 +- .../new-wiki-done-button.js | 2 +- .../dialog-add-workspace/tab-bar.js | 2 +- src/senders/index.js | 14 ++++++ 8 files changed, 102 insertions(+), 22 deletions(-) rename public/libs/{ => wiki}/create-wiki.js (60%) diff --git a/public/libs/git.js b/public/libs/git.js index 0be62a37..63c4e504 100644 --- a/public/libs/git.js +++ b/public/libs/git.js @@ -366,8 +366,36 @@ async function getRemoteUrl(wikiFolderPath) { return ''; } +async function clone(githubRepoUrl, repoFolderPath, userInfo) { + const logProgress = message => logger.notice(message, { handler: 'createWikiProgress', function: 'clone' }); + const logInfo = message => logger.info(message, { function: 'clone' }); + logProgress('准备克隆线上Wiki'); + logProgress('开始初始化本地Git仓库'); + const { login: username, accessToken } = userInfo; + logInfo( + `Using gitUrl ${githubRepoUrl} with username ${username} and accessToken ${truncate(accessToken, { + length: 24, + })}`, + ); + await GitProcess.exec(['init'], repoFolderPath); + logProgress('仓库初始化完毕,开始配置Github远端仓库'); + await credentialOn(repoFolderPath, githubRepoUrl, userInfo); + logProgress('正在拉取Github远端仓库的数据,需要的时间取决于网速和仓库大小,请耐心等待'); + const { stderr, exitCode } = await GitProcess.exec(['pull', 'origin', 'master:master'], repoFolderPath); + await credentialOff(repoFolderPath); + if (exitCode !== 0) { + logInfo(stderr); + const CONFIG_FAILED_MESSAGE = 'Git仓库配置失败,详见错误日志'; + logProgress(CONFIG_FAILED_MESSAGE); + throw new Error(CONFIG_FAILED_MESSAGE); + } else { + logProgress('Git仓库配置完毕'); + } +} + module.exports = { initWikiGit, commitAndSync, getRemoteUrl, + clone, }; diff --git a/public/libs/create-wiki.js b/public/libs/wiki/create-wiki.js similarity index 60% rename from public/libs/create-wiki.js rename to public/libs/wiki/create-wiki.js index 2a9ff889..de1ac6ec 100644 --- a/public/libs/create-wiki.js +++ b/public/libs/wiki/create-wiki.js @@ -1,17 +1,33 @@ const fs = require('fs-extra'); const path = require('path'); -const { TIDDLYWIKI_TEMPLATE_FOLDER_PATH, TIDDLERS_PATH } = require('../constants/paths'); +const { TIDDLYWIKI_TEMPLATE_FOLDER_PATH, TIDDLERS_PATH } = require('../../constants/paths'); +const { clone } = require('../git'); +const { logger } = require('../log'); -const getLogProgress = logger => message => +const logProgress = message => logger.notice({ type: 'progress', payload: { message, handler: 'createWikiProgress' }, }); -async function createWiki(newFolderPath, folderName, logger) { - const logProgress = getLogProgress(logger); +/** + * Link a sub wiki to a main wiki, this will create a shortcut folder from main wiki to sub wiki, so when saving files to that shortcut folder, you will actually save file to the sub wiki + * @param {string} mainWikiPath folderPath of a wiki as link's destination + * @param {string} folderName sub-wiki's folder name + * @param {string} newWikiPath sub-wiki's folder path + */ +async function linkWiki(mainWikiPath, folderName, subWikiPath) { + const mainWikiTiddlersFolderPath = path.join(mainWikiPath, TIDDLERS_PATH, folderName); + try { + await fs.createSymlink(subWikiPath, mainWikiTiddlersFolderPath); + logProgress(`从${subWikiPath}到${mainWikiTiddlersFolderPath}的链接创建成功,将文件存入后者相当于将文件存入前者。`); + } catch { + throw new Error(`无法链接文件夹 "${subWikiPath}" 到 "${mainWikiTiddlersFolderPath}"`); + } +} +async function createWiki(newFolderPath, folderName) { logProgress('开始用模板创建Wiki'); const newWikiPath = path.join(newFolderPath, folderName); if (!(await fs.pathExists(newFolderPath))) { @@ -38,12 +54,9 @@ async function createWiki(newFolderPath, folderName, logger) { * @param {string} mainWikiToLink * @param {boolean} onlyLink not creating new subwiki folder, just link existed subwiki folder to main wiki folder */ -async function createSubWiki(newFolderPath, folderName, mainWikiToLink, onlyLink = false, logger) { - const logProgress = getLogProgress(logger); - +async function createSubWiki(newFolderPath, folderName, mainWikiToLink, onlyLink = false) { logProgress('开始创建子Wiki'); const newWikiPath = path.join(newFolderPath, folderName); - const mainWikiTiddlersFolderPath = path.join(mainWikiToLink, TIDDLERS_PATH, folderName); if (!(await fs.pathExists(newFolderPath))) { throw new Error(`该目录不存在 "${newFolderPath}"`); } @@ -51,6 +64,7 @@ async function createSubWiki(newFolderPath, folderName, mainWikiToLink, onlyLink throw new Error(`Wiki已经存在于该位置 "${newWikiPath}"`); } logProgress('开始链接子Wiki到父Wiki'); + await linkWiki(mainWikiToLink, folderName, newWikiPath); if (!onlyLink) { try { await fs.mkdirs(newWikiPath); @@ -58,11 +72,7 @@ async function createSubWiki(newFolderPath, folderName, mainWikiToLink, onlyLink throw new Error(`无法在该处创建文件夹 "${newWikiPath}"`); } } - try { - await fs.createSymlink(newWikiPath, mainWikiTiddlersFolderPath); - } catch { - throw new Error(`无法链接文件夹 "${newWikiPath}" 到 "${mainWikiTiddlersFolderPath}"`); - } + logProgress('子Wiki创建完毕'); } @@ -83,4 +93,13 @@ async function ensureWikiExist(wikiPath, shouldBeMainWiki) { } } -module.exports = { createWiki, createSubWiki, removeWiki, ensureWikiExist }; +async function cloneWiki(parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo) { + await clone(githubWikiUrl, path.join(parentFolderLocation, wikiFolderName), userInfo); +} + +async function cloneSubWiki(parentFolderLocation, wikiFolderName, mainWikiPath, githubWikiUrl, userInfo) { + await clone(githubWikiUrl, path.join(parentFolderLocation, wikiFolderName), userInfo); + await linkWiki(mainWikiPath, wikiFolderName, path.join(parentFolderLocation, wikiFolderName)); +} + +module.exports = { createWiki, createSubWiki, removeWiki, ensureWikiExist, cloneWiki, cloneSubWiki }; diff --git a/public/listeners/index.js b/public/listeners/index.js index f0751208..288021fc 100755 --- a/public/listeners/index.js +++ b/public/listeners/index.js @@ -7,7 +7,7 @@ const { initWikiGit, getRemoteUrl } = require('../libs/git'); const { stopWatchWiki } = require('../libs/wiki/watch-wiki'); const { stopWiki } = require('../libs/wiki/wiki-worker-mamager'); const { logger } = require('../libs/log'); -const { createWiki, createSubWiki, removeWiki, ensureWikiExist } = require('../libs/create-wiki'); +const { createWiki, createSubWiki, removeWiki, ensureWikiExist, cloneWiki, cloneSubWiki } = require('../libs/wiki/create-wiki'); const { ICON_PATH, REACT_PATH, DESKTOP_PATH, LOG_FOLDER } = require('../constants/paths'); const { getPreference, getPreferences, resetPreferences, setPreference } = require('../libs/preferences'); @@ -60,7 +60,7 @@ const spellcheckLanguagesWindow = require('../windows/spellcheck-languages'); const loadListeners = () => { ipcMain.handle('copy-wiki-template', async (event, newFolderPath, folderName) => { try { - await createWiki(newFolderPath, folderName, logger); + await createWiki(newFolderPath, folderName); return ''; } catch (error) { return String(error); @@ -75,6 +75,24 @@ const loadListeners = () => { return String(error); } }); + ipcMain.handle('clone-wiki', async (event, parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo) => { + try { + await cloneWiki(parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo); + return ''; + } catch (error) { + console.info(error); + return String(error); + } + }); + ipcMain.handle('clone-sub-wiki', async (event, parentFolderLocation, wikiFolderName, mainWikiPath, githubWikiUrl, userInfo) => { + try { + await cloneSubWiki(parentFolderLocation, wikiFolderName, mainWikiPath, githubWikiUrl, userInfo); + return ''; + } catch (error) { + console.info(error); + return String(error); + } + }); ipcMain.handle('ensure-wiki-exist', async (event, wikiPath, shouldBeMainWiki) => { try { await ensureWikiExist(wikiPath, shouldBeMainWiki); diff --git a/src/components/dialog-add-workspace/clone-wiki-done-button.js b/src/components/dialog-add-workspace/clone-wiki-done-button.js index f16b0bd9..00bad372 100644 --- a/src/components/dialog-add-workspace/clone-wiki-done-button.js +++ b/src/components/dialog-add-workspace/clone-wiki-done-button.js @@ -13,7 +13,7 @@ import Alert from '@material-ui/lab/Alert'; import * as actions from '../../state/dialog-add-workspace/actions'; import type { IUserInfo } from './user-info'; -import { requestCloneWiki, requestCloneSubWiki, getIconPath, initWikiGit } from '../../senders'; +import { requestCloneWiki, requestCloneSubWiki, getIconPath } from '../../senders'; import useWikiCreationMessage from './use-wiki-creation-message'; @@ -89,7 +89,7 @@ function CloneWikiDoneButton({ disabled={!parentFolderLocation || !githubWikiUrl || progressBarOpen || !userInfo} onClick={async () => { updateForm(workspaceFormData); - const cloneError = await requestCloneWiki(parentFolderLocation, wikiFolderName, githubWikiUrl); + const cloneError = await requestCloneWiki(parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo); if (cloneError) { setWikiCreationMessage(cloneError); } else { @@ -121,7 +121,7 @@ function CloneWikiDoneButton({ { updateForm(workspaceFormData); const creationError = await requestCloneSubWiki( @@ -129,6 +129,7 @@ function CloneWikiDoneButton({ wikiFolderName, mainWikiToLink.name, githubWikiUrl, + userInfo, ); if (creationError) { setWikiCreationMessage(creationError); diff --git a/src/components/dialog-add-workspace/existed-wiki-done-button.js b/src/components/dialog-add-workspace/existed-wiki-done-button.js index d656460b..3fe7e6db 100644 --- a/src/components/dialog-add-workspace/existed-wiki-done-button.js +++ b/src/components/dialog-add-workspace/existed-wiki-done-button.js @@ -117,7 +117,7 @@ function DoneButton({ { const wikiFolderName = basename(existedFolderLocation); const parentFolderLocation = dirname(existedFolderLocation); diff --git a/src/components/dialog-add-workspace/new-wiki-done-button.js b/src/components/dialog-add-workspace/new-wiki-done-button.js index d68c4ebb..57a63ca4 100644 --- a/src/components/dialog-add-workspace/new-wiki-done-button.js +++ b/src/components/dialog-add-workspace/new-wiki-done-button.js @@ -126,7 +126,7 @@ function NewWikiDoneButton({ { updateForm(workspaceFormData); let creationError = await requestCreateSubWiki(parentFolderLocation, wikiFolderName, mainWikiToLink.name); diff --git a/src/components/dialog-add-workspace/tab-bar.js b/src/components/dialog-add-workspace/tab-bar.js index 07d56e66..e1a66334 100644 --- a/src/components/dialog-add-workspace/tab-bar.js +++ b/src/components/dialog-add-workspace/tab-bar.js @@ -27,7 +27,7 @@ export default function TabBar({ currentTab, currentTabSetter }: IProps) { > - + diff --git a/src/senders/index.js b/src/senders/index.js index ee1498eb..a8a1cfb0 100644 --- a/src/senders/index.js +++ b/src/senders/index.js @@ -1,5 +1,6 @@ // @flow const { ipcRenderer } = window.require('electron'); +import type { IUserInfo } from '../components/dialog-add-workspace/user-info'; export const requestCopyWikiTemplate = (newFolderPath: string, folderName: string) => ipcRenderer.invoke('copy-wiki-template', newFolderPath, folderName); @@ -11,6 +12,19 @@ export const requestCreateSubWiki = ( ) => ipcRenderer.invoke('create-sub-wiki', newFolderPath, folderName, mainWikiToLink, onlyLink); export const ensureWikiExist = (wikiPath: string, shouldBeMainWiki: boolean) => ipcRenderer.invoke('ensure-wiki-exist', wikiPath, shouldBeMainWiki); +export const requestCloneWiki = ( + parentFolderLocation: string, + wikiFolderName: string, + githubWikiUrl: string, + userInfo: IUserInfo, +) => ipcRenderer.invoke('clone-wiki', parentFolderLocation, wikiFolderName, githubWikiUrl, userInfo); +export const requestCloneSubWiki = ( + parentFolderLocation: string, + wikiFolderName: string, + mainWikiPath: string, + githubWikiUrl: string, + userInfo: IUserInfo, +) => ipcRenderer.invoke('clone-sub-wiki', parentFolderLocation, wikiFolderName, mainWikiPath, githubWikiUrl, userInfo); export const requestOpen = (uri: string, isDirectory?: boolean) => ipcRenderer.send('request-open', uri, !!isDirectory); export const requestShowMessageBox = (message: string, type: string) => ipcRenderer.send('request-show-message-box', message, type);