FileManagerLib Features, etc

They’re not unreasonable requests (well, perhaps apart from the last one — where do you need an alias instead of a file?), but the lib is getting a bit big for my comfort.

The first is just a matter of using rename object, and in AppleScript terms I think that’s arguably more readable code — the extra overhead is tiny. I actually added it to the command at one stage, and I felt it just made the dictionary more complex and potentially confusing.

I can see value in sorting by extension, but I’d need to see arguments for the other options.

Filtering just gets too complicated terminology-wise. NSPredicate is your friend.

I have 20+years of AppleScripts that I’m updating to use with libraries, most of them managing files using finder/system events. While updating these scripts, some still used every day, I came across this in the instructions:
“After you start the script, check your email or get up and stretch your legs, and come back in a few minutes and the script should be done.”

That same script, using FileManagerLib runs in just a few seconds now.

In my case, all of the scripts I’ve written over the years use alias/alias list whenever possible. I just updated one script that was written before Finder had the alias list option, and it has a routine stepping through a list of files, coercing each item to an alias. I’ll use the exact same handler for output from filemanagerlib. Maybe I don’t need to, and I wouldn’t write new scripts that way, but it would make updating old scripts much easier.

So without it, I need to move a file to a temp folder, make sure there’s not a file with that name already in the temp folder, then rename it and move it to the destination folder. In this scenario I don’t want keep duplicate files. I can’t rename it in place because there may be a file with the new name already in the source folder. I can’t move it with the old name because there is a file there in the destination folder.

Well, first, I’m wondering if “Kind” could be added to this list, or if that’s a uniquely finder/system events thing?

full_name
name_extension
name_stub
parent_folder_path
parent_folder_name
displayed_name

My thinking in including all of these is that if just if the information is there, and we may need it in relation to one item, we may need it to sort a group of items.

Sorting by name is already in the sort command, and for my purposes that’s enough, but I could imagine a scenario where sorting by name_stub, as opposed to full_name would be appropriate. (I don’t recall what the difference between displayed_name and full_name is, unless it’s based on whether extensions showing is on or off?) (also what does sort use now?)

I can see a scenario where I use entire contents to extract files, and then want them sorted by parent folder path. I could build a list of lists containing all the parsed data and then sort the list, but I think it would be faster to have the library do it (would certainly be simpler).

Got it. The solution would be to build the list of lists using parsed data, and extract what I need from the list based on what element I want.

The lib would have to do the repeat routine. Using as alias list makes sense with the Finder, but I’m not sure there are many (any?) places where you can’t use a «furl» instead of an alias.

OK, I’m convinced :smile:

I suppose there’s some argument for it. I’m always wary because it can be inconsistent.

The aim is to cover reasonably common requirements, not everything imaginable. I’m never going to keep up with your imagination. :wink:

Because of the way enumeration is done, they’re going to returned in that order automatically.

If you’re doing all that just to determine if a file exists, there is a much easier way:

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
on doesItemExist(pPosixPath) -- @Path @File @Finder @ASObjC
  (*  VER: 1.0    2017-03-02
---------------------------------------------------------------------------------
  PURPOSE:  Determine if the Path Actually Exists
  PARAMETERS:
    • pPOSIXPath    | text  | POSIX Path to check
  RETURNS:  boolean │  true IF the file/folder does exist; else false
  
  AUTHOR:  JMichaelTX
  BASED ON:  Script by Chris Stone & Shane Stanley
  REF:
    1. Does a NSURL Have a Valid Target
        https://lists.apple.com/archives/applescript-users/2017/Mar/msg00010.html
        
—————————————————————————————————————————————————————————————————————————————————
*)
  ##  Requires:  use framework "Foundation"
  
  local myNSURL, doesItExistBool
  
  --- Expand tilde (~) in Path (if it exists) ---
  set pPosixPath to (current application's NSString's stringWithString:pPosixPath)'s stringByExpandingTildeInPath
  
  --- GET NSURL & DETERMINE IF IT ACTUALLY EXISTS ---
  set myNSURL to current application's |NSURL|'s fileURLWithPath:pPosixPath
  set doesItExistBool to (myNSURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean
  
  return doesItExistBool
end doesItemExist
--~~~~~~~~~~~~~~~ END OF handler doesItemExist ~~~~~~~~~~~~~~~~~~~~~~~~~

Doing all that to move a file to another folder with a unique name. If an item already exists with that name, then add a “-1,” or increment there of, to the end of the file name stub.

Shane has completely resolved the issue. :smile: The script checks if an item exists with that name, and if it does give the a unique name before moving.

But here’s the thing, I’m updating all these scripts that are passing aliases to all the handlers and apps.

The best examples are things like open file and read file, they get aliases in variables in all my scripts (seemed like a good idea at the time).

So now I either have to coerce every file reference I get to alias, or go back and look for (and hope I find) all the times I pass an alias in a variable that’s to a handler, command or app and rewrite the call or coerce to alias there.

Your right, I can use other forms of file reference everywhere in new scripts, and I will, but for now I’ve got these legacy scripts that I’m hoping to update with as little pain as possible.

But does it make any difference which you pass? If you have:

read x

it works exactly the same whether x is an alias or a «class furl». I haven’t checked all possibilities, but you might find you don’t have to change any code at all.

Wouldn’t I just have to coerce the file reference into a class furl instead? (I see no advantage to that over alias, and I prefer no chevron characters )

I tried all the result types from objects of and none work without conversion to alias (or presumably furl) or rewriting the call.

But if it returned alias list…

use script "Filemanagerlib"
use scripting additions
set aFolder to choose folder

set fileList to objects of aFolder ¬
   searching subfolders false ¬
   include invisible items false ¬
   include folders false ¬
   include files true ¬
   result type files list

repeat with myFile in fileList
    set openFile to open for access myFile with write permission
   close access openFile
end repeat

No — that’s what it is already. Try this and see:

set x to choose file name
class of x

Are you sure? The snippet you posted works fine as it is (under 10.11 and later).

FileManagerLib version 2.1 is now available. See:

I’m noticing an unexpected behavior in the exists object command.

If you use it directly in an if then statement, it correctly follows the conditional, but true/false doesn’t appear in the result window. Instead it’s some NSURL path (see comments). Whether it’s true or false.

use scripting additions
use script "FileManagerLib" version "2.2.1"
set targetFile to "Foo"
set targetFile to choose file
exists object targetFile
if exists object targetFile then
	--(NSURL) file:///Users/user/Documents/Pics/Reverie-2.jpg
	beep
else
	beep
	--(NSURL) file:///Foo
end if

You’re seeing AppleScript in action. When the if exists... line is called, AppleScript’s result is first set to the NSURL of targetFile in the firstLine of the handler it calls:

on exists object aFileOrPath
	set aURL to my makeURLFromFileOrPath:aFileOrPath
	return (aURL's checkResourceIsReachableAndReturnError:(missing value)) as boolean
end exists object

Because the handler is called as part of an if statement, which do not return results, AppleScript’s result property remains unchanged, despite the actual result of the handler call being a boolean value.

This sort of thing can happen if either the return statement of a handler is followed by code rather than a variable as above, or where the handler has no return statement and its last line is code.

I’d take some convincing that it needs attending to. I could go through every handler and add an extra return line, but I’m not sure there’s any public benefit. I consider exposing quirks as educational :wink:

I now feel more educated. Thanks!

Have we talked about modification date? Would it be possible to get Modification Date and Creation Date added to parse objects command of fileManagerLib??

If not, is there a better (faster) way of getting those than Finder/System Events?

(Changed the name of this topic because we’ve gone way beyond that original post)

They’re easy enough to get via ASObjC:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set thePath to POSIX path of (choose file)
set theURL to current application's |NSURL|'s fileURLWithPath:thePath
set {theResult, theValue} to theURL's getResourceValue:(reference) forKey:(current application's NSURLContentModificationDateKey) |error|:(missing value)
set theDate to theValue as date

The other relevant keys are NSURLContentAccessDateKey and NSURLCreationDateKey.

I’m hesitant about adding them to the lib partly to avoid bloat, and partly because if I add a lot of properties to parse object, I risk slowing it down.

Is there a better (faster) way of doing this? I’m getting all the files in the entire contents of a directory, then filtering by a list of name extensions.

Entire Contents is fast, but going through the list to read the extensions takes forever and causes hangs (there are about 9k files).

I’m thinking I may try just using TIDs to get the extension from the path text, and maybe try to use one of those fancy script objects that Nigel showed us, but first I’m wondering if there’s not a simple solution I’m missing.

on FilterEntireContents(aFolder)
   
   set folderContents to objects of aFolder ¬
      searching subfolders true ¬
      include invisible items false ¬
      include folders false ¬
      include files true ¬
      result type files list
 
   set filteredContents to {}
   repeat with thisFile in folderContents
      set fileInfo to parse object thisFile as item 
      if name_extension of fileInfo is in {"wav", "band", "mp3", "m4p", "m4a"} then
         set the end of filteredContents to thisFile as item
      end if
   end repeat
   return filteredContents
   
end FilterEntireContents

This requires 10.11 or later, but should be pretty quick:

use AppleScript version "2.5" -- requirs 10.11 or later
use framework "Foundation"
use script "FileManagerLib" version "2.2.1"
use scripting additions

FilterEntireContents2("/Users/shane/Desktop")

on FilterEntireContents2(aFolder)
	
	set folderContents to objects of aFolder ¬
		searching subfolders true ¬
		include invisible items false ¬
		include folders false ¬
		include files true ¬
		result type urls array
	
	set thePred to current application's NSPredicate's predicateWithFormat:"pathExtension IN[c] %@" argumentArray:{{"wav", "band", "mp3", "m4p", "m4a"}}
	return (folderContents's filteredArrayUsingPredicate:thePred) as list
end FilterEntireContents2

But you can make it significantly faster by changing include folders to true. Assuming you don’t use extensions for folder names, the result will be the same. But importantly, when both include folders and include files are true, no time is spent separating folders from files and packages — and that’s what takes most of the time because it requires a repeat loop. I’m talking a factor of more than x10.

This script doesn’t work. I want to set the mod date of the files chosen by the users. Am I doing something wrong or is filemanagerlib not working ?


use script "FileManagerLib" version "2.3.2"
use scripting additions
set now to current date
set filesToFix to my chooseFiles()
repeat with thisFile in filesToFix
   modificationdate(thisFile as alias)
   change value for thisFile as alias ¬
      to now ¬
      property name modification property
   modificationdate(thisFile)
end repeat

on modificationdate(anyFile)
   set dateInfo to date info for anyFile
   return modification_date of dateInfo
end modificationdate

on chooseFiles()
   set myfiles to choose file with prompt "Pick files to change modification date" with multiple selections allowed
   return myfiles as list
end chooseFiles

I think you’ll find that it’s working in that the mod date is being changed (see in the Finder). The bug is that the result of date info for is incorrect: the values for modification_date and creation_date are reversed. I’ll get a fix out shortly. Version 2.3.3 is now available for download.

That was quick! Thanks!