Skip to content

Commit

Permalink
Allow to provide 'grep' regex for print to narrow output.
Browse files Browse the repository at this point in the history
  • Loading branch information
hzeller committed Jun 27, 2024
1 parent 5893b61 commit 74716d3
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 31 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ of these and print the final form:
bant print -b @googletest//:gtest
```

The `-g` option allows to 'grep' for targets where any of the strings in the
AST of a rule matches a pattern

```
bant print ... -g "arena.*test"
```

#### Workspace

**`workspace`** prints all the external projects found in the workspace.
Expand Down Expand Up @@ -229,10 +236,13 @@ Options
Commands (unique prefix sufficient):
== Parsing ==
print : Print AST matching pattern. -e : only files w/ parse errors
-b : elaBorate; light eval: expand variables, concat etc.
-b : elaBorate; light eval: expand variables, concat etc.
-g <regex> : 'grep' - only print targets where any string
matches regex.
-i If '-g' is given: case insensitive
parse : Parse all BUILD files from pattern. Follow deps with -r
Emit parse errors. Silent otherwise: No news are good news.
-v : some stats.
-v : some stats.
== Extract facts == (Use -f to choose output format) ==
workspace : Print external projects found in WORKSPACE.
Expand All @@ -258,7 +268,7 @@ Commands (unique prefix sufficient):
== Tools ==
dwyu : DWYU: Depend on What You Use (emit buildozer edit script)
-k strict: emit remove even if # keep comment in line.
-k strict: emit remove even if # keep comment in line.
canonicalize : Emit rename edits to canonicalize targets.
```

Expand Down
26 changes: 19 additions & 7 deletions bant/bant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,13 @@ static int usage(const char *prog, const char *message, int exit_code) {
Commands (unique prefix sufficient):
%s== Parsing ==%s
print : Print AST matching pattern. -e : only files w/ parse errors
-b : elaBorate; light eval: expand variables, concat etc.
-b : elaBorate; light eval: expand variables, concat etc.
-g <regex> : 'grep' - only print targets where any string
matches regex.
-i If '-g' is given: case insensitive
parse : Parse all BUILD files from pattern. Follow deps with -r
Emit parse errors. Silent otherwise: No news are good news.
-v : some stats.
-v : some stats.
%s== Extract facts ==%s (Use -f to choose output format) ==
workspace : Print external projects found in WORKSPACE.
Expand All @@ -110,7 +113,7 @@ Commands (unique prefix sufficient):
%s== Tools ==%s
dwyu : DWYU: Depend on What You Use (emit buildozer edit script)
-k strict: emit remove even if # keep comment in line.
-k strict: emit remove even if # keep comment in line.
canonicalize : Emit rename edits to canonicalize targets.
)",
BOLD, RESET, BOLD, RESET, BOLD, RESET);
Expand All @@ -132,14 +135,16 @@ int main(int argc, char *argv[]) {

bant::CommandlineFlags flags;

bool regex_case_insesitive = false;

using bant::OutputFormat;
static const std::map<std::string_view, OutputFormat> kFormatOutNames = {
{"native", OutputFormat::kNative}, {"s-expr", OutputFormat::kSExpr},
{"plist", OutputFormat::kPList}, {"csv", OutputFormat::kCSV},
{"json", OutputFormat::kJSON}, {"graphviz", OutputFormat::kGraphviz},
};
int opt;
while ((opt = getopt(argc, argv, "C:qo:vhpecbf:r::Vk")) != -1) {
while ((opt = getopt(argc, argv, "C:qo:vhpecbf:r::Vkg:i")) != -1) {
switch (opt) {
case 'C': {
std::error_code err;
Expand Down Expand Up @@ -176,10 +181,13 @@ int main(int argc, char *argv[]) {
: std::numeric_limits<int>::max();
break;

case 'k':
flags.ignore_keep_comment = true;
break;
case 'k': flags.ignore_keep_comment = true; break;

case 'g': flags.grep_regex = optarg; break;

case 'i':
regex_case_insesitive = true;
break;
// "print" options
case 'p': flags.print_ast = true; break;
case 'e': flags.print_only_errors = true; break;
Expand All @@ -197,6 +205,10 @@ int main(int argc, char *argv[]) {
}
}

if (regex_case_insesitive && !flags.grep_regex.empty()) {
flags.grep_regex.insert(0, "(?i)");
}

bant::FilesystemPrewarmCacheInit(argc, argv);

bant::Session session(primary_out, info_out, flags);
Expand Down
6 changes: 4 additions & 2 deletions bant/cli-commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ CliStatus RunCommand(Session &session, Command cmd,
switch (cmd) {
case Command::kPrint: flags.print_ast = true; [[fallthrough]];
case Command::kParse:
// Parsing has already be done by now by building the dependency graph
// Parsing has already be done by now by building the dependency graph,
// so it would already have emitted parse errors. Here we only have to
// decide if we print anything.
if (flags.print_ast || flags.print_only_errors) {
bant::PrintProject(pattern, session.out(), session.info(), project,
flags.print_only_errors);
flags.print_only_errors, flags.grep_regex);
}
break;

Expand Down
2 changes: 2 additions & 0 deletions bant/frontend/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ cc_library(
"//bant/util:memory",
"@abseil-cpp//absl/log:check",
"@abseil-cpp//absl/strings",
"@re2",
],
)

Expand Down Expand Up @@ -120,6 +121,7 @@ cc_library(
"//bant/util:memory",
"//bant/util:stat",
"@abseil-cpp//absl/log:check",
"@re2",
],
)

Expand Down
50 changes: 33 additions & 17 deletions bant/frontend/parsed-project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include <cstdlib>
#include <iostream>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
Expand All @@ -38,6 +39,7 @@
#include "bant/util/file-utils.h"
#include "bant/util/stat.h"
#include "bant/workspace.h"
#include "re2/re2.h"

namespace bant {
namespace {
Expand Down Expand Up @@ -236,7 +238,19 @@ const ParsedBuildFile *ParsedProject::FindParsedOrNull(

void PrintProject(const BazelPattern &pattern, std::ostream &out,
std::ostream &info_out, const ParsedProject &project,
bool only_files_with_errors) {
bool only_files_with_errors, std::string_view grep_regex) {
std::unique_ptr<RE2> regex;
if (!grep_regex.empty()) {
// TODO: pass options to not log error
regex = std::make_unique<RE2>(grep_regex);
if (!regex->ok()) {
// This really needs the session passed in so that we can reach the
// correct error stream.
std::cerr << "Grep pattern: " << regex->error() << "\n";
return;
}
}

for (const auto &[package, file_content] : project.ParsedFiles()) {
if (only_files_with_errors && file_content->errors.empty()) {
continue;
Expand All @@ -245,26 +259,28 @@ void PrintProject(const BazelPattern &pattern, std::ostream &out,
continue;
}

if (pattern.is_recursive()) {
out << "# " << file_content->name() << ": "
<< file_content->package.ToString() << "\n";
info_out << file_content->errors;
PrintVisitor(out).WalkNonNull(file_content->ast);
out << "\n";
} else {
query::FindTargets(
file_content->ast, {}, [&](const query::Result &result) {
query::FindTargetsAllowEmptyName(
file_content->ast, {}, [&](const query::Result &result) {
if (!pattern.is_recursive()) {
// Need more specific check if matches.
auto self = BazelTarget::ParseFrom(result.name, package);
if (!self.has_value() || !pattern.Match(*self)) {
return;
}
// TODO: instead of just marking the range of the function name,
// show the range the whole function covers until closed parenthesis.
out << "# " << project.Loc(result.node->identifier()->id()) << "\n";
PrintVisitor(out).WalkNonNull(result.node);
out << "\n";
});
}
}

// TODO: instead of just marking the range of the function name,
// show the range the whole function covers until closed parenthesis.
// TODO: if isatty(out), color filename gray
std::stringstream tmp_out;
tmp_out << "# " << project.Loc(result.node->identifier()->id()) << "\n";
PrintVisitor printer(tmp_out, regex.get());
printer.WalkNonNull(result.node);
tmp_out << "\n";
if (!regex || printer.any_highlight()) { // w/o regex: always print.
out << tmp_out.str();
}
});
}
}
} // namespace bant
5 changes: 4 additions & 1 deletion bant/frontend/parsed-project.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ class ParsedProject : public SourceLocator {
// "out" is the destination of the acutal parse tree, "info_out" will
// print error message and filenames.
// If "only_files_with_errors" is set, prints only the files that had issues.
// With "grep_regex", only targets are printed that have any substring match
// expression.
// TODO: this function has too many parameters.
void PrintProject(const BazelPattern &pattern, std::ostream &out,
std::ostream &info_out, const ParsedProject &project,
bool only_files_with_errors);
bool only_files_with_errors, std::string_view grep_regex);
} // namespace bant
#endif // BANT_PROJECT_PARDER_
6 changes: 6 additions & 0 deletions bant/frontend/print-visitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "bant/frontend/ast.h"
#include "bant/frontend/scanner.h"
#include "re2/re2.h"

namespace bant {
void PrintVisitor::VisitFunCall(FunCall *f) {
Expand Down Expand Up @@ -122,6 +123,11 @@ void PrintVisitor::VisitScalar(Scalar *s) {
str->AsString().find_first_of('"') != std::string_view::npos;
const char quote_char = has_any_double_quote ? '\'' : '"';
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
if (optional_highlight_) {
// TODO: actually highlight.
any_highlight_ |=
RE2::PartialMatch(str->AsString(), *optional_highlight_);
}
out_ << quote_char << str->AsString() << quote_char;
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
}
Expand Down
10 changes: 9 additions & 1 deletion bant/frontend/print-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,18 @@
#ifndef BANT_PRINT_VISITOR_H
#define BANT_PRINT_VISITOR_H

#include <memory>
#include <ostream>

#include "bant/frontend/ast.h"
#include "re2/re2.h"

namespace bant {
class PrintVisitor : public BaseVoidVisitor {
public:
explicit PrintVisitor(std::ostream &out) : out_(out) {}
explicit PrintVisitor(std::ostream &out,
const RE2 *optional_highlight = nullptr)
: out_(out), optional_highlight_(optional_highlight) {}
// Using default impl. for Assignment.
void VisitFunCall(FunCall *f) final;
void VisitList(List *l) final;
Expand All @@ -38,9 +42,13 @@ class PrintVisitor : public BaseVoidVisitor {
void VisitScalar(Scalar *s) final;
void VisitIdentifier(Identifier *i) final;

bool any_highlight() const { return any_highlight_; }

private:
int indent_ = 0;
std::ostream &out_;
const RE2 *const optional_highlight_;
bool any_highlight_ = false;
};
} // namespace bant

Expand Down
1 change: 1 addition & 0 deletions bant/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ struct CommandlineFlags {
bool ignore_keep_comment = false;
int recurse_dependency_depth = 0;
OutputFormat output_format = OutputFormat::kNative;
std::string grep_regex;
};

// A session contains some settings such as output/verbose requests
Expand Down

0 comments on commit 74716d3

Please sign in to comment.