Skip to content

Commit

Permalink
Merge branch 'fix-assignment'
Browse files Browse the repository at this point in the history
Fixes #75
  • Loading branch information
lgarron committed Jan 7, 2024
2 parents 23c336a + c57429d commit 8249535
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 18 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ You should see a bunch of new `.iconset` folders and `.icns` files that were aut
- [ImageMagick](https://www.imagemagick.org/) - for image processing (you should be able to run <code>convert</code> and <code>identify</code> on the commandline).
- Included with macOS:
- `iconutil`
- `sips`, `DeRez`, `Rez`, `SetFile` (You need Xcode command line tools for some of these.)
- Optional:
- [`fileicon`](https://github.com/mklement0/fileicon/)
- `sips`, `DeRez`, `Rez`, `SetFile` (You need Xcode command line tools for some of these.)

## Full options

Expand Down
3 changes: 3 additions & 0 deletions src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const IDENTIFY_COMMAND: &str = "identify";
pub(crate) const ICONUTIL_COMMAND: &str = "iconutil";
pub(crate) const OPEN_COMMAND: &str = "open";

pub(crate) const OSASCRIPT_COMMAND: &str = "osascript";
pub(crate) const FILEICON_COMMAND: &str = "fileicon";

pub(crate) const SIPS_COMMAND: &str = "sips";
pub(crate) const DEREZ_COMMAND: &str = "DeRez";
pub(crate) const REZ_COMMAND: &str = "Rez";
Expand Down
85 changes: 75 additions & 10 deletions src/icon_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,32 @@ const RETINA_SCALE: u32 = 2;
pub enum ProgressBarType {
Input,
Conversion,
OutputWithIcns,
OutputWithoutIcns,
OutputWithAssignmentDefault,
OutputWithAssignmentUsingRez,
OutputIcns,
}

impl ProgressBarType {
pub fn num_steps(&self) -> u64 {
match self {
ProgressBarType::Input => 1,
ProgressBarType::Conversion => 13,
ProgressBarType::OutputWithIcns => 7,
ProgressBarType::OutputWithoutIcns => 1,
ProgressBarType::OutputWithAssignmentDefault => 2,
ProgressBarType::OutputWithAssignmentUsingRez => 7,
ProgressBarType::OutputIcns => 1,
}
}
}

use crate::{
command::{
run_command, run_convert, DEREZ_COMMAND, ICONUTIL_COMMAND, REZ_COMMAND, SETFILE_COMMAND,
SIPS_COMMAND,
run_command, run_convert, DEREZ_COMMAND, FILEICON_COMMAND, ICONUTIL_COMMAND,
OSASCRIPT_COMMAND, REZ_COMMAND, SETFILE_COMMAND, SIPS_COMMAND,
},
convert::{density, BlurDown, CommandArgs, CompositingOperation},
error::{FolderifyError, GeneralError},
generic_folder_icon::get_folder_icon,
options::{self, ColorScheme, Options},
options::{self, ColorScheme, Options, SetIconUsing},
primitives::{Dimensions, Extent, Offset, RGBColor},
};

Expand Down Expand Up @@ -564,6 +566,71 @@ impl IconConversion {
target_path.display(),
);
}

let assignment_fn = match options.set_icon_using {
SetIconUsing::Fileicon => Self::assign_icns_using_rez,
SetIconUsing::Osascript => Self::assign_icns_using_osascript,
SetIconUsing::Rez => Self::assign_icns_using_fileicon,
};
assignment_fn(self, options, icns_path, target_path)?;

self.step("");

Ok(())
}

pub fn assign_icns_using_osascript(
&self,
_options: &Options,
icns_path: &Path,
target_path: &Path,
) -> Result<(), FolderifyError> {
self.step("Using `osascript` to assign the `.icns` file.");

// Adapted from:
// - https://github.com/mklement0/fileicon/blob/9c41a44fac462f66a1194e223aa26e4c3b9b5ae3/bin/fileicon#L268-L276
// - https://github.com/mklement0/fileicon/issues/32#issuecomment-1074124748
// - https://apple.stackexchange.com/a/161984
let stdin = format!("use framework \"Cocoa\"
set sourcePath to \"{}\"
set destPath to \"{}\"
set imageData to (current application's NSImage's alloc()'s initWithContentsOfFile:sourcePath)
(current application's NSWorkspace's sharedWorkspace()'s setIcon:imageData forFile:destPath options:2)",
icns_path.to_string_lossy(), target_path.to_string_lossy()
);

let args = CommandArgs::new();
run_command(OSASCRIPT_COMMAND, &args, Some(stdin.as_bytes()))?;

// TODO: verify that the icon file exists

Ok(())
}

pub fn assign_icns_using_fileicon(
&self,
_options: &Options,
icns_path: &Path,
target_path: &Path,
) -> Result<(), FolderifyError> {
self.step("Using `fileicon` to assign the `.icns` file.");
let mut args = CommandArgs::new();
args.push("set");
args.push_path(target_path);
args.push_path(icns_path);
run_command(FILEICON_COMMAND, &args, None)?;

Ok(())
}

pub fn assign_icns_using_rez(
&self,
_options: &Options,
icns_path: &Path,
target_path: &Path,
) -> Result<(), FolderifyError> {
let target_is_dir = metadata(target_path)
.expect("Target does not exist!")
.is_dir(); // TODO: Return `FolderifyError`
Expand Down Expand Up @@ -622,9 +689,7 @@ impl IconConversion {
run_command(SETFILE_COMMAND, &args, None)?;
} else {
self.step("Skipping invisible file attribute for file target");
}

self.step("");
};

Ok(())
}
Expand Down
9 changes: 6 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,12 @@ fn main() {
};

// Deduplicate this `match` with the one that happens after handle joining.
let output_progress_bar_type = match output_iconset_only {
Some(_) => icon_conversion::ProgressBarType::OutputWithoutIcns,
None => icon_conversion::ProgressBarType::OutputWithIcns,
let output_progress_bar_type = match (output_iconset_only, &options.set_icon_using) {
(Some(_), _) => icon_conversion::ProgressBarType::OutputIcns,
(None, options::SetIconUsing::Rez) => {
icon_conversion::ProgressBarType::OutputWithAssignmentUsingRez
}
(None, _) => icon_conversion::ProgressBarType::OutputWithAssignmentDefault,
};
let output_icon_conversion =
working_dir.icon_conversion(output_progress_bar_type, "(Output)", multi_progress_bar);
Expand Down
17 changes: 13 additions & 4 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ struct FolderifyArgs {
#[arg(long)]
no_progress: bool,

/// Legacy argument. Now ignored.
/// Program used to set the icon. `osascript` should work in most circumstances, `fileicon` performs more checks, and `rez` produces smaller but less accurate icons.
#[arg(long, hide(true))]
set_icon_using: Option<String>,
set_icon_using: Option<SetIconUsingOrAuto>,

/// Detailed output. Also sets `--no-progress`.
#[clap(short, long)]
Expand Down Expand Up @@ -104,14 +104,16 @@ enum ColorSchemeOrAuto {

#[derive(ValueEnum, Clone, Debug, PartialEq)]
pub enum SetIconUsing {
SetIcon,
Fileicon,
Osascript,
Rez,
}

#[derive(ValueEnum, Clone, Debug, PartialEq)]
enum SetIconUsingOrAuto {
Auto,
SetIcon,
Fileicon,
Osascript,
Rez,
}

Expand All @@ -123,6 +125,7 @@ pub struct Options {
pub target: Option<PathBuf>,
pub output_icns: Option<PathBuf>,
pub output_iconset: Option<PathBuf>,
pub set_icon_using: SetIconUsing,
pub show_progress: bool,
pub reveal: bool,
pub verbose: bool,
Expand Down Expand Up @@ -187,13 +190,19 @@ pub fn get_options() -> Options {
let debug = var("FOLDERIFY_DEBUG") == Ok("1".into());
let verbose = args.verbose || debug;
let show_progress = !args.no_progress && !args.verbose;
let set_icon_using = match args.set_icon_using {
Some(SetIconUsingOrAuto::Rez) => SetIconUsing::Rez,
Some(SetIconUsingOrAuto::Fileicon) => SetIconUsing::Fileicon,
_ => SetIconUsing::Osascript,
};
Options {
mask_path: mask,
color_scheme: map_color_scheme_auto(args.color_scheme),
no_trim: args.no_trim,
target: args.target,
output_icns: args.output_icns,
output_iconset: args.output_iconset,
set_icon_using,
show_progress,
reveal: args.reveal,
verbose,
Expand Down

0 comments on commit 8249535

Please sign in to comment.