mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
licenses_cpp: Started writing the licenses file (#170539)
This writes the licenses and associates them with packages. It has simple deduplication. This also adds linux ci tests. Writing the file adds about 7 seconds, now we are at 37s. Too much is getting written now though so that should come down once the output is corrected. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
5994e6174f
commit
3bddd07fa6
@ -268,6 +268,40 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cas_archive": false,
|
||||
"drone_dimensions": [
|
||||
"device_type=none",
|
||||
"os=Linux"
|
||||
],
|
||||
"gclient_variables": {
|
||||
"use_rbe": true
|
||||
},
|
||||
"gn": [
|
||||
"--target-dir",
|
||||
"ci/host_release_licenses",
|
||||
"--runtime-mode",
|
||||
"release",
|
||||
"--no-lto",
|
||||
"--rbe",
|
||||
"--no-goma"
|
||||
],
|
||||
"name": "ci/host_release_licenses",
|
||||
"description": "Runs the license_cpp script.",
|
||||
"ninja": {
|
||||
"config": "ci/host_release_licenses",
|
||||
"targets": [
|
||||
"flutter/tools/licenses_cpp",
|
||||
"flutter/tools/licenses_cpp:licenses_cpp_testrunner"
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"name": "Run license_cpp unittests",
|
||||
"script": "out/ci/host_release_licenses/licenses_cpp_testrunner"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cas_archive": false,
|
||||
"drone_dimensions": [
|
||||
|
||||
@ -4,6 +4,8 @@ source_set("licenses") {
|
||||
"src/catalog.h",
|
||||
"src/comments.cc",
|
||||
"src/comments.h",
|
||||
"src/comments_util.cc",
|
||||
"src/comments_util.h",
|
||||
"src/data.cc",
|
||||
"src/data.h",
|
||||
"src/filter.cc",
|
||||
|
||||
@ -349,9 +349,9 @@ struct yy_trans_info {
|
||||
flex_int32_t yy_verify;
|
||||
flex_int32_t yy_nxt;
|
||||
};
|
||||
static const flex_int16_t yy_accept[27] = {0, 0, 0, 0, 0, 0, 0, 9, 7,
|
||||
7, 1, 7, 4, 4, 6, 6, 0, 1,
|
||||
0, 1, 2, 3, 0, 5, 0, 5, 0};
|
||||
static const flex_int16_t yy_accept[28] = {0, 0, 0, 0, 0, 0, 0, 9, 7, 7,
|
||||
1, 7, 4, 4, 6, 6, 0, 1, 0, 1,
|
||||
2, 3, 0, 5, 0, 2, 5, 0};
|
||||
|
||||
static const YY_CHAR yy_ec[256] = {
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
@ -371,23 +371,23 @@ static const YY_CHAR yy_ec[256] = {
|
||||
|
||||
static const YY_CHAR yy_meta[7] = {0, 1, 1, 2, 1, 1, 3};
|
||||
|
||||
static const flex_int16_t yy_base[34] = {
|
||||
0, 0, 0, 24, 12, 12, 7, 8, 34, 5, 0, 7, 34, 0, 34, 12, 0,
|
||||
0, 0, 0, 34, 34, 0, 0, 0, 0, 34, 18, 21, 24, 27, 2, 30, 0};
|
||||
static const flex_int16_t yy_base[36] = {
|
||||
0, 0, 0, 27, 24, 14, 12, 10, 34, 5, 0, 7, 34, 0, 34, 12, 0, 0,
|
||||
0, 0, 0, 34, 0, 0, 0, 34, 0, 34, 18, 21, 24, 27, 5, 3, 30, 0};
|
||||
|
||||
static const flex_int16_t yy_def[34] = {
|
||||
0, 27, 27, 28, 28, 29, 29, 26, 26, 26, 30, 26, 26, 31, 26, 26, 9,
|
||||
30, 11, 30, 26, 26, 15, 32, 33, 32, 0, 26, 26, 26, 26, 26, 26, 26};
|
||||
static const flex_int16_t yy_def[36] = {
|
||||
0, 28, 28, 29, 29, 30, 30, 27, 27, 27, 31, 27, 27, 32, 27, 27, 9, 31,
|
||||
11, 31, 33, 27, 15, 34, 35, 27, 34, 0, 27, 27, 27, 27, 27, 27, 27, 27};
|
||||
|
||||
static const flex_int16_t yy_nxt[41] = {
|
||||
0, 26, 9, 23, 10, 21, 11, 16, 26, 17, 15, 18, 20, 17,
|
||||
22, 15, 23, 13, 24, 8, 8, 8, 12, 12, 12, 14, 14, 14,
|
||||
19, 13, 19, 25, 26, 25, 7, 26, 26, 26, 26, 26, 26};
|
||||
0, 27, 9, 23, 10, 25, 11, 16, 21, 17, 27, 18, 20, 17,
|
||||
22, 15, 23, 15, 24, 8, 8, 8, 12, 12, 12, 14, 14, 14,
|
||||
19, 13, 19, 26, 13, 26, 7, 27, 27, 27, 27, 27, 27};
|
||||
|
||||
static const flex_int16_t yy_chk[41] = {
|
||||
0, 0, 2, 33, 2, 31, 2, 9, 7, 9, 6, 9, 11, 11,
|
||||
15, 5, 15, 4, 15, 27, 27, 27, 28, 28, 28, 29, 29, 29,
|
||||
30, 3, 30, 32, 0, 32, 26, 26, 26, 26, 26, 26, 26};
|
||||
0, 0, 2, 35, 2, 33, 2, 9, 32, 9, 7, 9, 11, 11,
|
||||
15, 6, 15, 5, 15, 28, 28, 28, 29, 29, 29, 30, 30, 30,
|
||||
31, 4, 31, 34, 3, 34, 27, 27, 27, 27, 27, 27, 27};
|
||||
|
||||
/* The intent behind this definition is that it'll catch
|
||||
* any uses of REJECT which flex missed.
|
||||
@ -409,6 +409,7 @@ static const flex_int16_t yy_chk[41] = {
|
||||
|
||||
#line 20 "comments.l"
|
||||
#include "flutter/tools/licenses_cpp/src/comments.h"
|
||||
#include "flutter/tools/licenses_cpp/src/comments_util.h"
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
@ -420,9 +421,9 @@ struct LexerContext {
|
||||
std::function<void(std::string_view)> callback;
|
||||
std::string buffer;
|
||||
};
|
||||
#line 461 "comments.cc"
|
||||
#line 462 "comments.cc"
|
||||
|
||||
#line 463 "comments.cc"
|
||||
#line 464 "comments.cc"
|
||||
|
||||
#define INITIAL 0
|
||||
#define C_COMMENT 1
|
||||
@ -678,9 +679,9 @@ YY_DECL {
|
||||
}
|
||||
|
||||
{
|
||||
#line 39 "comments.l"
|
||||
#line 40 "comments.l"
|
||||
|
||||
#line 728 "comments.cc"
|
||||
#line 729 "comments.cc"
|
||||
|
||||
while (/*CONSTCOND*/ 1) /* loops until end-of-file is reached */
|
||||
{
|
||||
@ -705,7 +706,7 @@ YY_DECL {
|
||||
}
|
||||
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
|
||||
yy_current_state = (int)yy_def[yy_current_state];
|
||||
if (yy_current_state >= 27)
|
||||
if (yy_current_state >= 28)
|
||||
yy_c = yy_meta[yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
|
||||
@ -734,18 +735,18 @@ YY_DECL {
|
||||
|
||||
case 1:
|
||||
YY_RULE_SETUP
|
||||
#line 40 "comments.l"
|
||||
#line 41 "comments.l"
|
||||
{
|
||||
BEGIN(BLOCK);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext, yyleng);
|
||||
}
|
||||
YY_BREAK
|
||||
case 2:
|
||||
/* rule 2 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 44 "comments.l"
|
||||
#line 45 "comments.l"
|
||||
{
|
||||
BEGIN(C_COMMENT);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
}
|
||||
YY_BREAK
|
||||
|
||||
@ -754,7 +755,6 @@ YY_DECL {
|
||||
#line 50 "comments.l"
|
||||
{
|
||||
BEGIN(INITIAL);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
yyextra->callback(yyextra->buffer);
|
||||
yyextra->buffer.clear();
|
||||
}
|
||||
@ -762,7 +762,7 @@ YY_DECL {
|
||||
case 4:
|
||||
/* rule 4 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 56 "comments.l"
|
||||
#line 55 "comments.l"
|
||||
{
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
}
|
||||
@ -771,9 +771,10 @@ YY_DECL {
|
||||
case 5:
|
||||
/* rule 5 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 62 "comments.l"
|
||||
#line 61 "comments.l"
|
||||
{
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
yyextra->buffer.append("\n", 1);
|
||||
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext + 1, yyleng - 1);
|
||||
}
|
||||
YY_BREAK
|
||||
case 6:
|
||||
@ -799,7 +800,7 @@ YY_DECL {
|
||||
#line 73 "comments.l"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 853 "comments.cc"
|
||||
#line 854 "comments.cc"
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
case YY_STATE_EOF(C_COMMENT):
|
||||
case YY_STATE_EOF(BLOCK):
|
||||
@ -1079,7 +1080,7 @@ static yy_state_type yy_get_previous_state(yyscan_t yyscanner) {
|
||||
}
|
||||
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
|
||||
yy_current_state = (int)yy_def[yy_current_state];
|
||||
if (yy_current_state >= 27)
|
||||
if (yy_current_state >= 28)
|
||||
yy_c = yy_meta[yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
|
||||
@ -1107,11 +1108,11 @@ static yy_state_type yy_try_NUL_trans(yy_state_type yy_current_state,
|
||||
}
|
||||
while (yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state) {
|
||||
yy_current_state = (int)yy_def[yy_current_state];
|
||||
if (yy_current_state >= 27)
|
||||
if (yy_current_state >= 28)
|
||||
yy_c = yy_meta[yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
|
||||
yy_is_jam = (yy_current_state == 26);
|
||||
yy_is_jam = (yy_current_state == 27);
|
||||
|
||||
(void)yyg;
|
||||
return yy_is_jam ? 0 : yy_current_state;
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
%{
|
||||
#include "flutter/tools/licenses_cpp/src/comments.h"
|
||||
#include "flutter/tools/licenses_cpp/src/comments_util.h"
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
@ -39,17 +40,15 @@ COMMENT_START (\/\/|#)
|
||||
%%
|
||||
^[ \t]*{COMMENT_START}[^\n]* {
|
||||
BEGIN(BLOCK);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext, yyleng);
|
||||
}
|
||||
^[ \t]*\/\* {
|
||||
^[ \t]*\/\*[\n]? {
|
||||
BEGIN(C_COMMENT);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
}
|
||||
|
||||
<C_COMMENT>{
|
||||
\*\/ {
|
||||
BEGIN(INITIAL);
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
yyextra->callback(yyextra->buffer);
|
||||
yyextra->buffer.clear();
|
||||
}
|
||||
@ -60,7 +59,8 @@ COMMENT_START (\/\/|#)
|
||||
|
||||
<BLOCK>{
|
||||
\n[ \t]*{COMMENT_START}[^\n]* {
|
||||
yyextra->buffer.append(yytext, yyleng);
|
||||
yyextra->buffer.append("\n", 1);
|
||||
CommentsUtil::AddTrimLine(&yyextra->buffer, yytext + 1, yyleng - 1);
|
||||
}
|
||||
\n|. {
|
||||
BEGIN(INITIAL);
|
||||
|
||||
@ -17,7 +17,7 @@ TEST(CommentsTest, Simple) {
|
||||
});
|
||||
|
||||
ASSERT_EQ(comments.size(), 1u);
|
||||
EXPECT_EQ(comments[0], "// Hello");
|
||||
EXPECT_EQ(comments[0], "Hello");
|
||||
}
|
||||
|
||||
TEST(CommentsTest, Nothing) {
|
||||
@ -47,7 +47,7 @@ dfdd
|
||||
});
|
||||
|
||||
ASSERT_EQ(comments.size(), 1u);
|
||||
EXPECT_EQ(comments[0], "/*\nhello world\n*/");
|
||||
EXPECT_EQ(comments[0], "hello world\n");
|
||||
}
|
||||
|
||||
TEST(CommentsTest, MultilineCpp) {
|
||||
@ -64,5 +64,5 @@ daa
|
||||
});
|
||||
|
||||
ASSERT_EQ(comments.size(), 1u);
|
||||
EXPECT_EQ(comments[0], "// hello\n// world");
|
||||
EXPECT_EQ(comments[0], "hello\nworld");
|
||||
}
|
||||
|
||||
15
engine/src/flutter/tools/licenses_cpp/src/comments_util.cc
Normal file
15
engine/src/flutter/tools/licenses_cpp/src/comments_util.cc
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/tools/licenses_cpp/src/comments_util.h"
|
||||
#include "flutter/third_party/re2/re2/re2.h"
|
||||
|
||||
void CommentsUtil::AddTrimLine(std::string* buffer,
|
||||
const char* text,
|
||||
size_t length) {
|
||||
RE2 regex(R"regex(^(?:\s*//\s?)(.*))regex");
|
||||
re2::StringPiece captured_content;
|
||||
RE2::FullMatch(re2::StringPiece(text), regex, &captured_content);
|
||||
buffer->append(captured_content);
|
||||
}
|
||||
16
engine/src/flutter/tools/licenses_cpp/src/comments_util.h
Normal file
16
engine/src/flutter/tools/licenses_cpp/src/comments_util.h
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_TOOLS_LICENSES_CPP_SRC_COMMENTS_UTIL_H_
|
||||
#define FLUTTER_TOOLS_LICENSES_CPP_SRC_COMMENTS_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
/// @brief Helper functions for the generated comments lexer.
|
||||
class CommentsUtil {
|
||||
public:
|
||||
static void AddTrimLine(std::string* buffer, const char* text, size_t length);
|
||||
};
|
||||
|
||||
#endif // FLUTTER_TOOLS_LICENSES_CPP_SRC_COMMENTS_UTIL_H_
|
||||
@ -6,8 +6,11 @@
|
||||
|
||||
#include <unistd.h>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/third_party/abseil-cpp/absl/container/btree_map.h"
|
||||
#include "flutter/third_party/abseil-cpp/absl/container/flat_hash_set.h"
|
||||
#include "flutter/third_party/abseil-cpp/absl/log/log.h"
|
||||
#include "flutter/third_party/abseil-cpp/absl/status/statusor.h"
|
||||
#include "flutter/third_party/re2/re2/re2.h"
|
||||
@ -92,9 +95,53 @@ void PrintProgress(size_t idx, size_t count) {
|
||||
bool IsStdoutTerminal() {
|
||||
return isatty(STDOUT_FILENO);
|
||||
}
|
||||
|
||||
class LicensesWriter {
|
||||
public:
|
||||
explicit LicensesWriter(std::ostream& licenses) : licenses_(licenses) {}
|
||||
|
||||
void Write(const absl::flat_hash_set<std::string>& packages,
|
||||
std::string_view license) {
|
||||
std::vector<std::string_view> sorted;
|
||||
sorted.reserve(packages.size());
|
||||
sorted.insert(sorted.end(), packages.begin(), packages.end());
|
||||
std::sort(sorted.begin(), sorted.end());
|
||||
if (!first_write_) {
|
||||
for (int i = 0; i < 80; ++i) {
|
||||
licenses_.put('-');
|
||||
}
|
||||
licenses_.put('\n');
|
||||
}
|
||||
first_write_ = false;
|
||||
for (std::string_view package : sorted) {
|
||||
licenses_ << package << "\n";
|
||||
}
|
||||
licenses_ << "\n" << license << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& licenses_;
|
||||
bool first_write_ = true;
|
||||
};
|
||||
|
||||
std::string GetPackageName(const fs::path& full_path) {
|
||||
std::optional<std::string> result;
|
||||
bool after_third_party = false;
|
||||
for (const fs::path& component : full_path) {
|
||||
if (after_third_party) {
|
||||
result = component;
|
||||
after_third_party = false;
|
||||
} else if (component.string() == "third_party") {
|
||||
after_third_party = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result.has_value() ? result.value() : "engine";
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
std::ostream& licenses,
|
||||
const Data& data) {
|
||||
std::vector<absl::Status> errors;
|
||||
std::vector<fs::path> git_repos = GetGitRepos(working_dir);
|
||||
@ -117,6 +164,8 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
errors.push_back(git_files.status());
|
||||
return errors;
|
||||
}
|
||||
LicensesWriter writer(licenses);
|
||||
absl::btree_map<std::string, absl::flat_hash_set<std::string>> license_map;
|
||||
for (const std::string& git_file : git_files.value()) {
|
||||
bool did_find_copyright = false;
|
||||
fs::path full_path = git_repo / git_file;
|
||||
@ -125,6 +174,9 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
// Ignore file.
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string package = GetPackageName(full_path);
|
||||
|
||||
VLOG(1) << full_path.string();
|
||||
absl::StatusOr<MMapFile> file = MMapFile::Make(full_path.string());
|
||||
if (!file.ok()) {
|
||||
@ -144,6 +196,16 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
if (RE2::PartialMatch(comment, pattern, &match)) {
|
||||
did_find_copyright = true;
|
||||
VLOG(1) << comment;
|
||||
|
||||
auto package_emplace_result = license_map.try_emplace(
|
||||
comment, absl::flat_hash_set<std::string>());
|
||||
absl::flat_hash_set<std::string>& comment_set =
|
||||
package_emplace_result.first->second;
|
||||
if (comment_set.find(package) != comment_set.end()) {
|
||||
// License is already seen.
|
||||
return;
|
||||
}
|
||||
comment_set.emplace(std::string(package));
|
||||
}
|
||||
});
|
||||
if (!did_find_copyright) {
|
||||
@ -151,6 +213,9 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
absl::NotFoundError("Expected copyright in " + full_path.string()));
|
||||
}
|
||||
}
|
||||
for (const auto& comment_entry : license_map) {
|
||||
writer.Write(comment_entry.second, comment_entry.first);
|
||||
}
|
||||
}
|
||||
if (IsStdoutTerminal()) {
|
||||
PrintProgress(count++, git_repos.size());
|
||||
@ -161,6 +226,7 @@ std::vector<absl::Status> LicenseChecker::Run(std::string_view working_dir,
|
||||
}
|
||||
|
||||
int LicenseChecker::Run(std::string_view working_dir,
|
||||
std::ostream& licenses,
|
||||
std::string_view data_dir) {
|
||||
absl::StatusOr<Data> data = Data::Open(data_dir);
|
||||
if (!data.ok()) {
|
||||
@ -168,7 +234,7 @@ int LicenseChecker::Run(std::string_view working_dir,
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::vector<absl::Status> errors = Run(working_dir, data.value());
|
||||
std::vector<absl::Status> errors = Run(working_dir, licenses, data.value());
|
||||
for (const absl::Status& status : errors) {
|
||||
std::cerr << status << std::endl;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#ifndef FLUTTER_TOOLS_LICENSES_CPP_SRC_LICENSE_CHECKER_H_
|
||||
#define FLUTTER_TOOLS_LICENSES_CPP_SRC_LICENSE_CHECKER_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include "flutter/third_party/abseil-cpp/absl/status/status.h"
|
||||
@ -14,8 +15,11 @@ class LicenseChecker {
|
||||
public:
|
||||
static const char* kHeaderLicenseRegex;
|
||||
static std::vector<absl::Status> Run(std::string_view working_dir,
|
||||
std::ostream& licenses,
|
||||
const Data& data);
|
||||
static int Run(std::string_view working_dir, std::string_view data_dir);
|
||||
static int Run(std::string_view working_dir,
|
||||
std::ostream& licenses,
|
||||
std::string_view data_dir);
|
||||
};
|
||||
|
||||
#endif // FLUTTER_TOOLS_LICENSES_CPP_SRC_LICENSE_CHECKER_H_
|
||||
|
||||
@ -56,6 +56,15 @@ void main() {
|
||||
}
|
||||
)header";
|
||||
|
||||
const char* kCHeader = R"header(
|
||||
/*
|
||||
C Copyright Test
|
||||
*/
|
||||
|
||||
void main() {
|
||||
}
|
||||
)header";
|
||||
|
||||
const char* kLicense = R"lic(
|
||||
Test License
|
||||
v2.0
|
||||
@ -117,12 +126,13 @@ TEST_F(LicenseCheckerTest, SimplePass) {
|
||||
ASSERT_EQ(std::system("git add LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), *data);
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(LicenseCheckerTest, SimpleFailure) {
|
||||
TEST_F(LicenseCheckerTest, SimpleMissingLicense) {
|
||||
absl::StatusOr<fs::path> temp_path = MakeTempDir();
|
||||
ASSERT_TRUE(temp_path.ok());
|
||||
|
||||
@ -135,11 +145,134 @@ TEST_F(LicenseCheckerTest, SimpleFailure) {
|
||||
ASSERT_EQ(std::system("git add main.cc"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), *data);
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 2u);
|
||||
EXPECT_TRUE(
|
||||
FindError(errors, absl::StatusCode::kNotFound, "Expected LICENSE at"));
|
||||
EXPECT_TRUE(FindError(errors, absl::StatusCode::kNotFound,
|
||||
"Expected copyright in.*main.cc"));
|
||||
}
|
||||
|
||||
TEST_F(LicenseCheckerTest, SimpleWritesLicensesFile) {
|
||||
absl::StatusOr<fs::path> temp_path = MakeTempDir();
|
||||
ASSERT_TRUE(temp_path.ok());
|
||||
|
||||
absl::StatusOr<Data> data = MakeTestData();
|
||||
ASSERT_TRUE(data.ok());
|
||||
|
||||
fs::current_path(*temp_path);
|
||||
ASSERT_EQ(std::system("git init"), 0);
|
||||
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "main.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
|
||||
ASSERT_EQ(std::system("git add main.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 0u);
|
||||
|
||||
EXPECT_EQ(ss.str(), R"output(engine
|
||||
|
||||
Copyright Test
|
||||
)output");
|
||||
}
|
||||
|
||||
TEST_F(LicenseCheckerTest, SimpleWritesTwoLicensesFiles) {
|
||||
absl::StatusOr<fs::path> temp_path = MakeTempDir();
|
||||
ASSERT_TRUE(temp_path.ok());
|
||||
|
||||
absl::StatusOr<Data> data = MakeTestData();
|
||||
ASSERT_TRUE(data.ok());
|
||||
|
||||
fs::current_path(*temp_path);
|
||||
ASSERT_EQ(std::system("git init"), 0);
|
||||
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "main.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kCHeader, *temp_path / "cmain.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
|
||||
ASSERT_EQ(std::system("git add main.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add cmain.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 0u);
|
||||
|
||||
EXPECT_EQ(ss.str(), R"output(engine
|
||||
|
||||
C Copyright Test
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
engine
|
||||
|
||||
Copyright Test
|
||||
)output");
|
||||
}
|
||||
|
||||
TEST_F(LicenseCheckerTest, SimpleWritesDuplicateLicensesFiles) {
|
||||
absl::StatusOr<fs::path> temp_path = MakeTempDir();
|
||||
ASSERT_TRUE(temp_path.ok());
|
||||
|
||||
absl::StatusOr<Data> data = MakeTestData();
|
||||
ASSERT_TRUE(data.ok());
|
||||
|
||||
fs::current_path(*temp_path);
|
||||
ASSERT_EQ(std::system("git init"), 0);
|
||||
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "a.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "b.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
|
||||
ASSERT_EQ(std::system("git add a.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add b.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 0u);
|
||||
|
||||
EXPECT_EQ(ss.str(), R"output(engine
|
||||
|
||||
Copyright Test
|
||||
)output");
|
||||
}
|
||||
|
||||
TEST_F(LicenseCheckerTest, MultiplePackages) {
|
||||
absl::StatusOr<fs::path> temp_path = MakeTempDir();
|
||||
ASSERT_TRUE(temp_path.ok());
|
||||
|
||||
absl::StatusOr<Data> data = MakeTestData();
|
||||
ASSERT_TRUE(data.ok());
|
||||
|
||||
fs::current_path(*temp_path);
|
||||
ASSERT_EQ(std::system("mkdir -p third_party/foobar"), 0);
|
||||
ASSERT_EQ(std::system("git init"), 0);
|
||||
ASSERT_TRUE(WriteFile(kHeader, *temp_path / "a.cc").ok());
|
||||
ASSERT_TRUE(
|
||||
WriteFile(kHeader, *temp_path / "third_party" / "foobar" / "b.cc").ok());
|
||||
ASSERT_TRUE(WriteFile(kLicense, *temp_path / "LICENSE").ok());
|
||||
ASSERT_TRUE(
|
||||
WriteFile(kLicense, *temp_path / "third_party" / "foobar" / "LICENSE")
|
||||
.ok());
|
||||
ASSERT_EQ(std::system("git add a.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add third_party/foobar/b.cc"), 0);
|
||||
ASSERT_EQ(std::system("git add third_party/foobar/LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git add LICENSE"), 0);
|
||||
ASSERT_EQ(std::system("git commit -m \"test\""), 0);
|
||||
|
||||
std::stringstream ss;
|
||||
std::vector<absl::Status> errors =
|
||||
LicenseChecker::Run(temp_path->string(), ss, *data);
|
||||
EXPECT_EQ(errors.size(), 0u);
|
||||
|
||||
EXPECT_EQ(ss.str(), R"output(engine
|
||||
foobar
|
||||
|
||||
Copyright Test
|
||||
)output");
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "flutter/third_party/abseil-cpp/absl/flags/flag.h"
|
||||
#include "flutter/third_party/abseil-cpp/absl/flags/parse.h"
|
||||
#include "flutter/third_party/abseil-cpp/absl/flags/usage.h"
|
||||
@ -17,6 +19,10 @@ ABSL_FLAG(std::optional<std::string>,
|
||||
data_dir,
|
||||
std::nullopt,
|
||||
"[REQUIRED] The directory with the licenses.");
|
||||
ABSL_FLAG(std::optional<std::string>,
|
||||
licenses_path,
|
||||
std::nullopt,
|
||||
"[REQUIRED] The path to write the licenses collection to.");
|
||||
ABSL_FLAG(int, v, 0, "Set the verbosity of logs.");
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@ -29,8 +35,16 @@ int main(int argc, char** argv) {
|
||||
|
||||
std::optional<std::string> working_dir = absl::GetFlag(FLAGS_working_dir);
|
||||
std::optional<std::string> data_dir = absl::GetFlag(FLAGS_working_dir);
|
||||
if (working_dir.has_value() && data_dir.has_value()) {
|
||||
return LicenseChecker::Run(working_dir.value(), data_dir.value());
|
||||
std::optional<std::string> licenses_path = absl::GetFlag(FLAGS_licenses_path);
|
||||
if (working_dir.has_value() && data_dir.has_value() &&
|
||||
licenses_path.has_value()) {
|
||||
std::ofstream licenses;
|
||||
licenses.open(licenses_path.value());
|
||||
if (licenses.bad()) {
|
||||
std::cerr << "Unable to write to '" << licenses_path.value() << "'.";
|
||||
return 1;
|
||||
}
|
||||
return LicenseChecker::Run(working_dir.value(), licenses, data_dir.value());
|
||||
}
|
||||
|
||||
if (!working_dir.has_value()) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user