How to Overwrite all files in a folder? - applescript-objc

I am using the following to copy a file:
on replace:sender
set allFiles to choose file with prompt "Please select your file:" with multiple selections allowed
repeat with theFile in allFiles
tell application "Finder"
set {name:fileName, name extension:nameExtension, file type:fileType} to theFile
if fileType is "png" or nameExtension is "png" then
set myPng to "~/Documents" & fileName as POSIX file
else
delay 0.2
tell current application's NSAlert's alloc's init()
its setMessageText:"Replace Photo"
its setInformativeText:"The file \"" & fileName & "\" is not a PNG file!"
its setAlertStyle:2
its setShowsSuppressionButton:false
its beginSheetModalForWindow:theWindow completionHandler:(missing value)
return
end tell
end if
if exists myPng then
delay 0.2
tell current application
display alert"There is already an older item named \""& fileName &"\" at this location." message ¬
"Do you want to replace it with the newer \"" & fileName & "\" one you're moving?" buttons {"Cancel", "Replace"} default button "Replace" as critical
set response to button returned of the result
if response is "Replace" then
delay 0.2
do shell script "rm -rf " & quoted form of POSIX path of myPng & space & "~/Documents" & myPng with administrator privileges
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
end if
if response is "Cancel" then
return
end if
end tell
else
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
end if
end tell
end repeat
end replace:
If there is a file with the same name in the target folder the user receives an alert, but what is happening is that with each copied file this alert is displayed, I would like to show this alert only once, just as it is done by macOS and then if the user clicks the "Replace" button all files will be replaced at once.

Your script doesn't compile so it didn't allow me to test it to really get a feel for what you're doing, so I hope I'm in the ball park with what I've come up with below.
But, aside from that, I'll be blunt: your script is a mess. You've got a Finder block that contains some AppleScriptObjC code, and then some shell function calls... I think you need to pick one, and then organise the code a bit more logically so people (especially you) can make sense of what's going on.
I typically avoid Finder for file system operations, but in this situation, it is advantageous because it allows one to compare a potential list of items (generated by a whose filter) with a known list of items—something no other application allows (and instead thinks you wish to compare it to the number 64). It also means that a move operation can be undone if necessary:
-- Bits of text for joining
-- Used for the alert dialogs
property lf : linefeed
property lft : linefeed & tab
property lf2 : lf & lf
property lf2t : lf2 & tab
property bullet : "›"
property li : bullet & space
-- Icon files, also used
-- for the alert dialogs
property CoreTypes : "/System/Library/CoreServices/CoreTypes.bundle"
property StopIcon : path to resource "AlertStopIcon.icns" in bundle CoreTypes
property NoteIcon : path to resource "AlertNoteIcon.icns" in bundle CoreTypes
on replace:sender
set prompt to "Please select some files:"
set fs to choose file with prompt prompt ¬
with multiple selections allowed
-- Get the directory in which the chosen files lie
set dir to (some item in fs & "::" as text)
set the text item delimiters to dir's POSIX path
-- Organise the files into two lists:
-- PNG files and non-PNG files
set PNGfs to {}
repeat with f in fs
get text items 2 thru -1 of f's POSIX path as text
set f's contents to the result
tell f to if its contents ends with ".png" then
set end of PNGfs to its contents
set its contents to null
end if
end repeat
set fs to every string in fs
set the text item delimiters to lft & li
if fs ≠ {} then display dialog ["The following files ", ¬
"are not PNG files and will be ignored:", lf2t, ¬
li & fs] as text with title ["Oops…!"] buttons ¬
["D'oh!"] with icon NoteIcon default button 1
if PNGfs = {} then return -- Nothing to move
tell application id "com.apple.Finder"
set here to dir as alias -- The source folder
set there to the (path to the documents folder) -- Destination folder
-- Enumerate files that might be replaced
set duplicates to the name of every file ¬
in there whose name is in PNGfs
if duplicates ≠ {} then tell (display dialog contents ¬
of ["The following files in ", here's POSIX path, ¬
" share names with files in ", there's POSIX path, ¬
":", lf2t & li & duplicates & lf2, "Do you want ", ¬
"to:", lft, "• Move all files anyway, replacing ", ¬
"the ones in ", there's POSIX path, ";", lft, "•", ¬
" Move only the files that can be moved without ", ¬
"replacing anything; OR", lft, "• Don't move any", ¬
" of the files for now ?"] as text ¬
with title ["Replace Existing Files?"] ¬
buttons ["Replace", "Keep", "Abort"] ¬
default button 1 with icon StopIcon) ¬
to set do to its button returned
-- If the user aborts, the script terminates.
-- If the user elects to replace existing files,
-- then we move those existing files to the trash.
-- If the user wishes to keep the existing files,
-- they remain in place. Either way, the final
-- operation is the same: move the files without
-- replacing anything.
if do = "Abort" then return 0 -- No files moved
if do = "Replace" then delete ¬
(files in there whose ¬
name is in ¬
duplicates)
move the (files in here whose ¬
name is in PNGfs) to ¬
there without replacing
end tell
end replace:
Doing it this way avoids the repeat loop and thus you only get a single dialog box per set of grouped events (one if the user selects files of the wrong type; and one if there's a risk of overwriting files).
In fact, you can even get rid of the first repeat loop that is used to split the list into two by file types: the choose file command has a parameter called of type, where you can specify one or more file types that the user's selection will be restricted to:
set fs to choose file with prompt prompt ¬
with multiple selections allowed ¬
of type ["png"] --OR:["public.png"]
"public.png" is the uniform type identifier for PNG files.

The easist way is to add a flag which is false by default and set to true after the user presses "Replace".
I removed the rm line because it's not needed and the syntax is wrong anyway.
on replace:sender
set replaceAll to false
set allFiles to choose file with prompt "Please select your file:" with multiple selections allowed
repeat with theFile in allFiles
tell application "Finder"
set {name:fileName, name extension:nameExtension, file type:fileType} to theFile
if fileType is "png" or nameExtension is "png" then
set myPng to "~/Documents" & fileName as POSIX file
else
delay 0.2
tell current application's NSAlert's alloc's init()
(its setMessageText:"Replace Photo")
(its setInformativeText:("The file \"" & fileName & "\" is not a PNG file!"))
(its setAlertStyle:2)
(its setShowsSuppressionButton:false)
(its beginSheetModalForWindow:theWindow completionHandler:(missing value))
return
end tell
end if
if exists myPng and replaceAll is false then
delay 0.2
tell current application
display alert "There is already an older item named \"" & fileName & "\" at this location." message ¬
"Do you want to replace it with the newer \"" & fileName & "\" one you're moving?" buttons {"Cancel", "Replace"} default button "Replace" as critical
set response to button returned of the result
if response is "Replace" then
delay 0.2
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
set replaceAll to true
end if
if response is "Cancel" then
return
end if
end tell
else
do shell script "mv " & quoted form of POSIX path of theFile & space & "~/Documents" with administrator privileges
end if
end tell
end repeat
end replace:

You can also use NSAlert (as you are earlier) with its suppression button and keep track of the state in the handler, for example (run in the foreground in Script Editor):
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
set buttonState to false
repeat -- forever, or at least until canceled
if buttonState then
display dialog "The suppression button state is currently " & buttonState buttons {"Cancel", "Reset", "OK"}
if button returned of the result is "Reset" then set buttonState to false
else
tell current application's NSAlert's alloc's init()
its setMessageText:"Alert"
its setInformativeText:"This alert is going to keep showing until you choose otherwise."
its setShowsSuppressionButton:true
its (suppressionButton's setTitle:"Skip the alerts")
its runModal()
set buttonState to (its suppressionButton's state()) as boolean
end tell
end if
end repeat

Related

Is it possible to format the colour of parts of my git branch name inside the prompt?

In my .zshrc file I have the following lines that parse my current git branch and display it in the terminal, the .zshrc file looks like this:
# Load version control information
autoload -Uz vcs_info
precmd() { vcs_info }
# Set up the prompt (with git branch name)
setopt PROMPT_SUBST
PROMPT='%n in ${PWD/#$HOME/~} ${vcs_info_msg_0_} > '
# Format the vcs_info_msg_0_ variable
zstyle ':vcs_info:git:*' formats '(%b)'
So my terminal ends up looking like this:
me in ~/repos/myrepo (feat/MYISSUE-123/fix-the-broken-stuff) >
I would like to modify the script above so MYISSUE-123 has a different colour to the rest of the branch name.
How can I do that?
Try this ... change precmd to:
precmd() {
vcs_info
psvar=(${(s:/:)vcs_info_msg_0_})
# in case there are more than three components:
psvar[3]=${(j:/:)psvar[3,-1]}
}
Make sure precmd() is being called prior to each prompt display by adding it to the hook:
autoload -Uz add-zsh-hook
add-zsh-hook precmd precmd
And change PROMPT to:
PROMPT='%n in ${PWD/#$HOME/~} %1v/%F{red}%2v%f/%3v > '
There are some notes about psvar in this answer: https://stackoverflow.com/a/64094551/9307265.
The (s) and (j) parameter expansion flags are documented in the zshexpn man page.
Please let me know if there are any issues.

PowerBI: Check if the folder/directory we are loading to exists or not using Power Query

I am a newbie in PowerBi and currently working on a POC where I need to load data from a folder or directory. Before this load, I need to check if
1) the respective folder exists
2) the file under the folder is with.csv extension.
Ex. Let suppose we have a file '/MyDoc2004/myAction.csv'.
Here first we need to check if MyDoc2004 exists and then if myAction file is with.csv extension.
Is there any way we can do this using Power Query?
1. Check if the folder exists
You can apply Folder.Contents function with the absolute path of the folder, and handle the error returned when the folder does not exist with try ... otherwise ... syntax.
let
absoluteFolderPath = "C:/folder/that/may/not/exist",
folderContentsOrError = Folder.Contents(absoluteFolderPath),
alternativeResult = """" & absoluteFolderPath & """ is not a valid folder path",
result = try folderContentsOrError otherwise alternativeResult
in
result
2. Check if the file is with .csv extension
I'm not sure what output you are expecting.
Here is a way to get the content of the file by full path including ".csv", or return an alternative result if not found.
let
absoluteFilePath = "C:/the/path/myAction.csv",
fileContentsOrError = File.Contents(absoluteFilePath),
alternativeResult = """" & absoluteFilePath & """ is not a valid file path",
result = try fileContentsOrError otherwise alternativeResult
in
result
If this is not what you are looking for, please update the question with the expected output.
Hope it helps.

Applscript- Use List to Select Specifc Photoshop Action

Ive been trying to write a Applescript using the bits of knowledge I have
current stumbling blocks are
-getting the returned list selection to run the photoshop action
-how to repeat the action on multiple images.
Aim
I want to use a list to extract different cobinations of files (with set naming conventions) from a defined folder,
I would then like that same list selection to choose between mutliple photoshop actions and run the extracted file combination through that action.
Stage 1
-on running open a list
-List to conatain a set of names relating to photoshop actions
-select from list
Stage 2
-choose folder with source images (always 14 images always with the same last 9 characters _0000.tif to _0013.tif)
-Choose a save folder
Stage 3
-dependant on original list selection, automatically gather files from source image folder and run them through a coresponsing photoshop action
e.g If "Action 1" selceted from List select image "_0001.tiff & _0010.tif" from source folder and do photoshop action "Action1"
Stage4
save in chosen "save folder"
The Script So Far
--Stage 1--
set PhotoshopActionList to {"Action1", "Action2", "Action3", "Action4", "Action5"}
set ActionrequiredAnswer to choose from list PhotoshopActionList with title "Actions Picker" with prompt "Choose Action?"
if ActionrequiredAnswer is false then
error number -128 (* user cancelled *)
else
set ActionrequiredAnswer to ActionrequiredAnswer's item 1 (* extract choice from list*)
end if
end run
--Stage 2--
property SourceFolder : missing value
property destinationFolder : missing value
if SourceFolder = missing value then
set SourceFolder to (choose folder with prompt "Choose Base Images:")
set destinationFolder to (choose folder with prompt "Choose Save Location:")
else
tell application "Finder"
set theFolders to every item of entire contents of SourceFolder as list
repeat with thisFolder in theFolders
make new alias file at destinationFolder to thisFolder
end repeat
end tell
end if
--Stage 3--
tell application "Finder"
set filesList to {files of entire contents of SourceFolder contains "_001", "_002", "003"} as alias list
end tell
tell application "Adobe Photoshop"
repeat with aFile in filesList
open aFile
do action "Action1" from "Actionsfolder"
end tell
--Stage 4--
save currentDocument in folder destinationFolder as JPEG
I did not found a way to select entire contents of folder AND filter extension 'tif', 'tiff',.. AND filter files whose name contains your patterns.
As work around, I did 2 steps:
1) select in entire contents only files with target extensions.
2)I loop through these files to check is file name contains the target pattern. This is done by routine FnameOK.
You need to complete the script bellow with your Photoshop action and the 'save as':
set PhotoshopActionList to {"Action1", "Action2", "Action3", "Action4", "Action5"}
set ListOK to {"_001", "_002", "003"}
set ActionRequiredAnswer to choose from list PhotoshopActionList with title "Actions Picker" with prompt "Choose Action?"
if ActionRequiredAnswer is false then
error number -128 (* user cancelled *)
else
set ActionRequiredAnswer to ActionRequiredAnswer's item 1 (* extract choice from list*)
end if
set SourceFolder to (choose folder with prompt "Choose Base Images:")
set DestinationFolder to (choose folder with prompt "Choose Save Location:")
tell application "Finder" to set filesList to files of entire contents of SourceFolder whose name extension is in {"tiff", "tif"}
repeat with aFile in filesList
tell application "Finder" to set NameF to name of aFile
if FNameOK(NameF, ListOK) then -- the file name contains a valid pattern, then process the file
tell application "Adobe Photoshop"
open (aFile as alias)
-- perform action selected
-- save as to Destination Folder
end tell
end if
end repeat
on FNameOK(Local_Name, LocalList) -- check if the file name contains an element of the list
set LocalCheck to false
repeat with OneItem in LocalList
if Local_Name contains OneItem then
return true
end if
end repeat
return false
end FNameOK

Excel VBA script or macro for linking to new Excel document using a template in it

I have a small family-operated shop and, in the process of speeding things up and/or automating them, I need help on the following matter (will try to explain as well as possible, since I am at a novice level on this kind of stuff.)
So, in my shop we offer a certain service (taking specific measurements of body dimensions along with weight/sugar levels etc etc). I have created an .xlsx document that contains all required fields and saved it as a template for future use. What I need to do is this:
I want to have a "master" Excel file with the names of our customers. From there, each name when clicked should open a new Excel file, using the aforementioned template, which would eventually be saved as each customer's record. I've tried a script for linking to the template but opening it as a new file (with the template in it) but, the problem is that each time I click on the name on the master file it opens a new document altogether, while I need it to open a new document named after the name in the original cell, with the template in it. As far as I can think, this is the best "automation" I can accomplish. Is it plausible? If so, how can I do it?
edit: this is the code, as i found it elsewhere:
'File:
' OfficeTemplate.vbs
'
'Problem:
' A hyperlink from an Office application to an Office template opens the template,
' instead of creating a new file.
' The proposed solution
' support.microsoft.com/kb/278627
' did not work.
'
'Solution:
' Create a hyperlink to a VBS file that starts the process.
'
'Instructions:
' Copy this VBScript into the same directory of your template.
' Rename it so that the VBS file name has the name of the template file in front.
' Example:
' Template name: test.dotx
' VBScript name: test.dotx.vbs
' Create the hyperlink to the VBS file.
Set fso = CreateObject("Scripting.FileSystemObject")
'Get the name of the template
OurName = fso.GetBaseName(WScript.ScriptName)
'Find all files in our directory
For Each File In fso.GetFolder(fso.GetParentFolderName(WScript.ScriptFullName)).Files
'Did we found the template?
If StrComp(OurName, File.Name, vbTextCompare) = 0 Then
'Invoke the default verb
CreateObject("Shell.Application").Namespace(0).ParseName(File.Path).InvokeVerb
'Wait a second to let the application start
WScript.Sleep 1000
'Done
Exit For
End If
Next
this is my template:
http://i215.photobucket.com/albums/cc55/psyclone_tread/templ.jpg
this is the master file, just a column with names and one with phone numbers, i want the names to link to each customer's individual file.
http://i215.photobucket.com/albums/cc55/psyclone_tread/master.jpg
Let me give you a very simple answer for this. Use VBA instead of VBS, and write code inside your master excel as per following illustration.
When you click on the cell with the name,
If File.Exists ("YourFolder\" & ActiveCell.Value & ".xlsx") Then
Workbooks.Open("YourFolder\" & ActiveCell.Value & ".xlsx")
Else
WorkBooks.Add(YourTemplate)
Fill in the details already present in the master sheet to new workbook if needed
NewWorkbook.Save("YourFolder\" & ActiveCell.Value & ".xlsx")
End If

Get full directory contents with AppleScript

I need to get the entire (visible) contents of a folder and its subfolders as a list. Is this possible?
see how easy this can be
tell application "Finder"
set file_list to entire contents of (choose folder with prompt "Please select directory.")
end tell
if you want a list of file names then you could do this
tell application "Finder"
set file_list to name of every file of entire contents of (choose folder with prompt "Please select directory.")
end tell
Yes, entire contents does exactly what you say -- but it easily chokes on
large folders, and takes forever. It's OK for
small things, like extracting all the files of one kind out of a folder you
know will only contain a small number of files.
The recursive method also works well -- but it's using "list folder", and
the dictionary listing for it says it's deprecated and we shouldn't use it
any more.
I'm sure there is a shell command that can do this faster, but here is one way in pure Applescript that gives you total control over formatting what info you would like displayed.
property kFileList : {}
tell application "Finder"
set source_folder to choose folder with prompt "Please select directory."
my createList(source_folder)
end tell
on createList(item_list)
set the the_items to list folder item_list without invisibles
set item_list to item_list as string
repeat with i from 1 to number of items in the the_items
set the_item to item i of the the_items
set the_item to (item_list & the_item) as alias
set this_info to info for the_item
set file_name to name of this_info
set end of kFileList to file_name
if folder of this_info is true then
my createList(the_item)
end if
end repeat
end createList
On a side note, there are also a number file listing applications that can do this faster than Applescript.
UPDATE: As a result of this discussion, here is the function again, but this time using the updated API. This could probably could use some cleaning up, but it works cataloging my Desktop handily enough (and that's a deep, deep folder for me):
property kFileList : {}
tell application "Finder"
set source_folder to choose folder with prompt "Please select directory."
my createList(source_folder)
end tell
return kFileList
on createList(mSource_folder)
set item_list to ""
tell application "System Events"
set item_list to get the name of every disk item of mSource_folder
end tell
set item_count to (get count of items in item_list)
repeat with i from 1 to item_count
set the_properties to ""
set the_item to item i of the item_list
set the_item to ((mSource_folder & the_item) as string) as alias
tell application "System Events"
set file_info to get info for the_item
end tell
if visible of file_info is true then
set file_name to displayed name of file_info
set end of kFileList to file_name
if folder of file_info is true then
my createList(the_item)
end if
end if
end repeat
end createList
Wow this is quite late but I checked and it works.
tell application "Finder" to set folder_root to (choose folder with prompt "Please select directory.")
set fl to {}
dump_folder(folder_root)
on dump_folder(f)
global fl
tell application "System Events" to set end of fl to (get the POSIX path of f)
tell application "Finder" to set nfl to (the items of the contents of f)
repeat with nf in nfl
dump_folder(nf as alias)
end repeat
end dump_folder
fl