mirror of
https://github.com/NaiboWang/EasySpider.git
synced 2026-10-30 18:22:29 +08:00
fix(macOS): stabilize command-line execution path
This commit is contained in:
@@ -16,6 +16,7 @@ execution_instances/*
|
||||
info.log
|
||||
npminstall-debug.log
|
||||
mysql_config.json
|
||||
macos_command_folder.json
|
||||
EasySpider_en/
|
||||
EasySpider_zh/
|
||||
TempUserDataFolder/
|
||||
|
||||
+124
-1
@@ -36,6 +36,64 @@ let config_context = JSON.parse(
|
||||
fs.readFileSync(path.join(task_server.getDir(), `config.json`), "utf8")
|
||||
); //仅在当前进程中使用,不会写入文件
|
||||
|
||||
const macOSCommandFolderConfigPath = path.join(
|
||||
task_server.getDir(),
|
||||
"macos_command_folder.json"
|
||||
);
|
||||
|
||||
function getMacOSCommandLauncher(folder) {
|
||||
if (!folder) {
|
||||
return "";
|
||||
}
|
||||
const absoluteFolder = path.resolve(folder);
|
||||
const appPath = path.join(absoluteFolder, "EasySpider.app");
|
||||
const scriptPath = path.join(absoluteFolder, "execute_macos.sh");
|
||||
const executablePath = path.join(absoluteFolder, "easyspider_executestage");
|
||||
if (!fs.existsSync(appPath) || !fs.existsSync(executablePath)) {
|
||||
return "";
|
||||
}
|
||||
// New packages include the wrapper so it can resolve its own directory.
|
||||
// Retain compatibility with older portable releases that only contain
|
||||
// the execution-stage binary.
|
||||
return fs.existsSync(scriptPath) ? scriptPath : executablePath;
|
||||
}
|
||||
|
||||
function readSavedMacOSCommandFolder() {
|
||||
try {
|
||||
const saved = JSON.parse(
|
||||
fs.readFileSync(macOSCommandFolderConfigPath, "utf8")
|
||||
);
|
||||
return getMacOSCommandLauncher(saved.folder) ? path.resolve(saved.folder) : "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function detectMacOSCommandFolder() {
|
||||
const savedFolder = readSavedMacOSCommandFolder();
|
||||
if (savedFolder) {
|
||||
return savedFolder;
|
||||
}
|
||||
if (process.platform !== "darwin" || !app.isPackaged) {
|
||||
return "";
|
||||
}
|
||||
// This resolves to the directory containing EasySpider.app during a
|
||||
// normal launch. Under App Translocation it resolves to .../d, which
|
||||
// does not contain the portable executor and therefore fails validation.
|
||||
const appBundlePath = path.resolve(process.resourcesPath, "../..");
|
||||
const candidate = path.dirname(appBundlePath);
|
||||
return getMacOSCommandLauncher(candidate) ? candidate : "";
|
||||
}
|
||||
|
||||
function saveMacOSCommandFolder(folder) {
|
||||
const absoluteFolder = path.resolve(folder);
|
||||
fs.writeFileSync(
|
||||
macOSCommandFolderConfigPath,
|
||||
JSON.stringify({folder: absoluteFolder}, null, 2)
|
||||
);
|
||||
return absoluteFolder;
|
||||
}
|
||||
|
||||
if (config.debug) {
|
||||
let logPath = "info.log";
|
||||
let logFile = fs.createWriteStream(logPath, {flags: "a"});
|
||||
@@ -1126,7 +1184,19 @@ async function beginInvoke(msg, ws) {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
config_folder: task_server.getDir() + "/",
|
||||
easyspider_location: task_server.getEasySpiderLocation(),
|
||||
// Never expose an App Translocation directory as a runnable
|
||||
// command-line location. macOS uses a validated portable
|
||||
// release folder instead.
|
||||
easyspider_location:
|
||||
process.platform === "darwin"
|
||||
? detectMacOSCommandFolder()
|
||||
: task_server.getEasySpiderLocation(),
|
||||
macos_command_folder:
|
||||
process.platform === "darwin" ? detectMacOSCommandFolder() : "",
|
||||
macos_command_launcher:
|
||||
process.platform === "darwin"
|
||||
? getMacOSCommandLauncher(detectMacOSCommandFolder())
|
||||
: "",
|
||||
execution_started,
|
||||
})
|
||||
);
|
||||
@@ -1155,6 +1225,59 @@ async function beginInvoke(msg, ws) {
|
||||
} catch {
|
||||
console.log("Cannot get Cookies");
|
||||
}
|
||||
} else if (msg.type == 8) {
|
||||
if (process.platform !== "darwin") {
|
||||
ws.send(JSON.stringify({
|
||||
response_type: "macos_command_folder",
|
||||
canceled: true,
|
||||
error: "The portable execution folder is only used on macOS.",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
const currentFolder = detectMacOSCommandFolder();
|
||||
const parentWindow =
|
||||
invoke_window && !invoke_window.isDestroyed()
|
||||
? invoke_window
|
||||
: mainWindow;
|
||||
const selection = await dialog.showOpenDialog(parentWindow, {
|
||||
title:
|
||||
language === "zh"
|
||||
? "选择 EasySpider_MacOS 发布文件夹"
|
||||
: "Select the EasySpider_MacOS release folder",
|
||||
defaultPath: currentFolder || app.getPath("downloads"),
|
||||
properties: ["openDirectory"],
|
||||
message:
|
||||
language === "zh"
|
||||
? "请选择同时包含 EasySpider.app 和 easyspider_executestage 的文件夹"
|
||||
: "Select the folder containing EasySpider.app and easyspider_executestage",
|
||||
});
|
||||
if (selection.canceled || selection.filePaths.length === 0) {
|
||||
ws.send(JSON.stringify({
|
||||
response_type: "macos_command_folder",
|
||||
canceled: true,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
const selectedFolder = path.resolve(selection.filePaths[0]);
|
||||
const launcher = getMacOSCommandLauncher(selectedFolder);
|
||||
if (!launcher) {
|
||||
ws.send(JSON.stringify({
|
||||
response_type: "macos_command_folder",
|
||||
canceled: false,
|
||||
error:
|
||||
language === "zh"
|
||||
? "所选文件夹必须同时包含 EasySpider.app 和 easyspider_executestage。"
|
||||
: "The selected folder must contain both EasySpider.app and easyspider_executestage.",
|
||||
}));
|
||||
return;
|
||||
}
|
||||
saveMacOSCommandFolder(selectedFolder);
|
||||
ws.send(JSON.stringify({
|
||||
response_type: "macos_command_folder",
|
||||
canceled: false,
|
||||
macos_command_folder: selectedFolder,
|
||||
macos_command_launcher: launcher,
|
||||
}));
|
||||
} else if (msg.type == 30) {
|
||||
send_message_to_browser(
|
||||
JSON.stringify({
|
||||
|
||||
@@ -50,6 +50,7 @@ rm -rf "$STAGE_DIR/Code" "$STAGE_DIR/Sample Tasks" "$STAGE_DIR/Data" \
|
||||
rm -f "$STAGE_DIR/config.json" "$STAGE_DIR/mysql_config.json"
|
||||
mkdir -p "$STAGE_DIR/Code" "$STAGE_DIR/Sample Tasks" "$STAGE_DIR/Data" \
|
||||
"$STAGE_DIR/execution_instances"
|
||||
cp "$SCRIPT_DIR/execute_macos.sh" "$STAGE_DIR/execute_macos.sh"
|
||||
cp "$REPO_ROOT/ExecuteStage"/*.py "$STAGE_DIR/Code/"
|
||||
cp "$REPO_ROOT/ExecuteStage/requirements.txt" "$STAGE_DIR/Code/"
|
||||
cp "$REPO_ROOT/ExecuteStage/Readme.md" "$STAGE_DIR/Code/"
|
||||
|
||||
@@ -92,8 +92,17 @@
|
||||
<label><a href="https://github.com/NaiboWang/EasySpider/wiki/Argument-Instruction"
|
||||
target="_blank">{{`Click Here~点击这里` | lang}}</a> {{`Here to see argument instruction.~这里查看参数配置说明。` | lang}}</label>
|
||||
<label v-if="OS=='MacOS'">{{`对于MacOS系统,EasySpider提供了两个不同的执行程序,分别为easyspider_executestage和easyspider_executestage_full,前者执行时加载速度较快,并提供了除OCR识别和数据去重以外的全部功能;后者则提供了包括OCR识别和数据去重在内的全部功能,但运行时加载速度较慢,需要等待2-10分钟才能执行程序,请根据自己的需求选择执行哪个程序。~For MacOS system, EasySpider provides two different execution programs, 'easyspider_executestage' and 'easyspider_executestage_full', the former loads faster when executing, and provides all functions except OCR recognition and data deduplication; the latter provides all functions including OCR recognition and data deduplication, but the loading speed is slower when running, and it takes 2-10 minutes to wait for the program to execute, please choose which program to execute according to your needs.` | lang}}</label>
|
||||
<label>{{ `Please open a terminal (For Windows, please use PowerShell instead of CMD), go to EasySpider's folder, and then copy (Command/Ctrl + c) the following command to run the task (EasySpider can quit when executing command for ease of timed execution, and you can set --read_type to "remote" for remote execution):~请在EasySpider目录下打开命令行工具Terminal (Windows请使用PowerShell而不是CMD),然后复制(Command/Ctrl + c)和运行以下命令以执行任务(执行命令时可以退出EasySpider以方便定时执行,如需要远程调用则需要将--read_type设置为remote并设置远程地址):` | lang }}</label>
|
||||
<textarea class="form-control" style="height:150px">cd {{easyspider_location}}
|
||||
<label v-if="OS=='MacOS'">{{ `Copy the following command into Terminal. The command uses the real EasySpider_MacOS release folder selected below and does not depend on an App Translocation path. You may quit EasySpider after the execution instance has been generated.~请将以下命令复制到Terminal运行。该命令使用下方选择的真实EasySpider_MacOS发布文件夹,不依赖App Translocation临时路径;生成执行实例后可以退出EasySpider。` | lang }}</label>
|
||||
<label v-else>{{ `Please open a terminal (For Windows, please use PowerShell instead of CMD), go to EasySpider's folder, and then copy (Command/Ctrl + c) the following command to run the task (EasySpider can quit when executing command for ease of timed execution, and you can set --read_type to "remote" for remote execution):~请在EasySpider目录下打开命令行工具Terminal (Windows请使用PowerShell而不是CMD),然后复制(Command/Ctrl + c)和运行以下命令以执行任务(执行命令时可以退出EasySpider以方便定时执行,如需要远程调用则需要将--read_type设置为remote并设置远程地址):` | lang }}</label>
|
||||
<div v-if="OS=='MacOS'" style="margin: 8px 0 10px 0;">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm"
|
||||
v-on:click="selectMacOSCommandFolder">{{ `Select/change EasySpider_MacOS folder~选择或更改EasySpider_MacOS文件夹` | lang }}</button>
|
||||
<div style="margin-top: 6px; word-break: break-all;">
|
||||
{{macos_command_folder}}
|
||||
</div>
|
||||
</div>
|
||||
<textarea v-if="OS=='MacOS'" class="form-control" style="height:170px" readonly>{{macos_command_line}}</textarea>
|
||||
<textarea v-else class="form-control" style="height:150px">cd {{easyspider_location}}
|
||||
{{command}} --config_folder "{{config_folder}}" --headless 0 --read_type local --config_file_name config.json --saved_file_name </textarea>
|
||||
</div>
|
||||
<!-- <div class="modal-footer">
|
||||
@@ -349,6 +358,10 @@
|
||||
easyspider_location: "",
|
||||
mysql_config_path: "",
|
||||
executionStarted: false,
|
||||
macos_command_folder: "",
|
||||
macos_command_launcher: "",
|
||||
macos_command_line: "",
|
||||
showCommandAfterFolderSelection: false,
|
||||
OS: "Windows",
|
||||
}, mounted() {
|
||||
$.get(this.backEndAddressServiceWrapper + "/getConfig", function (result) {
|
||||
@@ -398,6 +411,16 @@
|
||||
},
|
||||
readFromExcel: function () {
|
||||
$('#excelModal').modal('show');
|
||||
}, selectMacOSCommandFolder: function () {
|
||||
this.showCommandAfterFolderSelection = true;
|
||||
ws.send(JSON.stringify({type: 8}));
|
||||
}, showMacOSCommandDialog: function () {
|
||||
changeCommand();
|
||||
if (this.macos_command_launcher !== "") {
|
||||
$('#myModal').modal('show');
|
||||
} else {
|
||||
this.selectMacOSCommandFolder();
|
||||
}
|
||||
}, submitFile: function () {
|
||||
let form_data = new FormData();
|
||||
this.file = $('#excelFile').prop('files')[0];
|
||||
@@ -522,8 +545,12 @@
|
||||
}
|
||||
};
|
||||
ws.send(JSON.stringify(message));
|
||||
changeCommand();
|
||||
$('#myModal').modal('show');
|
||||
if (detectOperatingSystemAndArch().OS == 'MacOS') {
|
||||
this.showMacOSCommandDialog();
|
||||
} else {
|
||||
changeCommand();
|
||||
$('#myModal').modal('show');
|
||||
}
|
||||
// }
|
||||
},
|
||||
remoteExecute: function () {
|
||||
@@ -572,9 +599,9 @@
|
||||
// command dialog used by older packages.
|
||||
setTimeout(function () {
|
||||
if (!app.$data.executionStarted) {
|
||||
$('#myModal').modal('show');
|
||||
app.showMacOSCommandDialog();
|
||||
}
|
||||
}, 250);
|
||||
}, 1000);
|
||||
}
|
||||
// });
|
||||
});
|
||||
@@ -597,16 +624,29 @@
|
||||
} else if (systemInfo.OS == 'Linux') {
|
||||
app.$data.command = "./EasySpider/resources/app/chrome_linux64/easyspider_executestage --ids '[" + app.$data.ID.toString() + "]' --user_data " + (app.$data.with_user_data ? "1" : "0") + " --server_address " + app.$data.backEndAddressServiceWrapper;
|
||||
} else if (systemInfo.OS == 'MacOS') {
|
||||
if (getUrlParam("lang") == "zh") {
|
||||
app.$data.easyspider_location = "你的EasySpider文件夹,如:cd /Users/" + app.$data.config_folder.split("/")[2] + "/Downloads/EasySpider_MacOS";
|
||||
if (app.$data.macos_command_launcher !== "") {
|
||||
app.$data.macos_command_line =
|
||||
"cd " + quotePOSIXShell(app.$data.macos_command_folder) + "\n" +
|
||||
quotePOSIXShell(app.$data.macos_command_launcher) +
|
||||
" --ids " + quotePOSIXShell("[" + app.$data.ID.toString() + "]") +
|
||||
" --user_data " + (app.$data.with_user_data ? "1" : "0") +
|
||||
" --server_address " + quotePOSIXShell(app.$data.backEndAddressServiceWrapper) +
|
||||
" --config_folder " + quotePOSIXShell(app.$data.config_folder) +
|
||||
" --headless 0 --read_type local" +
|
||||
" --config_file_name config.json --saved_file_name ''";
|
||||
} else {
|
||||
app.$data.easyspider_location = "Your EasySpider folder, such as: cd /Users/" + app.$data.config_folder.split("/")[2] + "/Downloads/EasySpider_MacOS";
|
||||
app.$data.macos_command_line = getUrlParam("lang") == "zh"
|
||||
? "请先选择包含 EasySpider.app 和 easyspider_executestage 的 EasySpider_MacOS 文件夹。"
|
||||
: "Select the EasySpider_MacOS folder containing EasySpider.app and easyspider_executestage first.";
|
||||
}
|
||||
app.$data.command = "./easyspider_executestage --ids '[" + app.$data.ID.toString() + "]' --user_data " + (app.$data.with_user_data ? "1" : "0") + " --server_address " + app.$data.backEndAddressServiceWrapper;
|
||||
}
|
||||
// });
|
||||
}
|
||||
|
||||
function quotePOSIXShell(value) {
|
||||
return "'" + String(value).replaceAll("'", "'\"'\"'") + "'";
|
||||
}
|
||||
|
||||
$.get(app.$data.backEndAddressServiceWrapper + "/queryTask?id=" + sId, function (result) {
|
||||
app.$data.task = result;
|
||||
app.$data.show = true;
|
||||
@@ -636,12 +676,38 @@
|
||||
};
|
||||
ws.onmessage = function (message) {
|
||||
message = JSON.parse(message.data);
|
||||
if (message.response_type === "macos_command_folder") {
|
||||
if (message.error) {
|
||||
alert(message.error);
|
||||
app.$data.showCommandAfterFolderSelection = false;
|
||||
return;
|
||||
}
|
||||
if (message.canceled) {
|
||||
app.$data.showCommandAfterFolderSelection = false;
|
||||
return;
|
||||
}
|
||||
app.$data.macos_command_folder = message.macos_command_folder;
|
||||
app.$data.macos_command_launcher = message.macos_command_launcher;
|
||||
changeCommand();
|
||||
if (app.$data.showCommandAfterFolderSelection) {
|
||||
app.$data.showCommandAfterFolderSelection = false;
|
||||
$('#myModal').modal('show');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (message.config_folder) {
|
||||
app.$data.config_folder = message.config_folder.replaceAll("\\", "/");
|
||||
}
|
||||
if (message.easyspider_location) {
|
||||
if (message.macos_command_folder) {
|
||||
app.$data.macos_command_folder = message.macos_command_folder;
|
||||
}
|
||||
if (message.macos_command_launcher) {
|
||||
app.$data.macos_command_launcher = message.macos_command_launcher;
|
||||
}
|
||||
if (message.easyspider_location && detectOperatingSystemAndArch().OS != 'MacOS') {
|
||||
app.$data.easyspider_location = message.easyspider_location.replace("/EasySpider.app/", "");
|
||||
}
|
||||
changeCommand();
|
||||
app.$data.executionStarted = message.execution_started === true;
|
||||
}
|
||||
ws.onclose = function () {
|
||||
|
||||
Reference in New Issue
Block a user