From f2a650097d2796c7ced664005457505610e2fecd Mon Sep 17 00:00:00 2001 From: zyr17 Date: Sat, 30 Mar 2024 00:43:56 +0800 Subject: [PATCH] Merge branch 'test-macos' --- .github/workflows/macos.yml | 16 +++++---- .github/workflows/test_macos_PA.yml | 53 +++++++++++++++++++++++++++++ main.js | 14 ++++++-- src/algo.cpp | 21 ++++++++++-- src/analyzer.cpp | 3 ++ src/header.cpp | 1 + src/header.h | 2 ++ src/main.cpp | 47 ++++++++++++++++++++++++- src/main.h | 9 +++++ 9 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/test_macos_PA.yml diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index f81f0ac..d132a5e 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -39,25 +39,27 @@ jobs: run: | cp -r dist/MajsoulPaipuCrawler-darwin-x64 result cp bin/release/PaipuAnalyzer result/ - mkdir result/data + cp bin/release/PaipuAnalyzer ./ cp config.json result/ cp PAADData.json result/ cp doc/README.txt result/ cp doc/release-notes.txt result/ - cp -r i18n/ result/ - mv result MajsoulPaipuAnalyzer-macos-x64 + cp -r i18n result/ + mv result MajsoulPaipuAnalyzer-macos +# ln -s "~/Library/Application Support/MajsoulPaipuAnalyzer/data" result/data - name: archive run: | brew install p7zip - 7z a MajsoulPaipuAnalyzer-macos-x64.7z MajsoulPaipuAnalyzer-macos-x64 -m0=LZMA2 -mmt + 7z a MajsoulPaipuAnalyzer-macos.7z MajsoulPaipuAnalyzer-macos -m0=LZMA2 -mmt + 7z a PaipuAnalyzer.zip PaipuAnalyzer - uses: actions/upload-artifact@v2 with: - name: MajsoulPaipuAnalyzer-macos-x64.7z - path: MajsoulPaipuAnalyzer-macos-x64.7z + name: MajsoulPaipuAnalyzer-macos.7z + path: MajsoulPaipuAnalyzer-macos.7z - uses: actions/upload-artifact@v2 with: name: PaipuAnalyzer - path: bin/release/PaipuAnalyzer + path: PaipuAnalyzer.zip - name: Upload to release if: github.event_name != 'workflow_dispatch' run: | diff --git a/.github/workflows/test_macos_PA.yml b/.github/workflows/test_macos_PA.yml new file mode 100644 index 0000000..eb35bb9 --- /dev/null +++ b/.github/workflows/test_macos_PA.yml @@ -0,0 +1,53 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: MacOS PaipuAnalyzer only test CI + +on: + push: + workflow_dispatch: + +jobs: + build: + runs-on: macOS-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: npm + run: | + npm ci + npm run-script package-darwin + - name: cmake + run: | + git submodule update --init --recursive + mkdir bin + mkdir bin/release + cd bin/release + cmake ../.. -DCMAKE_BUILD_TYPE=Debug + make -j + - name: collect + run: | + mkdir result + cp bin/release/PaipuAnalyzer result/ + cp config.json result/ + cp PAADData.json result/ + cp -r i18n result/ + ln -s "~/Library/Application Support/MajsoulPaipuAnalyzer/data" result/data + ls -l result + mv result PaipuAnalyzer + - name: archive + run: | + brew install p7zip + 7z a PaipuAnalyzer.zip PaipuAnalyzer + - uses: actions/upload-artifact@v2 + with: + name: PaipuAnalyzer + path: PaipuAnalyzer.zip diff --git a/main.js b/main.js index a8bacd1..faa36e9 100644 --- a/main.js +++ b/main.js @@ -24,13 +24,21 @@ let nowgamedata = null; var paipuversion = undefined; var appPath = app.getAppPath(); -app.setPath('userData', appPath + '/UserData'); let dataPath = 'data/'; const paipu_bk_folder_name = 'old_paipu_backup'; const metadata_query_step = 100; // How many uuids to query once. In test, 850 is safe and 1500 will be banned. const metadata_fetch_delay = 1000; // ms to delay after fetching metadata -if (InMacOS) dataPath = __dirname + '/../../../../' + dataPath; +if (InMacOS) { + // let cwd = app.getPath('exe').replace(/\/[^\/]+$/, ''); + let cwd = path(process.env.HOME, "Library", "Application Support", "MajsoulPaipuAnalyzer"); + console.log('current dir: ' + cwd); + dataPath = cwd + '/' + dataPath; + if (!fs.existsSync(dataPath)) fs.mkdirSync(dataPath, { recursive: true }); +} +else { + app.setPath('userData', appPath + '/UserData'); +} //app.disableHardwareAcceleration(); @@ -886,7 +894,7 @@ const ready = () => { //browseWindow.maximize(); function readgamedata(userid, paipugamedata, callback){ let root = path(dataPath, 'majsoul', userid.toString()); - if (!fs.existsSync(dataPath)) fs.mkdirSync(dataPath); + if (!fs.existsSync(dataPath)) fs.mkdirSync(dataPath, { recursive: true }); if (!fs.existsSync(path(dataPath, 'majsoul'))) fs.mkdirSync(path(dataPath, 'majsoul')); if (!fs.existsSync(root)) fs.mkdirSync(root); let ppp = path(root, 'raw'); diff --git a/src/algo.cpp b/src/algo.cpp index 0eda4eb..95aa090 100644 --- a/src/algo.cpp +++ b/src/algo.cpp @@ -333,13 +333,28 @@ void testshanten(){ } int Access(const char *filename, int mode){ - return access((Header::datafolderprefix + filename).c_str(), mode); + std::string full_filename = Header::datafolderprefix + filename; + #ifdef __APPLE__ + // 如果是访问data,apple需要重设路径到Header::appledatafolderprefix + std::string filename_string = filename; + if (filename_string.find("data/") == 0) + full_filename = Header::appledatafolderprefix + filename; + #endif + // std::cout << "Access " << full_filename << std::endl; + return access(full_filename.c_str(), mode); } CJsonObject ReadJSON(const std::string &filename){ std::string jsonstr; char *buffer = new char[JSONBUFFERSIZE]; - auto f = fopen((Header::datafolderprefix + filename).c_str(), "r"); + std::string full_filename = Header::datafolderprefix + filename; + #ifdef __APPLE__ + // 如果是访问data,apple需要重设路径到Header::appledatafolderprefix + if (filename.find("data/") == 0) + full_filename = Header::appledatafolderprefix + filename; + #endif + // std::cout << "ReadJSON " << full_filename << std::endl; + auto f = fopen(full_filename.c_str(), "r"); for (; ; ){ int length = fread(buffer, 1, JSONBUFFERSIZE - 1, f); buffer[length] = '\0'; @@ -354,6 +369,7 @@ CJsonObject ReadJSON(const std::string &filename){ } std::vector ReadLineJSON(const std::string &filename, const std::string &prefix, const std::string &suffix){ + // TODO: Cannot work on MacOS! currently not used by MacOS, so not fixed. auto f = fopen((Header::datafolderprefix + filename).c_str(), "r"); std::vector res; for (; ; ){ @@ -370,6 +386,7 @@ std::vector ReadLineJSON(const std::string &filename, const std::st } void WriteJSON(const std::string &filename, const CJsonObject json){ + // TODO: Cannot work on MacOS! currently not used by MacOS, so not fixed. FILE *f = fopen((Header::datafolderprefix + filename).c_str(), "w"); fprintf(f, "%s", json.ToString().c_str()); } diff --git a/src/analyzer.cpp b/src/analyzer.cpp index 86ce0d7..be19101 100644 --- a/src/analyzer.cpp +++ b/src/analyzer.cpp @@ -2076,6 +2076,7 @@ void analyzetenhou(const std::string &dataf, const std::string &source, const st } void analyzemain(const std::string &dataf, const std::string &source, const std::string &id, CJsonObject &config){ + // std::cout << "Go into main" << std::endl; auto &filter = config["filter"]; PaipuAnalyzer pa = PaipuAnalyzer(filter); int paipunum = 0; @@ -2153,7 +2154,9 @@ void analyzemain(const std::string &dataf, const std::string &source, const std: } else{ std::vector paipus; + // std::cout << "Read paipu file: " << dataf + "/" + source + "/" + id + "/paipus.txt" << std::endl; auto paipuarr = Algo::ReadJSON(dataf + "/" + source + "/" + id + "/paipus.txt"); + // std::cout << "Read paipu file success: " << dataf + "/" + source + "/" + id + "/paipus.txt" << std::endl; for (int i = 0; i < paipuarr.GetArraySize(); i ++ ) paipus.push_back(&paipuarr[i]); //int step = paipus.size() - 1; diff --git a/src/header.cpp b/src/header.cpp index 74a82e1..6982e25 100644 --- a/src/header.cpp +++ b/src/header.cpp @@ -3,4 +3,5 @@ namespace Header{ std::string rootfolderprefix = "./"; std::string datafolderprefix = ""; + std::string appledatafolderprefix = "MajsoulPaipuAnalyzer/"; } \ No newline at end of file diff --git a/src/header.h b/src/header.h index 4cc5978..dc8f081 100644 --- a/src/header.h +++ b/src/header.h @@ -52,6 +52,8 @@ namespace Header{ extern std::string rootfolderprefix; //设置读取data时的前缀,从config.json中获得,调试时用于定位数据文件位置。在完成载入时会将rootfolder作为前缀加入。 extern std::string datafolderprefix; + //Apple专用的路径,因为牌谱没有权限存储到本地 + extern std::string appledatafolderprefix; } #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0fcdc32..f8ad686 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,37 @@ #include "main.h" namespace MAIN{ + +#ifdef __APPLE__ + std::string expandTilde(const char* str) { + if (!str) { + std::cout << "Null pointer passed to expandTilde" << std::endl; + throw std::exception(); + } + + glob_t globbuf; + if (glob(str, GLOB_TILDE, nullptr, &globbuf) == 0) { + std::string result(globbuf.gl_pathv[0]); + globfree(&globbuf); + return result; + } else { + std::cout << "Failed to expand tilde" << std::endl; + throw std::exception(); + } + } + + std::string settingsPath(const char* str) { + char path[PATH_MAX]; + auto state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_APPLICATION_SUPPORT, + SYSDIR_DOMAIN_MASK_USER); + if ((state = sysdir_get_next_search_path_enumeration(state, path))) { + return expandTilde(path); + } else { + std::cout << "Failed to get settings folder" << std::endl; + throw std::exception(); + } + } +#endif std::string source, id; CJsonObject config; @@ -19,14 +50,18 @@ namespace MAIN{ } _findclose(findi2); #elif defined(__linux) || defined(__APPLE__) + // std::cout << "try to open: " << dataprefix + "data/" + source << std::endl; DIR *dirptr = opendir((dataprefix + "data/" + source).c_str()); + // std::cout << "open success: " << dataprefix + "data/" + source << std::endl; dirent *entry; while (entry = readdir(dirptr)){ + // std::cout << "entry id: " << entry -> d_name << std::endl; ids.push_back(entry -> d_name); if (*ids.rbegin() == "." || *ids.rbegin() == ".." || *ids.rbegin() == "0") ids.pop_back(); } closedir(dirptr); + // std::cout << "close success: " << dataprefix + "data/" + source << std::endl; #else Out::cout << I18N::get("MAIN", "MACROUNDEFINED") << '\n'; PAUSEEXIT; @@ -60,14 +95,21 @@ namespace MAIN{ return 1; } config.Get("id", id); +#ifdef __APPLE__ + std::vector ids = findid(Header::appledatafolderprefix, source, id); +#else std::vector ids = findid(Header::datafolderprefix, source, id); +#endif + // std::cout << "ID: " << id << std::endl; if (!ids.size()){ Out::cout << I18N::get("MISC", "ERROR") + I18N::get("MAIN", "CANTDATA/SRC/*") + source + I18N::get("MAIN", "CANTDATA/SRC/*AFT") + "\n"; PAUSEEXIT; return 1; } + // std::cout << "Try to print to Out" << std::endl; Out::cout << '\n'; Out::cout << I18N::get("MAIN", "SRC") + I18N::get("MISC", "COLON") + source + "\n"; + // std::cout << "Try to print to Out Success" << std::endl; std::string outputid = id; #ifdef _WIN32 outputid = Algo::UTF82GBK(outputid); @@ -78,7 +120,7 @@ namespace MAIN{ void setrootfolder(){ #ifdef __APPLE__ - //只有macOS需要重新查找设置rootfolder + //只有macOS需要重新查找设置rootfolder,并设置正确的appledatafolderprefix unsigned int bufferSize = 512; std::vector buffer(bufferSize + 1); _NSGetExecutablePath(&buffer[0], &bufferSize); @@ -87,6 +129,8 @@ namespace MAIN{ if (i) s += i; s.erase(s.size() - 13); //删去"PaipuAnalyzer" Header::rootfolderprefix = s; + auto data_path_prefix = settingsPath(Header::appledatafolderprefix.c_str()); + Header::appledatafolderprefix = data_path_prefix + '/' + Header::appledatafolderprefix; #endif } @@ -102,6 +146,7 @@ int main(int argc, char *argv[]){ //Algo::testtenpai(); return 0; auto rcres = readconfig(); + // std::cout << "Read Config Result: " << rcres << std::endl; if (rcres == 1) return 0; if (argc > 1 && argv[1] == std::string("--tenhou-basedata")){ diff --git a/src/main.h b/src/main.h index 5f53b6e..a378df4 100644 --- a/src/main.h +++ b/src/main.h @@ -7,4 +7,13 @@ #include "mdatacompare.h" #include "i18n.h" +#ifdef __APPLE__ +#include // for sysdir_start_search_path_enumeration +#include // for glob needed to expand ~ to user dir +#include // for std::cout +#include // for std::string +#include // for std::exception +#include // for PATH_MAX +#endif + #endif \ No newline at end of file