I have a directory structure which looks like this:
parent-dir
XXX
file.txt
YYY
file2.txt
CCC
XXX
file3.txt
I currently use File /r XXX to recursively get parent-dir\XXX but because /r also causes File to search the input directories recursively I also get all of parent-dir\CCC\XXX.
I realize I could CreateDirectory XXX and SetOutputPath XXX and use File /r XXX\* and then SetOutputPath back but I don't want to have to do that every time I use File /r
Is there a safe way to use File /r which will not grab unintended things which might get added to parent-dir in the future?
For that problem of File /r that could get unexpected files, I have made the following macro:
; SlurpSubDir : include a file pattern from a directory
!macro SlurpSubDir args parentSrcDir subDir pattern parentDstDir
SetOutPath "${parentDstDir}\${subDir}"
File ${args} "${parentSrcDir}\${subDir}\${pattern}"
SetOutPath "${parentDstDir}"
!macroend
!define SlurpSubDir "!insertmacro SlurpSubDir"
That I call like this to get the whole perl subdirectory from ${InstSrcFiles} that is the directory where the setup master files are located, with exclusion of possible .svn directories, and the files will be installe into $INSTDIR:
${SlurpSubDir} "/r /x .svn" "${InstSrcFiles}" "perl" "*.*" "$INSTDIR"
Related
Problem
I have multiple files in very similarly structured folders that I want to install in one common folder.
I can do this by manually specifying each file I want to add, like so:
SetOutPath "$INSTDIR\Final\Destination"
File /r ".\ParentFolder\Folder1\Same\Path\For\All\Thing1.ext"
File /r ".\ParentFolder\Folder2\Same\Path\For\All\Thing2.ext"
File /r ".\ParentFolder\Folder3\Same\Path\For\All\Thing3.ext"
File /r ".\ParentFolder\Folder4\Same\Path\For\All\Thing4.ext"
File /r ".\ParentFolder\Folder5\Same\Path\For\All\Thing5.ext"
However, there are 50+ of these files, and they are likely to change, so I'd prefer to do this in a way that won't require editing the NSIS in the future.
What I have Tried
I tried putting in wildcards, like so:
SetOutPath "$INSTDIR\Final\Destination"
File /r ".\ParentFolder\*\Same\Path\For\All\*.ext"
However, I get the message
File: ".\ParentFolder\*\Same\Path\For\All\*.ext" -> no files found.
Question
Is there something wrong with using multiple wildcards * in my File query?
What would be the correct way to query multiple files in different folders?
You can't put wildcards anywhere, only in the filename unfortunately.
What you can do however is to use !system to execute a batch file (or any other command or application) that writes NSIS instructions to a file you can !include:
Section
SetOutPath $InstDir
!tempfile folders ; temporary .nsh
!system 'for /D %A in (.\ParentFolder\*) do #>>"${folders}" echo File /r "%~A\Same\Path\For\All\*.ext"'
!include "${folders}"
!delfile "${folders}"
SectionEnd
I would like to recursively execute a command in a loop, to set a metadadata tag on files based on the folder name (which is a date) for files in a tree structure.
Basically something like
FOR /R [folder] %%G in (*.mts) DO Exiftool -DateCreated=[folder name of]%%G %%G
However, I see no way to extract the folder name of the parameter - %%~pG will give me the entire path - including slashes
Thus I thought of nesting loops like this:
FOR /d /r %%G IN (.) DO (
FOR %%H IN (*.mts) DO (
echo %%~nG %%~nH
)
)
%%~nG will report the folder name but %%H is not available - the output looks like this:
(FOR %H IN (*.mts) DO (echo 2017-11-12 %~nH ) )
Maybe the second for-loop does not know where to start - how do I tell it so?
FOR %%H IN (*.mts) DO (
will look for .mts files in the current directory.
You want to look in the current %%G directory, so use
FOR %%H IN ("%%G\*.mts") DO (
In my NSIS script, I have the following lines (Didn't turn the 1st line into a code block because it was too long and looked bad as 1 line):
Exec '"$BINDIR\SubscriberACD.exe" //IS//SubscriberACD --Install="$BINDIR\SubscriberACD.exe" --Description="Subscriber service with Apache Commons Daemon" --Jvm="$JVMDIR\jvm.dll" --Classpath="$CLASSESDIR\SubscriberACD.jar;$CLASSESDIR\jeromq-0.3.5.jar;$CLASSESDIR\jackson-databind-2.6.3.jar;$CLASSESDIR\jackson-core-2.6.3.jar;$CLASSESDIR\jackson-annotations-2.6.0.jar;$CLASSESDIR\management-core-util-4.1.2.jar;$CLASSESDIR\management-measurement-4.1.2.jar;$CLASSESDIR\management-measurement-checkpoint-writer-1.0.jar;$CLASSESDIR\jna-4.2.2.jar;$CLASSESDIR\jna-platform-4.2.2.jar" --StartMode=jvm --StartClass=SubscriberACD.Subscriber --StartMethod=windowsService --StartParams=start --StopMode=jvm --StopClass=SubscriberACD.Subscriber --StopMethod=windowsService --StopParams=stop --LogPath="$INSTDIR\SubscriberACD\logs" --StdOutput=auto --StdError=auto'
Sleep 5000
ExecWait '"sc" config SubscriberACD start=" auto"'
Somehow, when I look at my NSIS logs, I see the following:
Execute: "C:\Program Files (x86)\MyProduct\SubscriberACD\bin\SubscriberACD.exe" //IS//SubscriberACD --Install="C:\Program Files (x86)\MyProduct\SubscriberACD\bin\SubscriberACD.exe" --Description=" Subscriber service with Apache Commons Daemon" --Jvm="C:\Program Files (x86)\MyProduct\SubscriberACD\jdk7\jre\bin\server\jvm.dll" --Classpath="C:\Program Files (x86)\MyProduct\SubscriberACD\classes\SubscriberACD.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\jeromq-0.3.5.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\jackson-databind-2.6.3.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\jackson-core-2.6.3.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\jackson-annotations-2.6.0.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\management-core-util-4.1.2.jar;C:\Program Files (x86)\MyProduct\SubscriberACD\classes\management-measurement-4.1.2.jar;C:\PrograExecute: "sc" config SubscriberACD start= auto
Notice how NSIS combined the two lines and actually overwrote some of the content from the first line. Any ideas on on what is causing this? Does NSIS not like commands with long parameters?
Originally, I used ExecWait for my first command. When I was seeing the same problem, I switch to using Exec and then added a Sleep 5000 after that to sleep for 5 seconds since I thought it might have been a timing issue.
I double checked my quotation marks to make sure that they match.
NSIS has a 1024 character limit by default. I'm guessing when $INSTDIR is expanded you exceed that limit. You can download the large string build or execute a batch file instead:
Section
InitPluginsDir
FileOpen $0 "$PluginsDir\test.cmd" w
FileWrite $0 '#echo off$\n'
; Write out example command in pieces:
FileWrite $0 '"$sysdir\forfiles.exe"'
FileWrite $0 ' /P "$windir" /S'
FileWrite $0 ' /M "*shell32*"$\n'
FileClose $0
ExecWait '"$PluginsDir\test.cmd"'
SectionEnd
I have to create a .BAT file that does this:
If C:\myprogram\sync\data.handler exists, exit;
If C:\myprogram\html\data.sql does not exist, exit;
In C:\myprogram\sync\ delete all files and folders except (test, test3 and test2)
Copy C:\myprogram\html\data.sql to C:\myprogram\sync\
Call other batch file with option sync.bat myprogram.ini.
If it was in the Bash environment it was easy for me, but I do not know how to test if a file or folder exists and if it is a file or folder.
You can use IF EXIST to check for a file:
IF EXIST "filename" (
REM Do one thing
) ELSE (
REM Do another thing
)
If you do not need an "else", you can do something like this:
set __myVariable=
IF EXIST "C:\folder with space\myfile.txt" set __myVariable=C:\folder with space\myfile.txt
IF EXIST "C:\some other folder with space\myfile.txt" set __myVariable=C:\some other folder with space\myfile.txt
set __myVariable=
Here's a working example of searching for a file or a folder:
REM setup
echo "some text" > filename
mkdir "foldername"
REM finds file
IF EXIST "filename" (
ECHO file filename exists
) ELSE (
ECHO file filename does not exist
)
REM does not find file
IF EXIST "filename2.txt" (
ECHO file filename2.txt exists
) ELSE (
ECHO file filename2.txt does not exist
)
REM folders must have a trailing backslash
REM finds folder
IF EXIST "foldername\" (
ECHO folder foldername exists
) ELSE (
ECHO folder foldername does not exist
)
REM does not find folder
IF EXIST "filename\" (
ECHO folder filename exists
) ELSE (
ECHO folder filename does not exist
)
Here is a good example on how to do a command if a file does or does not exist:
if exist C:\myprogram\sync\data.handler echo Now Exiting && Exit
if not exist C:\myprogram\html\data.sql Exit
We will take those three files and put it in a temporary place. After deleting the folder, it will restore those three files.
xcopy "test" "C:\temp"
xcopy "test2" "C:\temp"
del C:\myprogram\sync\
xcopy "C:\temp" "test"
xcopy "C:\temp" "test2"
del "c:\temp"
Use the XCOPY command:
xcopy "C:\myprogram\html\data.sql" /c /d /h /e /i /y "C:\myprogram\sync\"
I will explain what the /c /d /h /e /i /y means:
/C Continues copying even if errors occur.
/D:m-d-y Copies files changed on or after the specified date.
If no date is given, copies only those files whose
source time is newer than the destination time.
/H Copies hidden and system files also.
/E Copies directories and subdirectories, including empty ones.
Same as /S /E. May be used to modify /T.
/T Creates directory structure, but does not copy files. Does not
include empty directories or subdirectories. /T /E includes
/I If destination does not exist and copying more than one file,
assumes that destination must be a directory.
/Y Suppresses prompting to confirm you want to overwrite an
existing destination file.
`To see all the commands type`xcopy /? in cmd
Call other batch file with option sync.bat myprogram.ini.
I am not sure what you mean by this, but if you just want to open both of these files you just put the path of the file like
Path/sync.bat
Path/myprogram.ini
If it was in the Bash environment it was easy for me, but I do not
know how to test if a file or folder exists and if it is a file or
folder.
You are using a batch file. You mentioned earlier you have to create a .bat file to use this:
I have to create a .BAT file that does this:
Type IF /? to get help about if, it clearly explains how to use IF EXIST.
To delete a complete tree except some folders, see the answer of this question: Windows batch script to delete everything in a folder except one
Finally copying just means calling COPY and calling another bat file can be done like this:
MYOTHERBATFILE.BAT sync.bat myprogram.ini
I am doing something like this:
all:
#SET /p filecontent= < somefile.txt
#echo %filecontent%
However the filecontent variable does not seem to hold the contents of the file somefile.txt.
It is possible to read a file that is not a valid nmake file using !INCLUDE. For examle if we have a version file version that contains a single line of text we can do that:
//version file
1.2.4
//makefile
VERSION= \
!INCLUDE <version>
It is not working if the file contains more than one line.
Simply ensure somefile.txt is in acceptable nmake syntax, and then !include it. Thus:
c:>type somefile.txt
PASSWORD=secret
c:>type makefile
!INCLUDE somefile.txt
!MESSAGE Password is [$(PASSWORD)]
c:>nmake -nologo
Password is [secret]
You could try something like this:
# ---- vitaly.mak ----
target1:
# create and invoke a temporary cmd file
#<<mygetpassword.cmd
#echo off
setlocal
#SET /p filecontent= < secret.txt
#echo %filecontent%
endlocal
<<
#--- END ---
I think a cmd/bat file run within nmake.exe cannot affect the environment of nmake. So you must use the password that you grabbed from the secret.txt within the temporary cmd file.