diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2503062 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,70 @@ +on: + release: + types: [created] + +jobs: + release: + name: release ${{ matrix.target }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + archive: tar.gz + - target: x86_64-apple-darwin + os: macos-latest + archive: tar.gz + - target: x86_64-pc-windows-gnu + os: windows-latest + archive: zip + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + shared-key: ${{matrix.target}}-cache + + - name: Compile binaries + run: | + cargo build --verbose --release + if [ "${{ matrix.os }}" = "windows-latest" ]; then + bin="target/release/metaframer.exe" + else + bin="target/release/metaframer" + fi + echo "BIN=$bin" >> $GITHUB_ENV + + - name: Determine archive name + run: | + echo "ARCHIVE=metaframer-${{ github.event.tag_name }}-${{ matrix.target }}" >> $GITHUB_ENV + + - name: Create archive + run: | + mkdir -p "$ARCHIVE" + cp "$BIN" "$ARCHIVE"/ + cp {README.md,LICENSE} "$ARCHIVE"/ + + - name: Build archive (zip) + shell: bash + if: matrix.archive == 'zip' + run: | + 7z a "$ARCHIVE.zip" "$ARCHIVE" + certutil -hashfile "$ARCHIVE.zip" SHA256 > "$ARCHIVE.zip.sha256" + echo "ASSET=$ARCHIVE.zip" >> $GITHUB_ENV + echo "ASSET_SUM=$ARCHIVE.zip.sha256" >> $GITHUB_ENV + + - name: Build archive (Unix) + shell: bash + if: matrix.archive == 'tar.gz' + run: | + tar czf "$ARCHIVE.tar.gz" "$ARCHIVE" + shasum -a 256 "$ARCHIVE.tar.gz" > "$ARCHIVE.tar.gz.sha256" + echo "ASSET=$ARCHIVE.tar.gz" >> $GITHUB_ENV + echo "ASSET_SUM=$ARCHIVE.tar.gz.sha256" >> $GITHUB_ENV + + - name: Upload release archive + run: gh release upload "${{ github.event.tag_name }}" ${{ env.ASSET }} ${{ env.ASSET_SUM }} diff --git a/build.rs b/build.rs deleted file mode 100644 index 675598f..0000000 --- a/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::fs; -use std::path::Path; - -fn main() { - let config_dir = dirs::config_dir().unwrap(); - let dest_path = Path::new(&config_dir).join("metaframer/templates"); - - // Create the destination directory if it doesn't exist - fs::create_dir_all(&dest_path).unwrap(); - - // Copy the template files to the destination directory - for entry in fs::read_dir("templates").unwrap() { - let entry = entry.unwrap(); - let path = entry.path(); - if path.is_file() { - let filename = path.file_name().unwrap(); - fs::copy(&path, dest_path.join(filename)).unwrap(); - } - } - - // Tell Cargo to rerun the build script if the templates change - println!("cargo:rerun-if-changed=templates"); -} diff --git a/src/main.rs b/src/main.rs index a482111..fafd1d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,20 @@ use anyhow::{Context, Result}; use clap::Parser; -use dirs::{self, config_dir}; use handlebars::Handlebars; use log::{debug, error}; use resolution::Resolution; -use std::{fs::File, io::BufReader, path::PathBuf}; +use std::{ + fs::File, + io::BufReader, + path::{Path, PathBuf}, +}; +use templates::{copy_default_template, init_templates_if_needed, register_templates}; use crate::resolution::get_frame_width; mod framer; mod resolution; +mod templates; #[derive(Parser)] #[command(version, about, long_about = None)] // Read from `Cargo.toml` @@ -28,6 +33,14 @@ struct CliArgs { #[arg(long = "height", default_value_t = 40)] frame_height: u8, + /// Instruct to overwrite default configuration and templates + #[arg(long = "reset")] + reset: bool, + + /// Instruct to overwrite default configuration and templates + #[arg(short, long = "template", default_value = "default")] + template_name: String, + /// Specifies whether generated frames will not take any height of the target #[arg(short, long)] inset: bool, @@ -41,70 +54,18 @@ fn main() -> Result<()> { env_logger::Builder::new() .filter_level(args.verbose.log_level_filter()) .init(); + init_templates_if_needed()?; - let config_dir = config_dir().unwrap(); - let templates_path = config_dir.join("metaframer/templates"); - debug!("{:?} templates path", templates_path); + if args.reset { + copy_default_template()?; + } let mut handlebars = Handlebars::new(); - // TODO use custom templates ... like custom from .config/file - handlebars - .register_template_file("default", templates_path.join("default.svg")) - .with_context(|| { - format!( - "could not read template file`{:?}` in `{:?}`", - "default.svg".to_string(), - templates_path - ) - })?; - - handlebars - .register_template_file("Camera", templates_path.join("camera-icon.svg")) - .with_context(|| { - format!( - "could not read template file`{:?}` in {:?}", - "camera-icon.svg".to_string(), - templates_path - ) - })?; - - handlebars - .register_template_file("Aperture", templates_path.join("aperture-icon.svg")) - .with_context(|| { - format!( - "could not read template file`{:?}`", - "aperture-icon.svg".to_string() - ) - })?; - handlebars - .register_template_file( - "ShutterSpeed", - templates_path.join("shutter-speed-icon.svg"), - ) - .with_context(|| { - format!( - "could not read template file`{:?}`", - "shutter-speed-icon.svg".to_string() - ) - })?; - handlebars - .register_template_file("FocalLength", templates_path.join("focal-length-icon.svg")) - .with_context(|| { - format!( - "could not read template file`{:?}`", - "focal-length-icon.svg".to_string() - ) - })?; - handlebars - .register_template_file("Iso", templates_path.join("iso-icon.svg")) - .with_context(|| { - format!( - "could not read template file`{:?}`", - "iso-icon.svg".to_string() - ) - })?; + register_templates(&args.template_name, &mut handlebars)?; + debug!("Files: {:?}", args.paths); debug!("Resolution: {:?}", args.resolution); + debug!("Template name: {:?}", args.template_name); let paths = args.paths.clone(); @@ -120,8 +81,8 @@ fn main() -> Result<()> { Ok(()) } -fn get_frame_path(path: &PathBuf) -> PathBuf { - let mut frame_path = path.clone(); +fn get_frame_path(path: &Path) -> PathBuf { + let mut frame_path = path.to_path_buf(); let orig_file_stem = path.file_stem().unwrap(); frame_path.set_file_name(format!("{}_frame", orig_file_stem.to_str().unwrap())); frame_path.set_extension("svg"); @@ -129,14 +90,13 @@ fn get_frame_path(path: &PathBuf) -> PathBuf { frame_path } -fn process_file(handlebars: &Handlebars<'_>, args: &CliArgs, path: &PathBuf) -> Result<()> { - let file = File::open(path.clone()) - .with_context(|| format!("could not read file `{:?}`", path.clone()))?; +fn process_file(handlebars: &Handlebars<'_>, args: &CliArgs, path: &Path) -> Result<()> { + let file = File::open(path).with_context(|| format!("could not read file `{:?}`", path))?; let mut bufreader = BufReader::new(&file); let exifreader = exif::Reader::new(); let exif = exifreader .read_from_container(&mut bufreader) - .with_context(|| format!("file `{:?}` is not a valid image", path.clone()))?; + .with_context(|| format!("file `{:?}` is not a valid image", path))?; for f in exif.fields() { debug!( "{} {} {}", @@ -146,12 +106,12 @@ fn process_file(handlebars: &Handlebars<'_>, args: &CliArgs, path: &PathBuf) -> ); } - let dimensions = image::image_dimensions(path.clone())?; + let dimensions = image::image_dimensions(path)?; let excluded_height = if args.inset { 0 } else { args.frame_height }; let frame_width = get_frame_width(args.resolution, args.portrait, dimensions, excluded_height); let frame_data = framer::get_frame_data((frame_width, args.frame_height as u32), &exif)?; - let mut output_file = File::create(get_frame_path(&path))?; - handlebars.render_to_write("default", &frame_data, &mut output_file)?; + let mut output_file = File::create(get_frame_path(path))?; + handlebars.render_to_write("main", &frame_data, &mut output_file)?; Ok(()) } diff --git a/src/templates.rs b/src/templates.rs new file mode 100644 index 0000000..1eed1fe --- /dev/null +++ b/src/templates.rs @@ -0,0 +1,127 @@ +use anyhow::Context; +use dirs::{self, config_dir}; +use handlebars::{self, Handlebars}; +use log::debug; +use std::fs; +use std::path::{Path, PathBuf}; + +pub fn get_templates_path(template_name: &str) -> PathBuf { + let config_dir = config_dir().unwrap(); + let dest_path = Path::new(&config_dir) + .join("metaframer/templates/") + .join(template_name); + dest_path +} + +pub fn init_templates_if_needed() -> Result<(), anyhow::Error> { + let default_template_path = get_templates_path("default"); + if default_template_path.exists() { + return Ok(()); + } + copy_default_template()?; + Ok(()) +} + +/** + * Exctracts default templates overwriting if any change was made by user + */ +pub fn copy_default_template() -> Result<(), anyhow::Error> { + // Create the destination directory if it doesn't exist + let default_template_path = get_templates_path("default"); + fs::create_dir_all(&default_template_path)?; + + // Copy the template files to the destination directory + let default_template_files = [ + ("main.svg", include_str!("../templates/default/main.svg")), + ( + "iso-icon.svg", + include_str!("../templates/default/iso-icon.svg"), + ), + ( + "camera-icon.svg", + include_str!("../templates/default/camera-icon.svg"), + ), + ( + "aperture-icon.svg", + include_str!("../templates/default/aperture-icon.svg"), + ), + ( + "focal-length-icon.svg", + include_str!("../templates/default/focal-length-icon.svg"), + ), + ( + "shutter-speed-icon.svg", + include_str!("../templates/default/shutter-speed-icon.svg"), + ), + ]; + + for (name, content) in default_template_files { + let path = default_template_path.join(name); + fs::write(&path, content)?; + } + Ok(()) +} + +pub fn register_templates( + template_name: &str, + handlebars: &mut Handlebars, +) -> Result<(), anyhow::Error> { + let templates_path = get_templates_path(template_name); + debug!("{:?} templates path", templates_path); + handlebars + .register_template_file("main", templates_path.join("main.svg")) + .with_context(|| { + format!( + "could not read template file`{:?}` in `{:?}`", + "main.svg".to_string(), + templates_path + ) + })?; + + handlebars + .register_template_file("Camera", templates_path.join("camera-icon.svg")) + .with_context(|| { + format!( + "could not read template file`{:?}` in {:?}", + "camera-icon.svg".to_string(), + templates_path + ) + })?; + + handlebars + .register_template_file("Aperture", templates_path.join("aperture-icon.svg")) + .with_context(|| { + format!( + "could not read template file`{:?}`", + "aperture-icon.svg".to_string() + ) + })?; + handlebars + .register_template_file( + "ShutterSpeed", + templates_path.join("shutter-speed-icon.svg"), + ) + .with_context(|| { + format!( + "could not read template file`{:?}`", + "shutter-speed-icon.svg".to_string() + ) + })?; + handlebars + .register_template_file("FocalLength", templates_path.join("focal-length-icon.svg")) + .with_context(|| { + format!( + "could not read template file`{:?}`", + "focal-length-icon.svg".to_string() + ) + })?; + handlebars + .register_template_file("Iso", templates_path.join("iso-icon.svg")) + .with_context(|| { + format!( + "could not read template file`{:?}`", + "iso-icon.svg".to_string() + ) + })?; + Ok(()) +} diff --git a/templates/aperture-icon.svg b/templates/default/aperture-icon.svg similarity index 100% rename from templates/aperture-icon.svg rename to templates/default/aperture-icon.svg diff --git a/templates/camera-icon.svg b/templates/default/camera-icon.svg similarity index 100% rename from templates/camera-icon.svg rename to templates/default/camera-icon.svg diff --git a/templates/focal-length-icon.svg b/templates/default/focal-length-icon.svg similarity index 100% rename from templates/focal-length-icon.svg rename to templates/default/focal-length-icon.svg diff --git a/templates/iso-icon.svg b/templates/default/iso-icon.svg similarity index 100% rename from templates/iso-icon.svg rename to templates/default/iso-icon.svg diff --git a/templates/default.svg b/templates/default/main.svg similarity index 100% rename from templates/default.svg rename to templates/default/main.svg diff --git a/templates/shutter-speed-icon.svg b/templates/default/shutter-speed-icon.svg similarity index 100% rename from templates/shutter-speed-icon.svg rename to templates/default/shutter-speed-icon.svg