Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions crates/squawk/src/cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::{path::PathBuf, process};

use crate::{
Command, config::Config, debug::DebugArgs, file_finding::find_paths, reporter::LintArgs,
};

pub(crate) struct Stdin {
pub(crate) path: Option<String>,
}

pub(crate) enum Input {
Stdin(Stdin),
Paths(Vec<PathBuf>),
}

pub(crate) enum Cmd {
Debug(DebugArgs),
Lint(LintArgs),
Help,
None,
Server,
UploadToGithub(Box<Config>),
}

impl Cmd {
fn resolve_cli(conf: Config) -> Cmd {
// TODO: do we need to do the same thing for the github command?
let found_paths =
find_paths(&conf.path_patterns, &conf.excluded_paths).unwrap_or_else(|e| {
eprintln!("Failed to find files: {e}");
process::exit(1);
});
if found_paths.is_empty() && !conf.path_patterns.is_empty() {
eprintln!(
"Failed to find files for provided patterns: {:?}",
conf.path_patterns
);
if !conf.no_error_on_unmatched_pattern {
process::exit(1);
}
}
if !found_paths.is_empty() || conf.is_stdin {
let read_stdin = found_paths.is_empty() && conf.is_stdin;
let input = if read_stdin {
Input::Stdin(Stdin {
path: conf.stdin_filepath,
})
} else {
Input::Paths(found_paths)
};
if let Some(debug_option) = conf.debug {
return Cmd::Debug(DebugArgs {
input,
debug_option,
verbose: conf.verbose,
});
} else {
return Cmd::Lint(LintArgs {
input,
excluded_rules: conf.excluded_rules,
pg_version: conf.pg_version,
assume_in_transaction: conf.assume_in_transaction,
reporter: conf.reporter,
github_annotations: conf.github_annotations,
});
}
} else if !conf.no_error_on_unmatched_pattern {
return Cmd::Help;
} else {
return Cmd::None;
}
}

pub(crate) fn from(opts: crate::Opts) -> Cmd {
match opts.cmd {
Some(Command::Server) => Cmd::Server,
Some(Command::UploadToGithub(_)) => {
let conf = Config::from(opts);
Cmd::UploadToGithub(Box::new(conf))
}
None => {
let conf = Config::from(opts);
Cmd::resolve_cli(conf)
}
}
}
}
45 changes: 25 additions & 20 deletions crates/squawk/src/debug.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{io, path::PathBuf};
use std::io;

use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle};
use anyhow::Result;
Expand All @@ -7,23 +7,24 @@ use squawk_syntax::{ast::AstNode, syntax_error::SyntaxError};

use crate::{
DebugOption,
cmd::Input,
file::{sql_from_path, sql_from_stdin},
};

pub(crate) fn debug<W: io::Write>(
f: &mut W,
paths: &[PathBuf],
read_stdin: bool,
debug_option: &DebugOption,
verbose: bool,
) -> Result<()> {
pub(crate) struct DebugArgs {
pub(crate) input: Input,
pub(crate) debug_option: DebugOption,
pub(crate) verbose: bool,
}

pub(crate) fn debug<W: io::Write>(f: &mut W, args: DebugArgs) -> Result<()> {
let process_dump_ast = |sql: &str, filename: &str, f: &mut W| -> Result<()> {
match debug_option {
match args.debug_option {
DebugOption::Lex => {
let tokens = squawk_lexer::tokenize(sql);
let mut start = 0;
for token in tokens {
if verbose {
if args.verbose {
let content = &sql[start as usize..(start + token.len) as usize];
start += token.len;
writeln!(f, "{content:?} @ {:?}", token.kind)?;
Expand All @@ -34,7 +35,7 @@ pub(crate) fn debug<W: io::Write>(
}
DebugOption::Parse => {
let parse = squawk_syntax::SourceFile::parse(sql);
if verbose {
if args.verbose {
writeln!(f, "{}\n---", parse.syntax_node())?;
}
writeln!(f, "{:#?}", parse.syntax_node())?;
Expand Down Expand Up @@ -65,16 +66,20 @@ pub(crate) fn debug<W: io::Write>(
}
Ok(())
};
if read_stdin {
let sql = sql_from_stdin()?;
process_dump_ast(&sql, "stdin", f)?;
return Ok(());
}

for path in paths {
let sql = sql_from_path(path)?;
process_dump_ast(&sql, &path.to_string_lossy(), f)?;
}
match args.input {
Input::Stdin(_) => {
let sql = sql_from_stdin()?;
process_dump_ast(&sql, "stdin", f)?;
}
Input::Paths(path_bufs) => {
for path in path_bufs {
let sql = sql_from_path(&path)?;
process_dump_ast(&sql, &path.to_string_lossy(), f)?;
}
}
};

Ok(())
}

Expand Down
21 changes: 11 additions & 10 deletions crates/squawk/src/github.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::UploadToGithubArgs;
use crate::cmd::Input;
use crate::config::Config;
use crate::reporter::{CheckReport, fmt_github_annotations, fmt_tty_violation};
use crate::{file_finding::find_paths, reporter::check_files};
use crate::{LintArgs, UploadToGithubArgs};
use crate::{file_finding::find_paths, reporter::lint_files};
use anyhow::{Context, Result, anyhow, bail};
use console::strip_ansi_codes;
use log::info;
Expand Down Expand Up @@ -117,14 +118,14 @@ pub fn check_and_comment_on_pr(cfg: Config) -> Result<()> {
let found_paths = find_paths(&paths, &cfg.excluded_paths)?;

info!("checking files");
let file_results = check_files(
&found_paths,
cfg.is_stdin,
&cfg.stdin_filepath,
&cfg.excluded_rules,
cfg.pg_version,
cfg.assume_in_transaction,
)?;
let file_results = lint_files(&LintArgs {
input: Input::Paths(found_paths),
excluded_rules: cfg.excluded_rules,
pg_version: cfg.pg_version,
assume_in_transaction: cfg.assume_in_transaction,
reporter: cfg.reporter,
github_annotations: cfg.github_annotations,
})?;

// We should only leave a comment when there are files checked.
if paths.is_empty() {
Expand Down
76 changes: 24 additions & 52 deletions crates/squawk/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
mod cmd;
mod config;
mod debug;
mod file;
mod file_finding;
mod github;
mod reporter;
use crate::config::Config;
use crate::file_finding::find_paths;
use crate::cmd::Cmd;
use crate::reporter::LintArgs;
use anyhow::{Context, Result};
use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use debug::debug;
use reporter::check_and_dump_files;
use reporter::lint_and_report;
use simplelog::CombinedLogger;
use squawk_linter::{Rule, Version};
use std::io;
use std::panic;
use std::path::PathBuf;
use std::process::{self, ExitCode};
use std::process::ExitCode;

#[derive(Parser, Debug)]
pub struct UploadToGithubArgs {
Expand Down Expand Up @@ -182,58 +183,29 @@ Please open an issue at https://github.com/sbdchd/squawk/issues/new with the log
.expect("problem creating logger");
}

match opts.cmd {
Some(Command::Server) => {
match Cmd::from(opts) {
Cmd::Server => {
squawk_server::run().context("language server failed")?;
}
Some(Command::UploadToGithub(_)) => {
let conf = Config::from(opts);
github::check_and_comment_on_pr(conf).context("Upload to GitHub failed")?;
Cmd::UploadToGithub(config) => {
github::check_and_comment_on_pr(*config).context("Upload to GitHub failed")?;
}
None => {
let conf = Config::from(opts);
// TODO: do we need to do the same thing for the github command?
let found_paths =
find_paths(&conf.path_patterns, &conf.excluded_paths).unwrap_or_else(|e| {
eprintln!("Failed to find files: {e}");
process::exit(1);
});
if found_paths.is_empty() && !conf.path_patterns.is_empty() {
eprintln!(
"Failed to find files for provided patterns: {:?}",
conf.path_patterns
);
if !conf.no_error_on_unmatched_pattern {
process::exit(1);
}
}
if !found_paths.is_empty() || conf.is_stdin {
let stdout = io::stdout();
let mut handle = stdout.lock();

let read_stdin = found_paths.is_empty() && conf.is_stdin;
if let Some(kind) = conf.debug {
debug(&mut handle, &found_paths, read_stdin, &kind, conf.verbose)?;
} else {
let reporter = conf.reporter;
let exit_code = check_and_dump_files(
&mut handle,
&found_paths,
read_stdin,
conf.stdin_filepath,
&conf.excluded_rules,
conf.pg_version,
conf.assume_in_transaction,
&reporter,
conf.github_annotations,
)?;
return Ok(exit_code);
}
} else if !conf.no_error_on_unmatched_pattern {
Opts::command().print_long_help()?;
println!();
}
Cmd::Debug(debug_args) => {
let stdout = io::stdout();
let mut handle = stdout.lock();
debug(&mut handle, debug_args)?;
}
Cmd::Lint(lint_args) => {
let stdout = io::stdout();
let mut handle = stdout.lock();
return lint_and_report(&mut handle, lint_args);
}
Cmd::Help => {
Opts::command().print_long_help()?;
println!();
}
Cmd::None => (),
}

Ok(ExitCode::SUCCESS)
}
Loading
Loading