Applescript copy files/folders from a source using a second source

Hello to everyone,
I’m new in Applescript and obviously I have some trouble…

I would like to extract from my website, some files used for one extension, the problem is that they are a ton of files and they are around the whole filesystem…

So, I would like to have an Applescript who:

  1. ask a for a reference folder, who is used to detect the stricuture of folders and files to copy,
  2. ask for a source folder
  3. ask a destination folder
  4. copy all the files from the source using reference as file list, to the destination folder

Is it complicated? I tryed but nothing good…

Applescript copy files/folders from a source using a second source

Thank you un advance :slight_smile:

To help, we would need a better description of what this script is supposed to do. I don’t understand what the script does differently from simply copying files from one folder to another:

I’m not sure what this means. Can you provide the structure of samples of the three folders, showing the initial condition and desired result for the destination folder?

  • Tom.

Hello Tom,
this an example:

Reference: is the original structure files for the plugin, and this is the source list of files and folder I should to copy example
Folder A
File 1
File 2
Subfolder A
File 3
File 4

Source: is the whole website installation, contains thousands of files and plugins
Folder A
File 1
File 2
File 5
File 6
Subfolder A
File 3
File 4
Folder B
Folder C

Destination: the location where the script should copy and replicate the files and folders from source

I’m not sure is well explained, tell me if something isn’t clear.

Thank you!

Matteo

Sorry, I’m still not getting it… If Reference contains all the files and folders you need copied, laid out correctly, then why not just copy it to the destination? Why is “Source” even involved?

I don’t understand what information is being extracted from “Reference,” or how it is to be applied to the data in “Source.”

  • Tom.

Hello Tom,
yes as is isn’t pretty clear, you need some explanation…

Reference contains original files.
Source contains files in the production enviroment who probably are not the same version as in the reference, so I need to extract the files from the source and not from the reference.

So, I know which files I need (reference) but it’s hard to extract manually from source because there are tons of files and directory.

I hope now is more clear :slight_smile:

If I understand well what you need, the script below will do the job.

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

property skipHiddenFiles : false
--> true means : skip the hidden files
--> false means : copy the hidden files

on run
	my germaine()
end run

on germaine()
	
	set templateFolder to POSIX path of ((path to desktop folder as text) & "Charts for Adam") # Edit to fit your needs
	set templateFolder to POSIX path of "Macintosh HD:Macintosh …2.0:Dossier ClarisWorks 5.0:"
	set sourceFolder to POSIX path of ((path to desktop folder as text) & "sourceFolder") # Edit to fit your needs
	set targetFolder to POSIX path of ((path to desktop folder as text) & "targetFolder") # Edit to fit your needs
	(*
	set templateFolder to POSIX path of (choose folder with prompt "Reference")
	set sourceFolder to POSIX path of (choose folder with prompt "Source")
	set targetFolder to POSIX path of (choose folder with prompt "Destination")
	*)
	set |⌘| to current application
	set fileManager to |⌘|'s NSFileManager's defaultManager()
	set rootURL to |⌘|'s |NSURL|'s fileURLWithPath:templateFolder
	set rootLength to (rootURL's |path|()'s |length|()) + 1 -- used to trim paths
	if skipHiddenFiles then
		# Use this one if hidden files must be ignored.
		set theOptions to (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer) + (|⌘|'s NSDirectoryEnumerationSkipsHiddenFiles as integer)
	else
		# Use this one if hidden files must be copied
		set theOptions to (|⌘|'s NSDirectoryEnumerationSkipsPackageDescendants as integer)
	end if
	
	set theEnumerator to fileManager's enumeratorAtURL:rootURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value)
	
	set sourceFolder to |⌘|'s NSString's stringWithString:sourceFolder
	set targetFolder to |⌘|'s NSString's stringWithString:targetFolder
	
	repeat with oneURL in theEnumerator's allObjects()
		# Got one URL
		# Drop the path to the templateFolder
		set oneRelative to (oneURL's |path|()'s substringFromIndex:rootLength)
		# Build the URL of the source item
		set theSourceURL to (|⌘|'s |NSURL|'s fileURLWithPath:(sourceFolder's stringByAppendingPathComponent:oneRelative))
		# Build the URL of the target item
		set theDestURL to (|⌘|'s |NSURL|'s fileURLWithPath:(targetFolder's stringByAppendingPathComponent:oneRelative))
		# Copy the source item in the target item
		(my copyFromURL:theSourceURL toURL:theDestURL withReplacing:true)
	end repeat
end germaine

#=====#=====#=====#=====#=====#=====

-- This handler - borrowed from Shane STANLEY - is called by other handlers, and is not meant to called directly
on copyFromURL:sourceURL toURL:destinationURL withReplacing:replaceFlag
	set |⌘| to current application
	set theFileManager to |⌘|'s NSFileManager's |defaultManager|()
	set {theResult, theError} to (theFileManager's copyItemAtURL:sourceURL toURL:destinationURL |error|:(reference))
	if not theResult as boolean then
		if replaceFlag and (theError's code() as integer = |⌘|'s NSFileWriteFileExistsError as integer) then -- it already exists, so try replacing
			-- create suitable temporary directory in destinationURL's parent folder
			set {tempFolderURL, theError} to theFileManager's URLForDirectory:(|⌘|'s NSItemReplacementDirectory) inDomain:(|⌘|'s NSUserDomainMask) appropriateForURL:(destinationURL's |URLByDeletingLastPathComponent|()) create:true |error|:(reference)
			if tempFolderURL = missing value then error (theError's |localizedDescription|() as text) -- failed, so return error
			-- copy sourceURL to temp directory
			set tempDestURL to tempFolderURL's URLByAppendingPathComponent:(destinationURL's |lastPathComponent|())
			set {theResult, theError} to theFileManager's copyItemAtURL:sourceURL toURL:tempDestURL |error|:(reference)
			if not theResult as boolean then
				-- copy failed, so delete temporary directory and return error
				theFileManager's removeItemAtURL:tempFolderURL |error|:(missing value)
				error (theError's |localizedDescription|() as text)
			end if
			-- replace existing file with temp file atomically, then delete temp directory
			set {theResult, theError} to theFileManager's replaceItemAtURL:destinationURL withItemAtURL:tempDestURL backupItemName:(missing value) options:(|⌘|'s NSFileManagerItemReplacementUsingNewMetadataOnly) resultingItemURL:(missing value) |error|:(reference)
			theFileManager's removeItemAtURL:tempFolderURL |error|:(missing value)
			-- if replacement failed, return error
			if not theResult as boolean then error (theError's |localizedDescription|() as text)
		else -- replaceFlag is false or an error other than file already exists, so return error
			error (theError's |localizedDescription|() as text)
		end if
	end if
end copyFromURL:toURL:withReplacing:

#=====#=====#=====#=====#=====#=====

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) mardi 17 janvier 2017 11:59:55

Edited to repair encoding oddities.

Hello Yvan,
thank you very much for the big work you did for me :slight_smile:

I changed the code for the variables templateFolder, sourceFolder and targetFolder but I had anyway some errors :frowning:

Since I’m not Applescript expert I don’t understand how to resolve.

The error is:
-[NSURL length]: unrecognized selector sent to instance 0x6080018a27c0

I tryed to understand what mean this error with google with no results.

Thank you for helping me :slight_smile:

Matteo

First question :

How did you extracted the script from my message ?
The correct way is to use the dedicated button [Open this Scriplet in your Editor]
If you didn’t use it, please redo the entire process to be sure that what you are trying to use is the correct code.

Second question: which system are you running ?
When a question doesn’t name a specific system, I assume that the asker use the current system but here, as you may see, the first instruction clearly state that the script is designed for Yosemite (10.10) or later.

Third question: as you edited the instructions defining the three required path, are the new values of the correct format : POSIX path ?

I can’t help more because I am unable to reproduce what you got.

May you paste here the instructions defining your three required paths ? I’m wondering if the problem may be linked to the fact that at least the first path is pointing to a website.

It may be useful to explain why I use the structure :


on run
   my germaine()
end run

on germaine()
.

It just gets rid of the boring message claiming "Can’t save the script because ASObjC pointers can’t be saved"
I rewrote the message according to what my memory said. It may be far from perfect because I didn’t saw it for months.

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) mardi 17 janvier 2017 14:30:51

Hello Yvan,

  1. yes, I used the link “Open this Scriplet in your Editor:”
  2. my system is 10.12.2
  3. I changed the code:
set templateFolder to POSIX path of ((path to desktop folder as text) & "Charts for Adam") # Edit to fit your needs
set sourceFolder to POSIX path of ((path to desktop folder as text) & "sourceFolder") # Edit to fit your needs
set targetFolder to POSIX path of ((path to desktop folder as text) & "targetFolder") # Edit to fit your needs

With che code:

set templateFolder to choose folder with prompt "Reference"
set tempplateFolder to POSIX path of templateFolder
set sourceFolder to choose folder with prompt "Source"
set sourceFolder to POSIX path of sourceFolder
set targetFolder to choose folder with prompt "Destination"
set targetFolder to POSIX path of targetFolder

What is wrong Yvan?

Thank you very much!

Your instructions are correct but they say nothing about the used paths.

I assume that the problem is linked to the fact that at least the first path - templateFolder - is supposed to point to a webSite.

It would be useful to know exactly the pathnames, at this time mainly the first one, because the command using |length| apply to this one.

If you are reluctant to pass it in the thread, you may send it (better to pass the three) to my mailbox :
[format]k o e n i g . y v a n @ s f r . f r[/format]

With these infos I would be able to ask for complementary help if I can’t solve the problem on my side.

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) mardi 17 janvier 2017 15:33:32

Well, I think I understand what you need now… but thanks Yvan for stepping in, because now that I understand the problem, I don’t think I would have contributed a solution, because I think it would have taken me longer to write than my threshold for helping people on forums.

If what you posted match your real code, there is a sad typo in it. I commented it above and post the code modified to fit your needs in message #6.
I tested here and, when - as your code does - the script try to execute the instruction

set aURL to |⌘|'s |NSURL|'s fileURLWithPath:templateFolder 

with templateFolder defined as an alias (what is returned by choose folder) I really get the offending :
[format]error “-[NSURL length]: unrecognized selector sent to instance 0x6000012af0c0” number -10000[/format]
I concatenated some instructions to get a more compact code.

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) mardi 17 janvier 2017 17:56:50

Edited to repair encoding oddities

I made a bit of cleaning and added the option to skip or to copy the hidden files.

Yvan KOENIG running Sierra 10.12.2 in French (VALLAURIS, France) jeudi 19 janvier 2017 16:16:24