Skip to content

Commit 8249535

Browse files
committed
Merge branch 'fix-assignment'
Fixes #75
2 parents 23c336a + c57429d commit 8249535

File tree

5 files changed

+100
-18
lines changed

5 files changed

+100
-18
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ You should see a bunch of new `.iconset` folders and `.icns` files that were aut
112112
- [ImageMagick](https://www.imagemagick.org/) - for image processing (you should be able to run <code>convert</code> and <code>identify</code> on the commandline).
113113
- Included with macOS:
114114
- `iconutil`
115-
- `sips`, `DeRez`, `Rez`, `SetFile` (You need Xcode command line tools for some of these.)
115+
- Optional:
116+
- [`fileicon`](https://github.com/mklement0/fileicon/)
117+
- `sips`, `DeRez`, `Rez`, `SetFile` (You need Xcode command line tools for some of these.)
116118

117119
## Full options
118120

src/command.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ const IDENTIFY_COMMAND: &str = "identify";
1616
pub(crate) const ICONUTIL_COMMAND: &str = "iconutil";
1717
pub(crate) const OPEN_COMMAND: &str = "open";
1818

19+
pub(crate) const OSASCRIPT_COMMAND: &str = "osascript";
20+
pub(crate) const FILEICON_COMMAND: &str = "fileicon";
21+
1922
pub(crate) const SIPS_COMMAND: &str = "sips";
2023
pub(crate) const DEREZ_COMMAND: &str = "DeRez";
2124
pub(crate) const REZ_COMMAND: &str = "Rez";

src/icon_conversion.rs

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,32 @@ const RETINA_SCALE: u32 = 2;
1212
pub enum ProgressBarType {
1313
Input,
1414
Conversion,
15-
OutputWithIcns,
16-
OutputWithoutIcns,
15+
OutputWithAssignmentDefault,
16+
OutputWithAssignmentUsingRez,
17+
OutputIcns,
1718
}
1819

1920
impl ProgressBarType {
2021
pub fn num_steps(&self) -> u64 {
2122
match self {
2223
ProgressBarType::Input => 1,
2324
ProgressBarType::Conversion => 13,
24-
ProgressBarType::OutputWithIcns => 7,
25-
ProgressBarType::OutputWithoutIcns => 1,
25+
ProgressBarType::OutputWithAssignmentDefault => 2,
26+
ProgressBarType::OutputWithAssignmentUsingRez => 7,
27+
ProgressBarType::OutputIcns => 1,
2628
}
2729
}
2830
}
2931

3032
use crate::{
3133
command::{
32-
run_command, run_convert, DEREZ_COMMAND, ICONUTIL_COMMAND, REZ_COMMAND, SETFILE_COMMAND,
33-
SIPS_COMMAND,
34+
run_command, run_convert, DEREZ_COMMAND, FILEICON_COMMAND, ICONUTIL_COMMAND,
35+
OSASCRIPT_COMMAND, REZ_COMMAND, SETFILE_COMMAND, SIPS_COMMAND,
3436
},
3537
convert::{density, BlurDown, CommandArgs, CompositingOperation},
3638
error::{FolderifyError, GeneralError},
3739
generic_folder_icon::get_folder_icon,
38-
options::{self, ColorScheme, Options},
40+
options::{self, ColorScheme, Options, SetIconUsing},
3941
primitives::{Dimensions, Extent, Offset, RGBColor},
4042
};
4143

@@ -564,6 +566,71 @@ impl IconConversion {
564566
target_path.display(),
565567
);
566568
}
569+
570+
let assignment_fn = match options.set_icon_using {
571+
SetIconUsing::Fileicon => Self::assign_icns_using_rez,
572+
SetIconUsing::Osascript => Self::assign_icns_using_osascript,
573+
SetIconUsing::Rez => Self::assign_icns_using_fileicon,
574+
};
575+
assignment_fn(self, options, icns_path, target_path)?;
576+
577+
self.step("");
578+
579+
Ok(())
580+
}
581+
582+
pub fn assign_icns_using_osascript(
583+
&self,
584+
_options: &Options,
585+
icns_path: &Path,
586+
target_path: &Path,
587+
) -> Result<(), FolderifyError> {
588+
self.step("Using `osascript` to assign the `.icns` file.");
589+
590+
// Adapted from:
591+
// - https://github.com/mklement0/fileicon/blob/9c41a44fac462f66a1194e223aa26e4c3b9b5ae3/bin/fileicon#L268-L276
592+
// - https://github.com/mklement0/fileicon/issues/32#issuecomment-1074124748
593+
// - https://apple.stackexchange.com/a/161984
594+
let stdin = format!("use framework \"Cocoa\"
595+
596+
set sourcePath to \"{}\"
597+
set destPath to \"{}\"
598+
599+
set imageData to (current application's NSImage's alloc()'s initWithContentsOfFile:sourcePath)
600+
(current application's NSWorkspace's sharedWorkspace()'s setIcon:imageData forFile:destPath options:2)",
601+
icns_path.to_string_lossy(), target_path.to_string_lossy()
602+
);
603+
604+
let args = CommandArgs::new();
605+
run_command(OSASCRIPT_COMMAND, &args, Some(stdin.as_bytes()))?;
606+
607+
// TODO: verify that the icon file exists
608+
609+
Ok(())
610+
}
611+
612+
pub fn assign_icns_using_fileicon(
613+
&self,
614+
_options: &Options,
615+
icns_path: &Path,
616+
target_path: &Path,
617+
) -> Result<(), FolderifyError> {
618+
self.step("Using `fileicon` to assign the `.icns` file.");
619+
let mut args = CommandArgs::new();
620+
args.push("set");
621+
args.push_path(target_path);
622+
args.push_path(icns_path);
623+
run_command(FILEICON_COMMAND, &args, None)?;
624+
625+
Ok(())
626+
}
627+
628+
pub fn assign_icns_using_rez(
629+
&self,
630+
_options: &Options,
631+
icns_path: &Path,
632+
target_path: &Path,
633+
) -> Result<(), FolderifyError> {
567634
let target_is_dir = metadata(target_path)
568635
.expect("Target does not exist!")
569636
.is_dir(); // TODO: Return `FolderifyError`
@@ -622,9 +689,7 @@ impl IconConversion {
622689
run_command(SETFILE_COMMAND, &args, None)?;
623690
} else {
624691
self.step("Skipping invisible file attribute for file target");
625-
}
626-
627-
self.step("");
692+
};
628693

629694
Ok(())
630695
}

src/main.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,12 @@ fn main() {
9494
};
9595

9696
// Deduplicate this `match` with the one that happens after handle joining.
97-
let output_progress_bar_type = match output_iconset_only {
98-
Some(_) => icon_conversion::ProgressBarType::OutputWithoutIcns,
99-
None => icon_conversion::ProgressBarType::OutputWithIcns,
97+
let output_progress_bar_type = match (output_iconset_only, &options.set_icon_using) {
98+
(Some(_), _) => icon_conversion::ProgressBarType::OutputIcns,
99+
(None, options::SetIconUsing::Rez) => {
100+
icon_conversion::ProgressBarType::OutputWithAssignmentUsingRez
101+
}
102+
(None, _) => icon_conversion::ProgressBarType::OutputWithAssignmentDefault,
100103
};
101104
let output_icon_conversion =
102105
working_dir.icon_conversion(output_progress_bar_type, "(Output)", multi_progress_bar);

src/options.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ struct FolderifyArgs {
5959
#[arg(long)]
6060
no_progress: bool,
6161

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

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

105105
#[derive(ValueEnum, Clone, Debug, PartialEq)]
106106
pub enum SetIconUsing {
107-
SetIcon,
107+
Fileicon,
108+
Osascript,
108109
Rez,
109110
}
110111

111112
#[derive(ValueEnum, Clone, Debug, PartialEq)]
112113
enum SetIconUsingOrAuto {
113114
Auto,
114-
SetIcon,
115+
Fileicon,
116+
Osascript,
115117
Rez,
116118
}
117119

@@ -123,6 +125,7 @@ pub struct Options {
123125
pub target: Option<PathBuf>,
124126
pub output_icns: Option<PathBuf>,
125127
pub output_iconset: Option<PathBuf>,
128+
pub set_icon_using: SetIconUsing,
126129
pub show_progress: bool,
127130
pub reveal: bool,
128131
pub verbose: bool,
@@ -187,13 +190,19 @@ pub fn get_options() -> Options {
187190
let debug = var("FOLDERIFY_DEBUG") == Ok("1".into());
188191
let verbose = args.verbose || debug;
189192
let show_progress = !args.no_progress && !args.verbose;
193+
let set_icon_using = match args.set_icon_using {
194+
Some(SetIconUsingOrAuto::Rez) => SetIconUsing::Rez,
195+
Some(SetIconUsingOrAuto::Fileicon) => SetIconUsing::Fileicon,
196+
_ => SetIconUsing::Osascript,
197+
};
190198
Options {
191199
mask_path: mask,
192200
color_scheme: map_color_scheme_auto(args.color_scheme),
193201
no_trim: args.no_trim,
194202
target: args.target,
195203
output_icns: args.output_icns,
196204
output_iconset: args.output_iconset,
205+
set_icon_using,
197206
show_progress,
198207
reveal: args.reveal,
199208
verbose,

0 commit comments

Comments
 (0)