views:

161

answers:

2

Does anyone know if it is possible to directly edit file metadata on OS X. Specifically in perl. The parameter I'm specifically trying to change is kMDItemFSLabel (The color of the file). I've had a search around and I can't seem to find a way to do this without using a module such as Mac::Glue or an external application (Finder).

+1  A: 

There is no built-in function in Perl to operate on Mac filesystem metadata. Either your use a library from CPAN, or write it yourself, probably not as well as the author of the one in CPAN did.

Wooble
+7  A: 

The kMDItemFSLabel attribute is a property of the Finder. You need to use a way to communicate with the Finder to change its data. As far as I know, there is no bit you can twiddle with Perl to change the Finder's data without going through the Finder.

There are several ways to do this:

  1. Use CamelBones when the new version comes out. That allows a bridge to Objective C from Perl. Then you will need to use the Apple method with Cocoa system calls. Steep learning curve for Cocoa...

  2. If you have developer tools, use /Developer/Tools/SetFile (if that supports the metadata item)

  3. Use osascript to send the message to the Finder to change the color of the file. You can look at this earlier SO post for hints on doing that.

Most of the Perl related Objective C / Cocoa bridges have died unfortunately. MacPerl has not been updated since 2005.

Almost all the easiest methods require knowing at least minimal amount of Applescript and calling the text of that script though an interpolated type call to osascript.

In its 1 line form, osascript makes Perl look beautiful:

osascript -e 'tell application "Finder"' -e "activate" -e "display dialog \"hello\"" -e 'end tell'

To use osascript from Perl, most use a HERE document. There are examples from I book I have called Applescript - The Definitive Guide and from brian d foy on Controlling iTunes with Perl.

Here is a script in Perl I wrote for setting file color using osascript:

#!/usr/bin/perl
use strict; use warnings;
use File::Spec;
use String::ShellQuote; 

sub osahere  { 
    my $rtr;
    my $scr='osascript -ss -e '."'".join ('',@_)."'";
    open my $fh, '-|', $scr or die "death on osascript $!";
    $rtr=do { local $/; <$fh> };
    close $fh or die "death on osascript $!";
    return $rtr;
}

sub set_file_color {
# -- No color = 0
# -- Orange = 1
# -- Red = 2
# -- Yellow = 3
# -- Blue = 4
# -- Purple = 5
# -- Green = 6
# -- Gray = 7

my $file=shift;
my $color=shift || 0;
$color=0 if $color<0;
$color=7 if $color>7;

$file=File::Spec->rel2abs($file) 
    unless File::Spec->file_name_is_absolute( $file );
$file=shell_quote($file);

return undef unless -e $file;

my $rtr=osahere <<"END_SET_COLOR" ;
tell application "Finder"
    set f to "$file"
    set ItemToLabel to POSIX file f as alias
    set the label index of ItemToLabel to $color
end tell
END_SET_COLOR

return $rtr;
}

set_file_color("2591.txt",2);

If the Finder color is 0, kMDItemFSLabel is 0. If there is any color set, kMDItemFSLabel becomes 8-color. ie, label "orange" is label index 1, kMDItemFSLabel = 7; label "red" is label index 2, kMDItemFSLabel = 6; and so on.

drewk
Thank you for the awesome answer. This was exactly what I was looking for.
Leda
You are welcome
drewk