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
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ jobs:

# Linux builds
- arch: amd64
run_on: ubuntu-latest
run_on: ubuntu-24.04
os: linux
target: x86_64-unknown-linux-gnu
test: true
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# It will then package that binary into the image, and use that as the entrypoint.
# This means that running `docker build` is not a repeatable way to build the same
# image, but the benefit is much faster cross-platform builds; a net win.
FROM debian:bookworm-slim
FROM ubuntu:24.04

LABEL org.opencontainers.image.source=https://github.com/SierraSoftworks/github-backup
LABEL org.opencontainers.image.description="Backup your GitHub repositories and releases automatically"
Expand Down
1 change: 0 additions & 1 deletion src/engines/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,6 @@ mod tests {
#[cfg_attr(feature = "pure_tests", ignore)]
#[rstest]
#[case("SierraSoftworks/grey", "https://github.com/sierrasoftworks/grey.git")]
#[case("neovim/neovim", "https://github.com/neovim/neovim.git")]
#[tokio::test]
async fn test_backup(#[case] name: &str, #[case] url: &str) {
let temp_dir = tempfile::tempdir().expect("a temporary directory");
Expand Down
4 changes: 2 additions & 2 deletions src/engines/http_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@
tokio::fs::remove_file(&temp_path)
.await
.unwrap_or_else(|e| {
tracing::error!(
error!(

Check warning on line 160 in src/engines/http_file.rs

View check run for this annotation

Codecov / codecov/patch

src/engines/http_file.rs#L160

Added line #L160 was not covered by tests
"Failed to remove temporary backup file '{}': {}",
temp_path.display(),
e
Expand All @@ -175,7 +175,7 @@
tokio::fs::remove_file(&temp_path)
.await
.unwrap_or_else(|e| {
tracing::error!(
error!(

Check warning on line 178 in src/engines/http_file.rs

View check run for this annotation

Codecov / codecov/patch

src/engines/http_file.rs#L178

Added line #L178 was not covered by tests
"Failed to remove temporary backup file '{}': {}",
temp_path.display(),
e
Expand Down
8 changes: 3 additions & 5 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
human_errors::error_shim!(Error);

use std::convert;

use reqwest::StatusCode;

impl convert::From<reqwest::Error> for Error {
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
if err.is_connect() {
user_with_internal(
Expand Down Expand Up @@ -35,7 +33,7 @@ impl convert::From<reqwest::Error> for Error {
}
}

impl convert::From<reqwest::Response> for Error {
impl From<reqwest::Response> for Error {
fn from(resp: reqwest::Response) -> Self {
match resp.status() {
StatusCode::NOT_FOUND => user(
Expand All @@ -55,7 +53,7 @@ impl convert::From<reqwest::Response> for Error {
}
}

impl convert::From<reqwest::header::InvalidHeaderValue> for Error {
impl From<reqwest::header::InvalidHeaderValue> for Error {
fn from(err: reqwest::header::InvalidHeaderValue) -> Self {
system_with_internal(
"Could not parse header value due to an internal error.",
Expand Down
2 changes: 1 addition & 1 deletion src/filter/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl Debug for Expr<'_> {
}

struct ExprPrinter<'a, 'b>(&'a mut std::fmt::Formatter<'b>);
impl<'a, 'b> ExprVisitor<std::fmt::Result> for ExprPrinter<'a, 'b> {
impl ExprVisitor<std::fmt::Result> for ExprPrinter<'_, '_> {
fn visit_literal(&mut self, value: &FilterValue) -> std::fmt::Result {
write!(self.0, "{}", value)
}
Expand Down
2 changes: 1 addition & 1 deletion src/filter/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<'a, T: Filterable> FilterContext<'a, T> {
}
}

impl<'a, T: Filterable> ExprVisitor<FilterValue> for FilterContext<'a, T> {
impl<T: Filterable> ExprVisitor<FilterValue> for FilterContext<'_, T> {
fn visit_literal(&mut self, value: &FilterValue) -> FilterValue {
value.clone()
}
Expand Down
72 changes: 36 additions & 36 deletions src/filter/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,81 +159,81 @@
))));
}
'&' => {
if self.match_char('&') {
return Some(Ok(Token::And(Loc::new(
return if self.match_char('&') {
Some(Ok(Token::And(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Err(errors::user(
&format!("Filter included an orphaned '&' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '&&' operator to implement a logical AND within your filter."
)));
Some(Err(errors::user(
&format!("Filter included an orphaned '&' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '&&' operator to implement a logical AND within your filter."
)))

Check warning on line 171 in src/filter/lexer.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/lexer.rs#L168-L171

Added lines #L168 - L171 were not covered by tests
}
}
'|' => {
if self.match_char('|') {
return Some(Ok(Token::Or(Loc::new(
return if self.match_char('|') {
Some(Ok(Token::Or(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Err(errors::user(
&format!("Filter included an orphaned '|' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '||' operator to implement a logical OR within your filter."
)));
Some(Err(errors::user(
&format!("Filter included an orphaned '|' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '||' operator to implement a logical OR within your filter."
)))

Check warning on line 184 in src/filter/lexer.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/lexer.rs#L181-L184

Added lines #L181 - L184 were not covered by tests
}
}
'=' => {
if self.match_char('=') {
return Some(Ok(Token::Equals(Loc::new(
return if self.match_char('=') {
Some(Ok(Token::Equals(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Err(errors::user(
&format!("Filter included an orphaned '=' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '==' operator to implement a logical equality within your filter."
)));
Some(Err(errors::user(
&format!("Filter included an orphaned '=' at {} which is not a valid operator.", Loc::new(self.line, 1 + idx - self.line_start)),
"Ensure that you are using the '==' operator to implement a logical equality within your filter."
)))

Check warning on line 197 in src/filter/lexer.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/lexer.rs#L194-L197

Added lines #L194 - L197 were not covered by tests
}
}
'!' => {
if self.match_char('=') {
return Some(Ok(Token::NotEquals(Loc::new(
return if self.match_char('=') {
Some(Ok(Token::NotEquals(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Ok(Token::Not(Loc::new(
Some(Ok(Token::Not(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
}
}
'>' => {
if self.match_char('=') {
return Some(Ok(Token::GreaterEqual(Loc::new(
return if self.match_char('=') {
Some(Ok(Token::GreaterEqual(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Ok(Token::GreaterThan(Loc::new(
Some(Ok(Token::GreaterThan(Loc::new(
self.line,
idx - self.line_start,
))));
))))
}
}
'<' => {
if self.match_char('=') {
return Some(Ok(Token::SmallerEqual(Loc::new(
return if self.match_char('=') {
Some(Ok(Token::SmallerEqual(Loc::new(
self.line,
1 + idx - self.line_start,
))));
))))
} else {
return Some(Ok(Token::SmallerThan(Loc::new(
Some(Ok(Token::SmallerThan(Loc::new(
self.line,
idx - self.line_start,
))));
))))
}
}
'"' => {
Expand Down
18 changes: 9 additions & 9 deletions src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ impl Filter {
let filter_ptr = NonNull::from(&filter);
let pinned = Box::into_pin(filter);

let tokens = crate::filter::lexer::Scanner::new(unsafe { filter_ptr.as_ref() });
let ast = crate::filter::parser::Parser::parse(tokens.into_iter())?;
let tokens = lexer::Scanner::new(unsafe { filter_ptr.as_ref() });
let ast = parser::Parser::parse(tokens.into_iter())?;
Ok(Self {
filter: pinned,
ast,
Expand Down Expand Up @@ -71,6 +71,13 @@ impl<'de> serde::Deserialize<'de> for Filter {
formatter.write_str("a valid filter expression")
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Filter::new(v).map_err(serde::de::Error::custom)
}

fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
Expand All @@ -84,13 +91,6 @@ impl<'de> serde::Deserialize<'de> for Filter {
{
deserializer.deserialize_str(self)
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Filter::new(v).map_err(serde::de::Error::custom)
}
}

deserializer.deserialize_option(FilterVisitor)
Expand Down
14 changes: 7 additions & 7 deletions src/filter/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {
self.tokens.peek(),
Some(Ok(Token::Equals(..)) | Ok(Token::NotEquals(..)))
) {
let token = self.tokens.next().unwrap().unwrap();
let token = self.tokens.next().unwrap()?;
let right = self.comparison()?;
expr = Expr::Binary(Box::new(expr), token, Box::new(right));
}
Expand All @@ -89,7 +89,7 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {
| Some(Ok(Token::SmallerThan(..)))
| Some(Ok(Token::SmallerEqual(..)))
) {
let token = self.tokens.next().unwrap().unwrap();
let token = self.tokens.next().unwrap()?;
let right = self.unary()?;
expr = Expr::Binary(Box::new(expr), token, Box::new(right));
}
Expand All @@ -99,7 +99,7 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {

fn unary(&mut self) -> Result<Expr<'a>, Error> {
if matches!(self.tokens.peek(), Some(Ok(Token::Not(..)))) {
let token = self.tokens.next().unwrap().unwrap();
let token = self.tokens.next().unwrap()?;
let right = self.unary()?;
Ok(Expr::Unary(token, Box::new(right)))
} else {
Expand All @@ -110,7 +110,7 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {
fn primary(&mut self) -> Result<Expr<'a>, Error> {
match self.tokens.peek() {
Some(Ok(Token::LeftParen(..))) => {
let start = self.tokens.next().unwrap().unwrap();
let start = self.tokens.next().unwrap()?;
let expr = self.or()?;
if let Some(Ok(Token::RightParen(..))) = self.tokens.next() {
Ok(expr)
Expand All @@ -122,7 +122,7 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {
}
}
Some(Ok(Token::LeftBracket(..))) => {
let start = self.tokens.next().unwrap().unwrap();
let start = self.tokens.next().unwrap()?;
let mut items = Vec::new();
while !matches!(self.tokens.peek(), Some(Ok(Token::RightBracket(..)))) {
items.push(self.literal()?);
Expand Down Expand Up @@ -162,13 +162,13 @@ impl<'a, I: Iterator<Item = Result<Token<'a>, Error>>> Parser<'a, I> {
match self.tokens.next() {
Some(Ok(Token::True(..))) => Ok(true.into()),
Some(Ok(Token::False(..))) => Ok(false.into()),
Some(Ok(Token::Number(loc, n))) => Ok(super::FilterValue::Number(n.parse().map_err(|e| errors::user_with_internal(
Some(Ok(Token::Number(loc, n))) => Ok(FilterValue::Number(n.parse().map_err(|e| errors::user_with_internal(
&format!("Failed to parse the number '{n}' which you provided at {}.", loc),
"Please make sure that the number is well formatted. It should be in the form 123, or 123.45.",
e,
))?)),
Some(Ok(Token::String(.., s))) => Ok(s.replace("\\\"", "\"").replace("\\\\", "\\").into()),
Some(Ok(Token::Null(..))) => Ok(super::FilterValue::Null),
Some(Ok(Token::Null(..))) => Ok(FilterValue::Null),
Some(Ok(token)) => Err(errors::user(
&format!("While parsing your filter, we found an unexpected '{}' at {}.", token, token.location()),
"Make sure that you have written a valid filter query.",
Expand Down
42 changes: 21 additions & 21 deletions src/filter/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,27 @@
}

impl PartialOrd for FilterValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(FilterValue::Null, FilterValue::Null) => Some(Ordering::Equal),
(FilterValue::Bool(a), FilterValue::Bool(b)) => a.partial_cmp(b),
(FilterValue::Number(a), FilterValue::Number(b)) => a.partial_cmp(b),
(FilterValue::String(a), FilterValue::String(b)) => a.partial_cmp(b),
(FilterValue::Tuple(a), FilterValue::Tuple(b)) => {
if a.len() != b.len() {
a.len().partial_cmp(&b.len())

Check warning on line 105 in src/filter/value.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/value.rs#L97-L105

Added lines #L97 - L105 were not covered by tests
} else {
a.iter()
.zip(b.iter())
.map(|(x, y)| x.partial_cmp(y))
.find(|&cmp| cmp != Some(Ordering::Equal))
.unwrap_or(Some(Ordering::Equal))

Check warning on line 111 in src/filter/value.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/value.rs#L107-L111

Added lines #L107 - L111 were not covered by tests
}
}
_ => None, // Return None for non-comparable types

Check warning on line 114 in src/filter/value.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/value.rs#L114

Added line #L114 was not covered by tests
}
}

Check warning on line 116 in src/filter/value.rs

View check run for this annotation

Codecov / codecov/patch

src/filter/value.rs#L116

Added line #L116 was not covered by tests

fn lt(&self, other: &Self) -> bool {
match (self, other) {
(FilterValue::Null, FilterValue::Null) => true,
Expand Down Expand Up @@ -145,27 +166,6 @@
_ => false,
}
}

fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
match (self, other) {
(FilterValue::Null, FilterValue::Null) => Some(Ordering::Equal),
(FilterValue::Bool(a), FilterValue::Bool(b)) => a.partial_cmp(b),
(FilterValue::Number(a), FilterValue::Number(b)) => a.partial_cmp(b),
(FilterValue::String(a), FilterValue::String(b)) => a.partial_cmp(b),
(FilterValue::Tuple(a), FilterValue::Tuple(b)) => {
if a.len() != b.len() {
a.len().partial_cmp(&b.len())
} else {
a.iter()
.zip(b.iter())
.map(|(x, y)| x.partial_cmp(y))
.find(|&cmp| cmp != Some(Ordering::Equal))
.unwrap_or(Some(Ordering::Equal))
}
}
_ => None, // Return None for non-comparable types
}
}
}

impl Display for FilterValue {
Expand Down
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@
.and_then(|s| s.find_next_occurrence(&chrono::Utc::now(), false).ok());

{
let _span = tracing::info_span!("backup.all").entered();
let _span = info_span!("backup.all").entered();

Check warning on line 73 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L73

Added line #L73 was not covered by tests

for policy in config.backups.iter() {
let _policy_span = tracing::info_span!("backup.policy", policy = %policy).entered();
let _policy_span = info_span!("backup.policy", policy = %policy).entered();

Check warning on line 76 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L76

Added line #L76 was not covered by tests

match policy.kind.as_str() {
k if k == GitHubArtifactKind::Repo.as_str() => {
Expand Down Expand Up @@ -130,7 +130,7 @@
info!(" - {} ({})", entity, state);
}

fn on_error(&self, error: crate::Error) {
fn on_error(&self, error: Error) {

Check warning on line 133 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L133

Added line #L133 was not covered by tests
warn!("Error: {}", error);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/telemetry/traced_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct TracedStream<T: Stream> {
}

pub trait StreamExt: Stream + Sized {
fn trace(self, span: tracing::Span) -> TracedStream<Self> {
fn trace(self, span: Span) -> TracedStream<Self> {
TracedStream { stream: self, span }
}
}
Expand Down
Loading