Compare commits

..

9 Commits

Author SHA1 Message Date
Thomas Eppers
8a35904c79 bumped version to 0.11.0
All checks were successful
continuous-integration/woodpecker the build was successful
2021-10-28 18:41:28 +02:00
Thomas Eppers
c55ccf005b updated screenshot
All checks were successful
continuous-integration/woodpecker the build was successful
2021-10-28 18:39:47 +02:00
Thomas Eppers
b6a234a833 imbed screenshot in README
All checks were successful
continuous-integration/woodpecker the build was successful
2021-10-28 17:43:04 +02:00
Thomas Eppers
2a0dee78a7 added woodpecker ci config 2021-10-28 17:42:37 +02:00
Thomas Eppers
b67242d0ea changed program parameter from -c to -f to match docker-compose 2021-10-27 14:15:12 +02:00
Thomas Eppers
7b8e613058 added more Hints for Input 2021-10-27 14:12:23 +02:00
Thomas Eppers
74006af796 added a check to not show an error when load next page of tags 2021-10-27 14:10:07 +02:00
Thomas Eppers
d608fe6b50 changed function next_page from Result to Option 2021-10-27 13:40:55 +02:00
Thomas Eppers
3cfbc2a656 removed unused code 2021-10-27 13:40:41 +02:00
11 changed files with 78 additions and 48 deletions

37
.woodpecker.yml Normal file
View File

@ -0,0 +1,37 @@
# https://woodpecker-ci.org/docs/usage/intro
pipeline:
build_and_test:
image: rust
commands:
- cargo test
- cargo build --release
gitea_on_release:
# http://plugins.drone.io/drone-plugins/drone-gitea-release/
image: plugins/gitea-release
files: target/release/reel-moby
secrets: [gitea_release_api_key, gitea_release_base_url]
when:
event: tag
tag: v*
github_on_release:
# http://plugins.drone.io/drone-plugins/drone-github-release/
image: plugins/github-release
files: target/release/reel-moby
secrets: [github_release_api_key]
when:
event: tag
tag: v*
notify_when_failure:
# http://plugins.drone.io/appleboy/drone-discord/
image: appleboy/drone-discord
secrets: [ discord_webhook_id, discord_webhook_token]
message: "build {{build.number}} or release failed. Fix me please."
when:
status: failure
# http://plugins.drone.io/drone-plugins/drone-github-release/

View File

@ -1,7 +1,7 @@
[package] [package]
name = "reel-moby" name = "reel-moby"
version = "0.10.0" version = "0.11.0"
edition = "2018" edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -7,4 +7,4 @@ search for new docker tags and update them in your docker-compose file
Searches the current folder for a docker-compose.(yml|yaml) file and opens it when it found one. Then it is possible to select a image line. The program then shows the found repository and shows the latest tags. The tags can be scrolled and selected, which updates the opened file. Searches the current folder for a docker-compose.(yml|yaml) file and opens it when it found one. Then it is possible to select a image line. The program then shows the found repository and shows the latest tags. The tags can be scrolled and selected, which updates the opened file.
From that point save the file and pull the new image with `docker-compose up -d` or `docker-compse pull`. From that point save the file and pull the new image with `docker-compose up -d` or `docker-compse pull`.
[screenshot](./screenshot.png) ![screenshot](./screenshot.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -15,7 +15,7 @@ pub struct Opt {
/// A custom path to a docker-compose file /// A custom path to a docker-compose file
#[structopt(short, long, parse(from_os_str))] #[structopt(short, long, parse(from_os_str))]
config: Option<PathBuf>, file: Option<PathBuf>,
/// Give a Repository identifier, e.g. library/nginx /// Give a Repository identifier, e.g. library/nginx
#[structopt(short, long, parse(from_str))] #[structopt(short, long, parse(from_str))]

View File

@ -2,24 +2,16 @@ use std::fmt;
use regex::Regex; use regex::Regex;
// use crate::common;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
// Conversion,
// Empty,
NoTagFound, NoTagFound,
// InvalidChar,
MisformedInput, MisformedInput,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
// Error::Conversion => write!(f, "Conversion error"),
// Error::Empty => write!(f, "Input is empty"),
Error::NoTagFound => write!(f, "Expected a tag"), Error::NoTagFound => write!(f, "Expected a tag"),
// Error::InvalidChar => write!(f, "Invalid character found"),
Error::MisformedInput => write!(f, "Unexpected input"), Error::MisformedInput => write!(f, "Unexpected input"),
} }
} }

View File

@ -7,7 +7,6 @@ use serde::Deserialize;
#[derive(Deserialize, Debug, Clone)] #[derive(Deserialize, Debug, Clone)]
struct ImageDetails { struct ImageDetails {
architecture: String, architecture: String,
// os: String,
size: usize, size: usize,
} }
@ -25,6 +24,30 @@ pub struct Images {
last_updated: String, last_updated: String,
} }
impl fmt::Display for Images {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//architecture infos
let mut arch = String::new();
for image in self.images.iter().take(1) {
arch.push_str(&format!("{}", image));
}
for image in self.images.iter().skip(1) {
arch.push_str(&format!(", {}", image));
}
let now = chrono::Utc::now();
let rfc3339 = DateTime::parse_from_rfc3339(&self.last_updated).unwrap();
let dif = now - rfc3339.with_timezone(&chrono::Utc);
write!(
f,
"{} vor {} [{}]",
self.tag_name,
format_time_nice(dif),
arch
)
}
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Tags { pub struct Tags {
count: usize, count: usize,
@ -41,7 +64,6 @@ pub enum Error {
Converting(String), Converting(String),
/// invalid repos show a valid json with 0 tags /// invalid repos show a valid json with 0 tags
NoTagsFound, NoTagsFound,
NoNextPage,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -49,7 +71,6 @@ impl fmt::Display for Error {
match self { match self {
Error::Fetching(s) => write!(f, "Fetching error: {}", s), Error::Fetching(s) => write!(f, "Fetching error: {}", s),
Error::Converting(s) => write!(f, "Converting error: {}", s), Error::Converting(s) => write!(f, "Converting error: {}", s),
Error::NoNextPage => write!(f, "No next page available"),
Error::NoTagsFound => write!(f, "Given Repo has 0 tags. Is it valid?"), Error::NoTagsFound => write!(f, "Given Repo has 0 tags. Is it valid?"),
} }
} }
@ -98,38 +119,17 @@ impl Tags {
} }
/// returns tags of next page /// returns tags of next page
pub fn next_page(&self) -> Result<Self, Error> { pub fn next_page(&self) -> Option<Self> {
match &self.next_page { match &self.next_page {
Some(url) => Self::with_url(url), Some(url) => match Self::with_url(url) {
None => Err(Error::NoNextPage), Ok(tags) => Some(tags),
Err(_) => None,
},
None => None,
} }
} }
} }
impl fmt::Display for Images {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
//architecture infos
let mut arch = String::new();
for image in self.images.iter().take(1) {
arch.push_str(&format!("{}", image));
}
for image in self.images.iter().skip(1) {
arch.push_str(&format!(", {}", image));
}
let now = chrono::Utc::now();
let rfc3339 = DateTime::parse_from_rfc3339(&self.last_updated).unwrap();
let dif = now - rfc3339.with_timezone(&chrono::Utc);
write!(
f,
"{} vor {} [{}]",
self.tag_name,
format_time_nice(dif),
arch
)
}
}
/// converts a given duration to a readable string /// converts a given duration to a readable string
fn format_time_nice(time: chrono::Duration) -> String { fn format_time_nice(time: chrono::Duration) -> String {
if time.num_weeks() == 52 { if time.num_weeks() == 52 {

View File

@ -54,7 +54,7 @@ impl Ui {
state: State::SelectService, state: State::SelectService,
repo: repo_entry::RepoEntry::new(repo_id), repo: repo_entry::RepoEntry::new(repo_id),
tags: tag_list::TagList::with_status("Tags are empty"), tags: tag_list::TagList::with_status("Tags are empty"),
services: service_switcher::ServiceSwitcher::new(&opt.config).unwrap(), services: service_switcher::ServiceSwitcher::new(&opt.file).unwrap(),
info: info::Info::new("Select image of edit Repository"), info: info::Info::new("Select image of edit Repository"),
}; };
@ -122,6 +122,7 @@ impl Ui {
State::SelectTag => { State::SelectTag => {
let mut repo = ui.repo.get(); let mut repo = ui.repo.get();
let tag = match ui.tags.get_selected() { let tag = match ui.tags.get_selected() {
Err(tag_list::Error::NextPageSelected) => continue,
Err(e) => { Err(e) => {
ui.info.set_info(&format!("{}", e)); ui.info.set_info(&format!("{}", e));
continue; continue;

View File

@ -10,7 +10,7 @@ use termion::input::TermRead;
use crate::widget::service_switcher; use crate::widget::service_switcher;
pub fn create_ui(opt: &Opt) { pub fn create_ui(opt: &Opt) {
let service_result = service_switcher::ServiceSwitcher::new(&opt.config); let service_result = service_switcher::ServiceSwitcher::new(&opt.file);
match service_result { match service_result {
None => no_yaml::NoYaml::run(opt), None => no_yaml::NoYaml::run(opt),
Some(_) => default::Ui::run(opt), Some(_) => default::Ui::run(opt),

View File

@ -11,7 +11,7 @@ impl Info {
Self { Self {
info: String::from(info), info: String::from(info),
keys: String::from( keys: String::from(
"Tab Cycle widgets C-s Save C-r Reload C-q Quit ↑ ↓ Select tags or image line", "Tab Cycle widgets C-s Save C-r Reload C-q Quit ↑ ↓ Select tags or image line Return Select current selection",
), ),
} }
} }

View File

@ -68,8 +68,8 @@ impl TagList {
.collect(); .collect();
match tags.next_page() { match tags.next_page() {
Err(_) => (), None => (),
Ok(new_tags) => { Some(new_tags) => {
lines.push(Line::NextPage(String::from("load more tags"))); lines.push(Line::NextPage(String::from("load more tags")));
tags = new_tags; tags = new_tags;
} }
@ -149,8 +149,8 @@ impl TagList {
fn load_next_page(&mut self) { fn load_next_page(&mut self) {
match &self.tags { match &self.tags {
Some(tags) => match tags.next_page() { Some(tags) => match tags.next_page() {
Err(_) => (), None => (),
Ok(new_tags) => { Some(new_tags) => {
//load new tags object //load new tags object
self.tags = Some(new_tags); self.tags = Some(new_tags);