From 99151be489224736e78fcf92475ebbc44b6b09b3 Mon Sep 17 00:00:00 2001 From: --global Date: Wed, 24 Jul 2024 10:19:43 -0700 Subject: [PATCH 1/2] Squashed 'src/SfsClient/sfs-client/' changes from ff315ecf..6ab78af6 6ab78af6 Bump curl from 8.4.0 to 8.8.0 (#205) 14b2b422 Tool: adding a way to save output to a json file (#204) 84a6567e Forcing faster timeout on timeout test (#202) 3cbd0170 Dependabot: ignoring patch updates for pip dependencies (#200) d03c887f Bump clang-format from 18.1.4 to 18.1.5 (#198) git-subtree-dir: src/SfsClient/sfs-client git-subtree-split: 6ab78af61bc859461ea8298786d87f24b49e3ec2 --- .github/dependabot.yml | 4 + cgmanifest.json | 6 +- .../details/CurlConnectionTests.cpp | 16 +-- client/tests/util/TestHelper.cpp | 6 +- .../IntegrationDOClient.cpp | 3 +- samples/tool/SFSClientTool.cpp | 127 ++++++++++++++---- scripts/pip.requirements.txt | 2 +- vcpkg.json | 2 +- 8 files changed, 122 insertions(+), 44 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8e742a7932..c64b5ab54b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,3 +17,7 @@ updates: directory: "/" schedule: interval: "weekly" + ignore: + # Ignore patch updates for all pip dependencies + - dependency-name: "*" + update-types: ["version-update:semver-patch"] diff --git a/cgmanifest.json b/cgmanifest.json index 24cd480b66..38f44bc5a7 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -37,7 +37,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/curl/curl", - "commitHash": "d755a5f7c009dd63a61b2c745180d8ba937cbfeb" + "commitHash": "fd567d4f06857f4fc8e2f64ea727b1318f76ad33" } }, "developmentDependency": false @@ -56,7 +56,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/curl/curl", - "commitHash": "d755a5f7c009dd63a61b2c745180d8ba937cbfeb" + "commitHash": "fd567d4f06857f4fc8e2f64ea727b1318f76ad33" } } ] @@ -75,7 +75,7 @@ "type": "git", "git": { "repositoryUrl": "https://github.com/curl/curl", - "commitHash": "d755a5f7c009dd63a61b2c745180d8ba937cbfeb" + "commitHash": "fd567d4f06857f4fc8e2f64ea727b1318f76ad33" } } ] diff --git a/client/tests/functional/details/CurlConnectionTests.cpp b/client/tests/functional/details/CurlConnectionTests.cpp index c835fc8b13..1d8a21ad68 100644 --- a/client/tests/functional/details/CurlConnectionTests.cpp +++ b/client/tests/functional/details/CurlConnectionTests.cpp @@ -45,15 +45,15 @@ class CurlConnectionTimeout : public CurlConnection std::string Get(const std::string& url) override { - // Timeout within 100ms - curl_easy_setopt(m_handle, CURLOPT_TIMEOUT_MS, 100L); + // Timeout within 1ms + curl_easy_setopt(m_handle, CURLOPT_TIMEOUT_MS, 1L); return CurlConnection::Get(url); } std::string Post(const std::string& url, const std::string& data) override { - // Timeout within 100ms - curl_easy_setopt(m_handle, CURLOPT_TIMEOUT_MS, 100L); + // Timeout within 1ms + curl_easy_setopt(m_handle, CURLOPT_TIMEOUT_MS, 1L); return CurlConnection::Post(url, data); } }; @@ -316,11 +316,11 @@ TEST("Testing a response over the limit fails the operation") json body = {{{"TargetingAttributes", {}}, {"Product", largeProductName}}}; REQUIRE_NOTHROW(connection->Post(url, body.dump())); - // Over limit fails + // Going over the limit fails with a message like "client returned ERROR on write of 16384 bytes" body[0]["Product"] = overLimitProductName; - REQUIRE_THROWS_CODE_MSG(connection->Post(url, body.dump()), - ConnectionUnexpectedError, - "Failure writing output to destination"); + REQUIRE_THROWS_CODE_MSG_MATCHES(connection->Post(url, body.dump()), + ConnectionUnexpectedError, + Catch::Matchers::ContainsSubstring("client returned ERROR on write of")); } TEST("Testing MS-CV is sent to server") diff --git a/client/tests/util/TestHelper.cpp b/client/tests/util/TestHelper.cpp index c676f6485e..d569796323 100644 --- a/client/tests/util/TestHelper.cpp +++ b/client/tests/util/TestHelper.cpp @@ -43,7 +43,7 @@ std::string TimestampToString(std::chrono::time_point void SFS::test::LogCallbackToTest(const SFS::LogData& logData) { std::lock_guard guard(s_logMutex); - UNSCOPED_INFO("Log: " << TimestampToString(logData.time) << " [" << ToString(logData.severity) << "]" << " " - << std::filesystem::path(logData.file).filename().string() << ":" << logData.line << " " - << logData.message); + UNSCOPED_INFO("Log: " << TimestampToString(logData.time) << " [" << ToString(logData.severity) << "]" + << " " << std::filesystem::path(logData.file).filename().string() << ":" << logData.line + << " " << logData.message); } diff --git a/samples/integration-do-client/IntegrationDOClient.cpp b/samples/integration-do-client/IntegrationDOClient.cpp index c22f954a82..7fb6ce66ac 100644 --- a/samples/integration-do-client/IntegrationDOClient.cpp +++ b/samples/integration-do-client/IntegrationDOClient.cpp @@ -171,7 +171,8 @@ std::string TimestampToString(std::chrono::time_point void LoggingCallback(const SFS::LogData& logData) { std::cout << c_darkGreyStart << "Log: " << TimestampToString(logData.time) << " [" << ToString(logData.severity) - << "]" << " " << std::filesystem::path(logData.file).filename().string() << ":" << logData.line << " " + << "]" + << " " << std::filesystem::path(logData.file).filename().string() << ":" << logData.line << " " << logData.message << c_colorEnd << std::endl; } diff --git a/samples/tool/SFSClientTool.cpp b/samples/tool/SFSClientTool.cpp index 876b4c3e28..b784c94611 100644 --- a/samples/tool/SFSClientTool.cpp +++ b/samples/tool/SFSClientTool.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ void DisplayUsage() << "Options:" << std::endl << " -h, --help\t\t\tDisplay this help message" << std::endl << " -v, --version\t\t\tDisplay the library version" << std::endl + << " -o, --outputFile \t\tWhen specified, the JSON output is saved to this file" << std::endl << " --isApp\t\t\tIndicates the specific product is an App" << std::endl << " --instanceId \t\tA custom SFS instance ID" << std::endl << " --namespace \t\tA custom SFS namespace" << std::endl @@ -87,6 +89,12 @@ struct Settings std::string instanceId; std::string nameSpace; std::string customUrl; + std::string outputFile; + + bool ShouldOutputToFile() const + { + return !outputFile.empty(); + } }; void ParseArguments(const std::vector& args, Settings& settings) @@ -126,6 +134,11 @@ void ParseArguments(const std::vector& args, Settings& setting { settings.displayVersion = true; } + else if (matchArg(args[i], "-o", "--outputFile")) + { + validateArg(i, "outputFile", settings.outputFile); + settings.outputFile = args[++i]; + } else if (matchLongArg(args[i], "--isApp")) { settings.isApp = true; @@ -197,16 +210,8 @@ constexpr std::string_view ToString(Architecture type) return ""; } -void DisplayResults(const std::vector& contents) +json ContentsToJson(const std::vector& contents) { - if (contents.empty()) - { - PrintError("No results found"); - return; - } - - PrintLog("Content found:"); - json out = json::array(); for (const auto& content : contents) { @@ -233,7 +238,7 @@ void DisplayResults(const std::vector& contents) out.push_back(j); } - PrintLog(out.dump(2 /*indent*/)); + return out; } json AppFileToJson(const AppFile& file) @@ -265,16 +270,8 @@ json AppFileToJson(const AppFile& file) return fileJson; } -void DisplayResults(const std::vector& contents) +json AppContentsToJson(const std::vector& contents) { - if (contents.empty()) - { - std::cout << "No results found." << std::endl; - return; - } - - PrintLog("Content found:"); - json out = json::array(); for (const auto& content : contents) { @@ -309,7 +306,50 @@ void DisplayResults(const std::vector& contents) out.push_back(j); } - PrintLog(out.dump(2 /*indent*/)); + return out; +} + +void DisplayResults(const json& results) +{ + if (results.empty()) + { + return; + } + + PrintLog("Content found:"); + PrintLog(results.dump(2 /*indent*/)); +} + +Result JSONToFile(const json& results, const std::string& filename) +{ + if (results.empty()) + { + return Result::Unexpected; + } + + const std::filesystem::path filepath = std::filesystem::absolute(filename); + try + { + std::filesystem::create_directories(filepath.parent_path()); + } + catch (const std::exception& e) + { + PrintError("Failed to create parent directories for filepath: " + filepath.string() + ". Error: " + e.what()); + return Result::Unexpected; + } + + std::ofstream file(filepath, std::ios::out | std::ios::trunc); + if (!file.is_open()) + { + PrintError("Failed to open file for writing: " + filename); + return Result::Unexpected; + } + + file << results.dump(2 /*indent*/); + + PrintLog("Content found. Saved to file " + filepath.string()); + + return Result::Success; } void LogResult(const SFS::Result& result) @@ -348,7 +388,8 @@ std::string TimestampToString(std::chrono::time_point void LoggingCallback(const SFS::LogData& logData) { std::cout << c_darkGreyStart << "Log: " << TimestampToString(logData.time) << " [" << ToString(logData.severity) - << "]" << " " << std::filesystem::path(logData.file).filename().string() << ":" << logData.line << " " + << "]" + << " " << std::filesystem::path(logData.file).filename().string() << ":" << logData.line << " " << logData.message << c_colorEnd << std::endl; } @@ -365,11 +406,12 @@ bool SetEnv(const std::string& varName, const std::string& value) #endif } -Result GetLatestDownloadInfo(const SFSClient& sfsClient, const Settings& settings) +Result GetLatestDownloadInfo(const SFSClient& sfsClient, const Settings& settings, json& out) { PrintLog("Getting latest download info for product: " + settings.product); RequestParams params; params.productRequests = {{settings.product, {}}}; + if (settings.isApp) { std::vector appContents; @@ -381,14 +423,12 @@ Result GetLatestDownloadInfo(const SFSClient& sfsClient, const Settings& setting return result.GetCode(); } - // Display results - DisplayResults(appContents); + out = AppContentsToJson(appContents); } else { std::vector contents; auto result = sfsClient.GetLatestDownloadInfo(params, contents); - if (!result) { PrintError("Failed to get latest download info."); @@ -396,8 +436,33 @@ Result GetLatestDownloadInfo(const SFSClient& sfsClient, const Settings& setting return result.GetCode(); } - // Display results + out = ContentsToJson(contents); + } + + if (out.empty()) + { + PrintError("No results found."); + return Result::Unexpected; + } + + return Result::Success; +} + +Result HandleJSONContents(const Settings& settings, const json& contents) +{ + if (settings.ShouldOutputToFile()) + { + auto result = JSONToFile(contents, settings.outputFile); + if (!result) + { + PrintError("Failed to save to file."); + return result.GetCode(); + } + } + else + { DisplayResults(contents); + return Result::Success; } return Result::Success; @@ -464,7 +529,15 @@ int main(int argc, char* argv[]) } // Perform operations using SFSClient - result = GetLatestDownloadInfo(*sfsClient, settings); + json contents; + result = GetLatestDownloadInfo(*sfsClient, settings, contents); + if (!result) + { + LogResult(result); + return result.GetCode(); + } + + result = HandleJSONContents(settings, contents); if (!result) { LogResult(result); diff --git a/scripts/pip.requirements.txt b/scripts/pip.requirements.txt index 24d7184bf9..377f1e824f 100644 --- a/scripts/pip.requirements.txt +++ b/scripts/pip.requirements.txt @@ -1,2 +1,2 @@ -clang-format==18.1.4 +clang-format==18.1.5 cmake-format==0.6.13 \ No newline at end of file diff --git a/vcpkg.json b/vcpkg.json index 40450b89e9..688aa6126f 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -44,7 +44,7 @@ }, { "name": "curl", - "version": "8.4.0" + "version": "8.8.0" }, { "name": "nlohmann-json", From dec90d69a56a6bd07ef3881c39edb774fdb55d0d Mon Sep 17 00:00:00 2001 From: --global Date: Wed, 24 Jul 2024 10:22:25 -0700 Subject: [PATCH 2/2] update README --- src/SfsClient/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SfsClient/readme.md b/src/SfsClient/readme.md index caf768187a..d9662edfea 100644 --- a/src/SfsClient/readme.md +++ b/src/SfsClient/readme.md @@ -1,9 +1,9 @@ ## SfsClient -Do not change code under the sfs-client directory; it contains sfs-client source code from commit [ff315ec](https://github.com/microsoft/sfs-client/commits/ff315ec). +Do not change code under the sfs-client directory; it contains sfs-client source code from commit [6ab78af](https://github.com/microsoft/sfs-client/commits/6ab78af). It is created using git subtree command: ``` - git subtree add --prefix=src/SfsClient/sfs-client https://github.com/microsoft/sfs-client.git cf18b357f43aa9bbaba7d8b3b3774b39140aa00f --squash + git subtree add --prefix=src/SfsClient/sfs-client https://github.com/microsoft/sfs-client.git 6ab78af61bc859461ea8298786d87f24b49e3ec2 --squash ``` ### Update