Skip to content

Commit

Permalink
Merge pull request #34 from tamada/release/v0.6.0
Browse files Browse the repository at this point in the history
Release/v0.6.0
  • Loading branch information
tamada authored Aug 16, 2024
2 parents 8e34824 + 8625849 commit a0c38c4
Show file tree
Hide file tree
Showing 17 changed files with 469 additions and 152 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ jobs:
- name: Create release
id: create_release
uses: marvinpinto/action-automatic-releases@latest
uses: softprops/action-gh-release@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
automatic_release_tag: v${{ steps.vars.outputs.tag }}
title: Release v${{ steps.vars.outputs.tag }}
tag_name: v${{ steps.vars.outputs.tag }}
name: Release v${{ steps.vars.outputs.tag }}
draft: false
prerelease: false

Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "totebag"
version = "0.5.2"
version = "0.6.0"
description = "A tool for extracting/archiving files and directories in multiple formats."
repository = "https://github.com/tamada/totebag"
readme = "README.md"
Expand All @@ -15,6 +15,7 @@ edition = "2021"

[dependencies]
bzip2 = "0.4.4"
cab = "0.6.0"
clap = { version = "4.5.4", features = ["derive"] }
delharc = "0.6.1"
flate2 = "1.0.29"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# totebag

[![Version](https://shields.io/badge/Version-0.5.2-blue)](https://github.com/tamada/totebag/releases/tag/v0.5.2)
[![Version](https://shields.io/badge/Version-0.6.0-blue)](https://github.com/tamada/totebag/releases/tag/v0.6.0)
[![MIT License](https://shields.io/badge/License-MIT-blue)](https://github.com/tamada/totebag/blob/main/LICENSE)
[![docker](https://shields.io/badge/Docker-0.5.2-blue?logo=docker)](https://github.com/tamada/totebag/pkgs/container/totebag)
[![docker](https://shields.io/badge/Docker-0.6.0-blue?logo=docker)](https://github.com/tamada/totebag/pkgs/container/totebag)

[![build](https://github.com/tamada/totebag/actions/workflows/build.yaml/badge.svg)](https://github.com/tamada/totebag/actions/workflows/build.yaml)
[![Rust Report Card](https://rust-reportcard.xuri.me/badge/github.com/tamada/totebag)](https://rust-reportcard.xuri.me/report/github.com/tamada/totebag)
Expand Down Expand Up @@ -58,7 +58,7 @@ brew install tamada/tap/totebag
## :whale: Docker
```sh
docker run -it --rm -v $PWD:/workdir ghcr.io/tamada/totebag:0.5.2 [OPTIONS] [ARGUMENTS]...
docker run -it --rm -v $PWD:/workdir ghcr.io/tamada/totebag:0.6.0 [OPTIONS] [ARGUMENTS]...
```
- **Working directory**: `/workdir`
Expand Down
4 changes: 2 additions & 2 deletions dockers/alpine/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:3.16 AS builder

ARG VERSION=0.5.2
ARG VERSION=0.6.0
ARG TARGETPLATFORM
ARG PLATFORM=${TARGETPLATFORM#linux/}

Expand All @@ -12,7 +12,7 @@ RUN apk add --no-cache curl tar gzip \

FROM alpine:3.16

ARG VERSION=0.5.2
ARG VERSION=0.6.0

LABEL org.opencontainers.image.source https://github.com/tamada/totebag

Expand Down
46 changes: 35 additions & 11 deletions src/archiver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ use crate::archiver::sevenz::SevenZArchiver;
use crate::archiver::tar::{TarArchiver, TarBz2Archiver, TarGzArchiver, TarXzArchiver, TarZstdArchiver};
use crate::archiver::zip::ZipArchiver;
use crate::cli::{Result, ToteError};
use crate::format::{find_format, Format};
use crate::format::{find_format, is_archive_file, Format};
use crate::verboser::{create_verboser, Verboser};
use crate::CliOpts;

mod cab;
mod lha;
mod os;
mod rar;
Expand All @@ -28,15 +29,16 @@ pub fn create_archiver(dest: &PathBuf) -> Result<Box<dyn Archiver>> {
match format {
Ok(format) => {
return match format {
Format::Zip => Ok(Box::new(ZipArchiver {})),
Format::Cab => Ok(Box::new(cab::CabArchiver {})),
Format::LHA => Ok(Box::new(LhaArchiver {})),
Format::Rar => Ok(Box::new(RarArchiver {})),
Format::SevenZ => Ok(Box::new(SevenZArchiver {})),
Format::Tar => Ok(Box::new(TarArchiver {})),
Format::TarGz => Ok(Box::new(TarGzArchiver {})),
Format::TarBz2 => Ok(Box::new(TarBz2Archiver {})),
Format::TarGz => Ok(Box::new(TarGzArchiver {})),
Format::TarXz => Ok(Box::new(TarXzArchiver {})),
Format::TarZstd => Ok(Box::new(TarZstdArchiver {})),
Format::LHA => Ok(Box::new(LhaArchiver {})),
Format::Rar => Ok(Box::new(RarArchiver {})),
Format::SevenZ => Ok(Box::new(SevenZArchiver {})),
Format::Zip => Ok(Box::new(ZipArchiver {})),
_ => Err(ToteError::UnknownFormat(format.to_string())),
}
}
Expand All @@ -60,18 +62,34 @@ pub fn archiver_info(archiver: &Box<dyn Archiver>, opts: &ArchiverOpts) -> Strin
pub struct ArchiverOpts {
pub dest: PathBuf,
pub targets: Vec<PathBuf>,
pub base_dir: PathBuf,
pub overwrite: bool,
pub recursive: bool,
pub v: Box<dyn Verboser>,
}

fn find_dest_and_args(opts: &CliOpts) -> (PathBuf, Vec<PathBuf>) {
match &opts.output {
Some(o) => (o.clone(), opts.args.clone()),
None => {
if is_archive_file(&opts.args[0]) {
let file = opts.args[0].clone();
let args = opts.args[1..].to_vec();
(file, args)
} else {
(PathBuf::from("totebag.zip"), opts.args.clone())
}
}
}
}

impl ArchiverOpts {
pub fn new(opts: &CliOpts) -> Self {
let args = opts.args.clone();
let dest = opts.output.clone().unwrap_or_else(|| PathBuf::from("."));
let (dest, args) = find_dest_and_args(&opts);
ArchiverOpts {
dest: dest,
targets: args,
base_dir: opts.base_dir.clone(),
overwrite: opts.overwrite,
recursive: !opts.no_recursive,
v: create_verboser(opts.verbose),
Expand All @@ -82,13 +100,15 @@ impl ArchiverOpts {
pub fn create(
dest: PathBuf,
targets: Vec<PathBuf>,
base_dir: PathBuf,
overwrite: bool,
recursive: bool,
verbose: bool,
) -> Self {
ArchiverOpts {
dest,
targets,
base_dir,
overwrite,
recursive,
v: create_verboser(verbose),
Expand Down Expand Up @@ -172,9 +192,13 @@ mod tests {
assert!(a9.is_ok());
assert_eq!(a9.unwrap().format(), Format::LHA);

let a10 = create_archiver(&PathBuf::from("results/test.unknown"));
assert!(a10.is_err());
if let Err(e) = a10 {
let a10 = create_archiver(&PathBuf::from("results/test.cab"));
assert!(a10.is_ok());
assert_eq!(a10.unwrap().format(), Format::Cab);

let ae = create_archiver(&PathBuf::from("results/test.unknown"));
assert!(ae.is_err());
if let Err(e) = ae {
if let ToteError::UnknownFormat(msg) = e {
assert_eq!(msg, "test.unknown: unknown format".to_string());
} else {
Expand Down
133 changes: 133 additions & 0 deletions src/archiver/cab.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use std::fs::File;
use std::path::PathBuf;

use cab::CabinetBuilder;

use crate::archiver::{Archiver, ArchiverOpts};
use crate::cli::{ToteError, Result};
use crate::format::Format;

pub(super) struct CabArchiver {
}

impl Archiver for CabArchiver {
fn perform(&self, opts: &ArchiverOpts) -> Result<()> {
match opts.destination() {
Err(e) => Err(e),
Ok(file) => {
write_impl(file, opts.targets(), opts.recursive, opts.base_dir.clone())
}
}
}

fn format(&self) -> Format {
Format::Cab
}
}

fn write_impl(file: File, targets: Vec<PathBuf>, recursive: bool, base_dir: PathBuf) -> Result<()> {
let mut builder = CabinetBuilder::new();
let folder = builder.add_folder(cab::CompressionType::MsZip);
let list = correct_targets(targets, recursive, base_dir);
for (_from, dest_file) in list.clone() {
folder.add_file(dest_file);
}
let mut writer = match builder.build(file) {
Ok(w) => w,
Err(e) => return Err(ToteError::Archiver(e.to_string())),
};
let mut iter = list.iter();
while let Some(mut w) = writer.next_file().unwrap() {
let (from, _) = iter.next().unwrap();
if let Ok(mut reader) = File::open(from) {
std::io::copy(&mut reader, &mut w).unwrap();
}
}
match writer.finish() {
Ok(_) => Ok(()),
Err(e) => Err(ToteError::Archiver(e.to_string())),
}
}

fn correct_targets(targets: Vec<PathBuf>, recursive: bool, base_dir: PathBuf) -> Vec<(PathBuf, String)> {
let mut result = vec![];
for target in targets {
let path = target.as_path();
if path.is_dir() && recursive {
process_dir(&mut result, path.to_path_buf(), &base_dir);
} else if path.is_file(){
process_file(&mut result, path.to_path_buf(), &base_dir);
}
}
result
}

fn process_dir(result: &mut Vec<(PathBuf, String)>, path: PathBuf, base_dir: &PathBuf) {
for entry in path.read_dir().unwrap() {
if let Ok(e) = entry {
let p = e.path();
if p.is_dir() {
process_dir(result, e.path(), &base_dir)
} else if p.is_file() {
process_file(result, e.path(), &base_dir)
}
}
}
}

fn process_file(result: &mut Vec<(PathBuf, String)>, target: PathBuf, base_dir: &PathBuf) {
let target_path = match target.strip_prefix(base_dir) {
Ok(p) => p.to_path_buf(),
Err(_) => target.clone(),
};
let name = target_path.to_str().unwrap();
result.push((target, name.to_string()));
}

#[cfg(test)]
mod tests {
use super::*;

use std::path::PathBuf;
use crate::verboser::create_verboser;

fn run_test<F>(f: F)
where
F: FnOnce(),
{
// setup(); // 予めやりたい処理
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
teardown(); // 後片付け処理

if let Err(err) = result {
std::panic::resume_unwind(err);
}
}

#[test]
fn test_format() {
let archiver = CabArchiver{};
assert_eq!(archiver.format(), Format::Cab);
}

#[test]
fn test_archive() {
run_test(|| {
let archiver = CabArchiver{};
let opts = ArchiverOpts {
dest: PathBuf::from("results/test.cab"),
targets: vec![PathBuf::from("src"), PathBuf::from("Cargo.toml")],
base_dir: PathBuf::from("."),
overwrite: false,
recursive: false,
v: create_verboser(false),
};
let r = archiver.perform(&opts);
assert!(r.is_ok());
});
}

fn teardown() {
let _ = std::fs::remove_file("results/test.cab");
}
}
22 changes: 12 additions & 10 deletions src/archiver/lha.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::archiver::{Archiver, Format, ArchiverOpts};
use crate::cli::{ToteError, Result};
use crate::archiver::{Archiver, ArchiverOpts, Format};
use crate::cli::{Result, ToteError};

pub(super) struct LhaArchiver {
}
pub(super) struct LhaArchiver {}

impl Archiver for LhaArchiver {
impl Archiver for LhaArchiver {
fn perform(&self, _: &ArchiverOpts) -> Result<()> {
Err(ToteError::UnsupportedFormat("only extraction support for lha".to_string()))
Err(ToteError::UnsupportedFormat(
"only extraction support for lha".to_string(),
))
}
fn format(&self) -> Format {
Format::LHA
Expand All @@ -17,21 +18,22 @@ impl Archiver for LhaArchiver {
mod tests {
use super::*;

use std::path::PathBuf;
use crate::verboser::create_verboser;
use std::path::PathBuf;

#[test]
fn test_format() {
let archiver = LhaArchiver{};
let archiver = LhaArchiver {};
assert_eq!(archiver.format(), Format::LHA);
}

#[test]
fn test_archive() {
let archiver = LhaArchiver{};
let archiver = LhaArchiver {};
let opts = ArchiverOpts {
dest: PathBuf::from("results/test.rar"),
dest: PathBuf::from("results/test.lzh"),
targets: vec![],
base_dir: PathBuf::from("."),
overwrite: false,
recursive: false,
v: create_verboser(false),
Expand Down
20 changes: 11 additions & 9 deletions src/archiver/rar.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::archiver::{Archiver, Format, ArchiverOpts};
use crate::cli::{ToteError, Result};
use crate::archiver::{Archiver, ArchiverOpts, Format};
use crate::cli::{Result, ToteError};

pub(super) struct RarArchiver {
}
pub(super) struct RarArchiver {}

impl Archiver for RarArchiver {
impl Archiver for RarArchiver {
fn perform(&self, _: &ArchiverOpts) -> Result<()> {
Err(ToteError::UnsupportedFormat("only extraction support for rar".to_string()))
Err(ToteError::UnsupportedFormat(
"only extraction support for rar".to_string(),
))
}
fn format(&self) -> Format {
Format::Rar
Expand All @@ -17,21 +18,22 @@ impl Archiver for RarArchiver {
mod tests {
use super::*;

use std::path::PathBuf;
use crate::verboser::create_verboser;
use std::path::PathBuf;

#[test]
fn test_format() {
let archiver = RarArchiver{};
let archiver = RarArchiver {};
assert_eq!(archiver.format(), Format::Rar);
}

#[test]
fn test_archive() {
let archiver = RarArchiver{};
let archiver = RarArchiver {};
let opts = ArchiverOpts {
dest: PathBuf::from("results/test.rar"),
targets: vec![],
base_dir: PathBuf::from("."),
overwrite: false,
recursive: false,
v: create_verboser(false),
Expand Down
Loading

0 comments on commit a0c38c4

Please sign in to comment.