Recursive search for sql files in directories (NSIS) - nsis

I have a problem with recursive search, but first some key data:
I have several directories filled with sql files which I want to copy to $TEMP
the directories i want to read from look like this v2.1.0.0
at the moment, the directories v2.5.0.0 to v2.7.0.3 have to be read
folders dont have to be "the next" so v2.5.0.3 can follow v2.5.0.0
I'm using the LogicLib
I'm new to this language (before java) and this is my first task
I'm currently trying to solve the problem with a ${ForEach}
!macro GetSQLVersionFiles first second third fourth
SetOutPath $TEMP
${ForEach} ${first} 0 9 + 1
${ForEach} ${second} 0 9 + 1
${ForEach} ${third} 0 9 + 1
${ForEach} ${fourth} 0 9 + 1
IfFileExists "scripte\v${first}.${second}.${third}.${fourth}" 0 +2
File "scripte\v${first}.${second}.${third}.${fourth}\*.sql"
${next}
${next}
${next}
${next}
!macroend
so my idea was, to make it viable for later, to have a macro with 4 parameters in which one can put the start directory, say the desired "2 5 0 0" and it iterates through every folder and puts the found .sql files into the $TEMP directory
things i've already tried
refering to all parameters without the {}
writing "${first} ${first} 9 + 1 (thought this would only iterate FROM first to 9)
the error i get is following
!insertmacro: _ForEach
Usage: StrCpy $(user_var: output) str [maxlen] [startoffset]
Error in macro _ForEach on macroline 3
Error in macro GetSQLVersionFiles on macroline 2
Error in script "\\NAMEOFMYSCRIPT -- aborting creation process
the third line in _ForEach of the LogicLib is
StrCpy "${_v}" "${_f}" ; Assign the initial value
Thanks in advance for your help :)

You are mixing defines and variables.
Defines are created with !define and accessed with ${name}.
Variables are created with Var and accessed with $name. There are also some built in variables you can use: $0..$9.
Variables can be changed at run-time, defines cannot.
The other issue is that you cannot use the File instruction to copy files on the end-users machine, you need to use the CopyFiles instruction if you want to copy files at run-time. If on the other hand you want to extract files from the installer (I cannot tell which you want based on your question) then you do need to use the File instruction but then you cannot use ${For} because it is a run-time concept. You can use !system to execute a batch file that builds a list of files in a .nsh that you then !include.

Related

Compare 'installed-version'versus 'to-be-installed-version'

Have been working with NSIS (v3.05) for a few weeks. Does what it needs to do. I have been chasing the following problem for a few days and have not been able to comprehend it completely.
Problem statement:
Compare two (2) versions with each other. Many ways to implement. I chose the following:
1st 'version' (string) is retrieved from the currently installed versions .txt file via (function) LineRead (!include TextFunc.nsh) like this:
IfFileExists "C:\$PROGRAMFILES64\...\VERSION.txt" 0 +31 # Open the file and perform N FileRead
DetailPrint "VERSION.txt found!"
${LineRead} "C:\$PROGRAMFILES64\...\VERSION.txt" "7" $4 # $4 = '1.x.y.z' (for example)
2nd 'version' is retrieved with following code:
!getdllversion "C:\...\application_name.exe" expversion_
StrCpy $7 ${expversion_} # pass the define string 'expversion' to $7
As last part I use following code for comparison of $4 and $7:
${VersionCompare} $4 $7 $R0
This can only work as I know for sure that '$4' (version string #1) and '$7' (version string #2) are correct inputs for VersionCompare (output: $R0)
Question: Is there a way to display (for test/check) the content of $4 (# compile time) in order to know for sure var $4 contains the correct string to be passed to function 'VersionCompare'? (tried 'DetailPrint $4'; does not resolve into the expected string (retrieved by function 'LineRead'). (I know that 'DetailPrint' only displays during executing the installation '.exe. file So is makes sense not seeing that # compile time.)
Output from MakeNSIS:
IfFileExists: "C:\$PROGRAMFILES64\...\VERSION.txt" ? 0 : +31
DetailPrint: "VERSION.txt found!"
!insertmacro: LineReadCall
!insertmacro: end of LineReadCall
DetailPrint: "The version number of the currently installed app: $4"
How-To get $4 resolve into the version string (for testing purposes) during compile time)?
Question number 2:
I use the preprocessor command '!GetDLLVersion' in a function to retrieve version number of the to be installed version of the 'app' (via The NSIS Installer...). MakeNSIS displays resolving the version correctly:
Function: "VersionRetrievalBinary"
!getdllversion: C:\1_SW_dev\...\app.exe (1.8.47.5)->(expversion_<1..4>)
Question: What exactly is 'expverion_'?; a var or a define? If a define (which I read here => Reference/!getdllversion), do I need to define it in my script as follow?:
!define expverion_1 " " # Major; single digit
!define expverion_2 " " # Minor; 2-digit
!define expverion_3 " " # Build; 3-digit
!define expverion_4 " "# Revision; 3-digit
Being unsure what 'expversion_' exactly is and operates/works MakeNSIS throws following warning that -I think- indicates clearly something is incorrect:
warning 6000: unknown variable/constant "{expversion_}" detected, ignoring (C:\1_SW_dev\...\app_client.nsi:295)
The worrying part is the word 'ignoring' in the MakeNSIS compiling message. Can I conclude from above mentioned warning message that assigning the string derived from the (define?) with name "expversion_" is not passed to var $7 by means of command:
StrCpy $7 ${expversion_}
Following MakeNSIS message (# compile time) appears to confirm this:
StrCpy $7 "${expversion_}" () ()
It appears to resolve empty (unsure if I read this MakeNSIS message correctly).
Although having learned a lot wrt NSIS (and liking it) and gone through most of the relevant documentation I do not get my head around this one.
Thnx in advance for solving this specific piece of the puzzle.
Have solved the puzzle myself.
The solution to a version comparison is rather 'simple'. The essential parts herewith: (add to .onInit)
Create a function (e.g. name 'VersionComparison')
Read local version from registry
'Read' installation version from binary (e.g. .DLL or .exe)
Use VersionCompare (!include WordFunc.nsh) to perform the actual comparison.
I'll tackle the !getdllversion issue first. It extracts the 4 16-bit numbers from the start of the version info block and stores them in 4 defines. It simply uses the name you pass in plus a number when naming the defines.
!getdllversion "$%windir%\explorer.exe" foo
!warning ${foo2} ; This prints the minor version
There is no specific number of digits as expected by your comments. Each of the 4 numbers go from 0 to 65535.
You can do basic verification of these numbers at compile time:
!if ${foo1} < 1
!error "Major version must at least be 1, we don't ship beta software :) "
!endif
The 2nd problem is harder to solve. Variables can only be expanded when the installer is running. The only option is to actually generate and run a "installer" from inside your main .nsi:
!makensis vertest.nsi = 0
!execute '"$%temp%\vertest.exe" /S' = 0
!defile "$%temp%\vertest.exe"
where vertest.nsi would look something like
OutFile "$%temp%\vertest.exe"
RequestExecutionLevel user
SilentInstall silent
Section
Do version test here and Goto..
fail:
Abort
success:
SectionEnd

Change file's name using command line arguments Bash [duplicate]

This question already has answers here:
Change file's numbers Bash
(2 answers)
Closed 2 years ago.
I need to implement a script (duplq.sh) that would rename all the text files existing in the current directory using the command line arguments. So if the command duplq.sh pic 0 3 was executed, it would do the following transformation:
pic0.txt will have to be renamed pic3.txt
pic1.txt to pic4.txt
pic2.txt to pic5.txt
pic3.txt to pic6.txt
etc…
So the first argument is always the name of a file the second and the third always a positive digit.
I also need to make sure that when I execute my script, the first renaming (pic0.txt to pic3.txt), does not erase the existing pic3.txt file in the current directory.
Here's what i did so far :
#!/bin/bash
name="$1"
i="$2"
j="$3"
for file in $name*
do
echo $file
find /var/log -name 'name[$i]' | sed -e 's/$i/$j/g'
i=$(($i+1))
j=$(($j+1))
done
But the find command does not seem to work. Do you have other solutions ?
The problem you're trying to solve is actually somewhat tricky, and I don't think you've fully thought it through. For instance, what's the difference between duplq.sh pic 0 3 and duplq.sh pic 2 5 -- it looks like both should just add 3 to the number, or would the second skip "pic0.txt" and "pic1.txt"? What effect would either one have on files named "pic", "pic.txt", "picture.txt", "picture2.txt", "pic2-2.txt", or "pic999.txt".
There are also a bunch of basic mistakes in the script you have so far:
You should (almost) always put variable references in double-qotes, to avoid unexpected word-splitting and wildcard expansion. So, for example, use echo "$file" instead of echo $file. In for file in $name*, you should put double-quotes around the variable but not the *, because you want that to be treated as a wildcard. Hence, the correct version is for file in "$name"*
Don't put variable references in single-quotes, they aren't expanded there. So in the find and sed commands, you aren't passing the variables' values, you're passing literal dollar signs followed by letters. Again, use double-quotes. Also, you don't have a "$" before "name", so it won't be treated as a variable even in double-quotes.
But the find and sed commands don't do what you want anyway. Consider find /var/log -name "name[1]" -- that looks for files named "name1", not "name1" + some extension. And it looks in the current directory and all subdirectories, which I'm pretty sure you don't want. And the "1" ("$i") may not be the number in the current filename. Suppose there are files named "pic0.jpg", "pic0.png", and "pic0.txt" -- on the first iteration, the loop might find all three with a pattern like "pic0*", then on the second and third iterations try to find "pic1*" and "pic2*, which don't exist. On the other hand, suppose there are files named "pic0.txt", "pic5.txt", and "pic8.txt" -- again, it might look for "pic0*" (ok), then "pic1*" (not found), and then "pic2*" (ditto).
Also, if you get to multi-digit numbers, the pattern "name[10]" will match "file0" and "file1", but not "file10". I don't know why you added the brackets there, but they don't do anything you'd want.
You already have the files being listed one at a time in the $file variable, searching again with different criteria just adds confusion.
Also, at no point in the script do you actually rename anything. The find | sed line will (if it works) print the new name for the file, but not actually rename it.
BTW, when you do use the mv command, use either mv -n or mv -i to keep it from silently and irretrievably overwriting files if/when a name conflict occurs.
To prevent overwriting when incrementing file numbers, you need to do the renames in reverse numeric order (i.e. rename "pic3.txt" to "pic6.txt" before renaming "pic0.txt" to "pic3.txt"). This is especially tricky because if you just sort filenames in reverse alphabetic order, you'll get "pic7.txt" before "pic10.txt". But you can't do a numeric sort without removing the "pic" and ".txt" parts first.
IMO this is actually the trickiest problem to be solved in order to get this script to work right. It might be simplest to specify the largest index number as one of the arguments, and have it start there and count down to 0 (looping over numbers rather than files), and then for each number iterate over matching files (e.g. "pic0.jpg", "pic0.png", and "pic0.txt").
So I assume that 0 3 is just a measurement for the difference of old num and new num and equivalent to 1 4 or 100 103.
To avoid overwriting existing files, create a new temp dir, move all affected files there, and move all of them back in the end.
#/bin/bash
#
# duplq.sh pic 0 3
base="$1"
delta=$(( $3 - $2 ))
# echo delta $delta
target=$(mktemp -d)
echo $target
# /tmp/tmp.7uXD2GzqAb
add () {
f="$1"
b="$2"
d=$3
num=${f#./${b}}
# echo -e "file: $f \tnum: $num \tnum + d: $((num + d))" ;
echo -e "$((num + d))" ;
}
for f in $(find -maxdepth 1 -type f -regex ".*/${base}[0-9]+")
do
newnum=$(add "$f" "${base}" $delta)
echo mv "$f" "$target/${base}$newnum"
done
# exit
echo mv $target/${base}* .
First I tried to just use bash syntax, to check, whether removal of the prefix (pic) results in just digits remaining. I also didn't use the extension .txt - this is left as an exercise for the reader. From the question it is unclear - it is never explicitly told, that all files share the same extension, but all files in the example do.
With the -regex ".*/${base}[0-9]+") in find, the values are guaranteed to be just digits.
num=${f#./${b}}
removes from file f the base ("pic"). Delta d is added.
Instead of really moving, I just echoed the mv-command.
#TODO: Implement the file name extension conservation.
And 2 other pitfalls came to my mind: If you have 3 files pic0, pic00 and pic000 they all will be renamed to pic3. And pic08 will be cut into pic and 08, 08 will then be tried to be read as octal number (or 09 or 012129 and so on) and lead to an error.
One way to solve this issue is, that you prepend the extracted number (001 or 018) with a "1", then add 3, and remove the leading 1:
001 1001 1004 004
018 1018 1021 021
but this clever solution leads to new problems:
999 1999 2002 002?
So a leading 1 has to be cut off, a leading 2 has to be reduced by 1. But now, if the delta is bigger, let's say 300:
018 1018 1318 318
918 1918 2218 1218
Well - that seems to be working.

Error when trying to use File inside ${ForEachIn}?

I have the following code block inside the .onInit function of my NSIS script.
; Split the supplied artifacts array.
nsArray::Split ARTIFACT_ARRAY "${ARTIFACTS}" ";"
${ForEachIn} ARTIFACT_ARRAY $R0 $R1
File ${IVY_ROOT}\"$R1"
${Next}
The ${ARTIFACTS} is a passed in property from ANT at NSIS compile time and is basically a comma seperated list of files. When I attempt to compile the script I get the error below.
[exec] File: "C:\My_Workspaces\WEnDL\\deployments\ivy\"$R1"" -> no files found.
[exec] Usage: File [/nonfatal] [/a] ([/r] [/x filespec [...]] filespec [...] |
[exec] /oname=outfile one_file_only)
[exec] Error in script "C:\My_Workspaces\WEnDL\/deployments/selections.nsis" on line 394 -- aborting creation process
Any pointers appreciated.
You cannot use variables in File instructions because variables are only evaluated on the end-users system. The same is true for plug-ins. You need to stick with ${defines} and the instructions starting with ! when parsing at compile-time.
The best option is letting your build system generate a .nsh with the File instructions if possible:
Section
SetOutPath $InstDir
!include "generatedfilelist.nsh"
SectionEnd
Another option is to call external tools or batch-files with !system and let them parse the list and generate the .nsh.
Finally, in NSIS v3 it might be possible to pull this off with macro recursion and !searchparse+!searchreplace but the available recursion depth is limited so it might not work depending on the number of files in your list.

NSIS Exec command with very long parameter list being cut off by the next line

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

How to modify text value in Bat file using Nsis script

I have builded Nsis script successfully.I have bat file in my project.Inside bat file i have two variables with default values as follows
JVM_DLL=c:\program Files\java\jre\bin\client\jvm.dll
Home_path=c:\opt\projectName
If the user wants to modify the value for JVM_DLL and Home_path that should be written in batch file.How to do this? I donot know how to write in batch file using Nsis script?
I have tried following codes.but its not working
StrCpy $JVM_DLL "jre\bin\client\jvm.dll"
${ConfigWrite} "$INSTDIR\resource\batch.bat" "JVM_DLL" "=$JVM_DLL" $R0
${ConfigWrite} "$INSTDIR\resource\batch.bat" "HOME_PATH" "=$INSTDIR" $R0
thanks
If you have defined the 2 values in the .bat file that is also launching makensis.exe, use the /D command line switch to define those values for the nsis script.
In your example, given your 2 .bat variables:
makensis.exe /DJVM_DLL=%JVM_DLL% /DHome_path=%Home_path% yourscript.nsi

Resources