Upgrading notepad++ with one click.
-
Hi
Often when I start notepad++ it asks to upgrade to the latest version. And I always have to answer the same questions again…
Would it be possible to get a one click upgrade?
Cheers, Oliver -
@Oliver-Maag said in Upgrading notepad++ with one click.:
Hi
Often when I start notepad++ it asks to upgrade to the latest version. And I always have to answer the same questions again…
Would it be possible to get a one click upgrade?While a one click upgrade is technically possible it would require adding components to Notepad++ that are very much against against the existing practice of keeping the application as lightweight as possible in terms of system resources used.
If you rarely use Notepad++ then you may be ok with disabling the check for updates and instead doing manual checks for updates. There are a couple of ways to do this. The next time you get the “Update available” prompt then click the
[Never]
button. Or, under Settings / Preferences / MISC. you can uncheck theEnable Notepad++ auto-updater
configuration setting. -
@Oliver-Maag Pass the
/S
argument to the installer with PythonScript to make the install silent.# https://community.notepad-plus-plus.org/topic/23039/faq-how-to-install-and-run-a-script-in-pythonscript # https://community.notepad-plus-plus.org/topic/25817/upgrading-notepad-with-one-click from Npp import notepad, MENUCOMMAND import os, subprocess, tempfile import xml.etree.ElementTree if sys.version_info.major == 2: import urllib import urllib2 urllib.request = urllib else: import urllib.request def main(): # Check for update version = notepad.getVersion() version = '.'.join(str(i) for i in version) url = 'https://notepad-plus-plus.org/update/getDownloadUrl.php?version=' + version if sys.version_info.major == 2: r = urllib2.urlopen(url) content = r.read().decode('utf-8') else: with urllib.request.urlopen(url) as r: content = r.read().decode('utf-8') dic = {'NeedToBeUpdated': 'no', 'Version': '', 'Location': ''} root = xml.etree.ElementTree.fromstring(content) for child in root: if child.tag in dic: dic[child.tag] = child.text if dic['NeedToBeUpdated'] == 'yes': reply = notepad.messageBox('Update to Notepad++ v' + dic['Version'], 'NppUpdate', MESSAGEBOXFLAGS.ICONQUESTION| MESSAGEBOXFLAGS.YESNO| MESSAGEBOXFLAGS.DEFBUTTON2) if reply == MESSAGEBOXFLAGS.RESULTNO: return else: notepad.messageBox('No update', 'NppUpdate') return # Download and install tempDir = tempfile.mkdtemp(prefix='NppUpdate_') installerName = dic['Location'].split('/')[-1] installerPath = os.path.join(tempDir, installerName) urllib.request.urlretrieve(dic['Location'], installerPath) command = ('ping -n 6 localhost&' '"{}" /S&' 'rd /s /q "{}"').format(installerPath, tempDir) subprocess.Popen(command, shell=True) notepad.menuCommand(MENUCOMMAND.FILE_EXIT) main()
Suggest to disable builtin auto updater as @mkupper mentions. Run this script every month or two to check for new version and update Notepad++ if a newer version exists.
It will check the version, if update is yes, download the new installer, it will exit Notepad++, wait 5 seconds and then run the installer with argument
/S
to install silently.If your happy with the default options for installation then a silent install might be suitable. If option selection is preferred, then silent install may not be a good option.
Tested the script with PythonScript 2.0 and 3.0.18.
-
-
The script I posted previous downloads x86 installer. Seems GUP.exe does some kind of get/post messages to the server to get the x64 installer. The changes to the new script will check notepad.exe if x86 or x64 (not arm, arm64 as I cannot test these installers) and will modify the installer name to download.
If anyone installed Notepad++ with the previous script expecting x64, I am sorry for the event.
from Npp import notepad, MENUCOMMAND import os, subprocess, tempfile import xml.etree.ElementTree if sys.version_info.major == 2: import urllib import urllib2 urllib.request = urllib else: import urllib.request def main(): def getExeBitness(file): with open(file, 'rb') as r: pos = r.read(1024).find(b'PE') r.seek(pos + 4, 0) char = r.read(1) if char == b'd': return 'x64' elif char == b'L': return 'x86' # Check for update version = notepad.getVersion() version = '.'.join(str(i) for i in version) url = 'https://notepad-plus-plus.org/update/getDownloadUrl.php?version=' + version if sys.version_info.major == 2: r = urllib2.urlopen(url) content = r.read().decode('utf-8') else: with urllib.request.urlopen(url) as r: content = r.read().decode('utf-8') dic = {'NeedToBeUpdated': 'no', 'Version': '', 'Location': ''} root = xml.etree.ElementTree.fromstring(content) for child in root: if child.tag in dic: dic[child.tag] = child.text if dic['NeedToBeUpdated'] == 'yes': reply = notepad.messageBox('Update to Notepad++ v' + dic['Version'], 'NppUpdate', MESSAGEBOXFLAGS.ICONQUESTION| MESSAGEBOXFLAGS.YESNO| MESSAGEBOXFLAGS.DEFBUTTON2) if reply == MESSAGEBOXFLAGS.RESULTNO: return else: notepad.messageBox('No update', 'NppUpdate') return # Get bitness. nppPath = os.path.join(notepad.getNppDir(), 'notepad++.exe') nppBitness = getExeBitness(nppPath) if not nppBitness: notepad.messageBox('Notepad++.exe get bitness failed', 'NppUpdate') return if nppBitness == 'x64': dic['Location'] = dic['Location'].replace('er.exe', 'er.x64.exe') # Download and install tempDir = tempfile.mkdtemp(prefix='NppUpdate_') installerName = dic['Location'].split('/')[-1] installerPath = os.path.join(tempDir, installerName) urllib.request.urlretrieve(dic['Location'], installerPath) command = ('ping -n 6 localhost&' '"{}" /S&' 'rd /s /q "{}"').format(installerPath, tempDir) subprocess.Popen(command, shell=True) notepad.menuCommand(MENUCOMMAND.FILE_EXIT) main()
-
@mpheath said in Upgrading notepad++ with one click.:
The script I posted previous downloads x86 installer. Seems GUP.exe does some kind of get/post messages to the server to get the x64 installer. The changes to the new script will check notepad.exe if x86 or x64 (not arm, arm64 as I cannot test these installers) and will modify the installer name to download.
Use
param=x64
to ask for the URL of the 64-bit download. For example, https://notepad-plus-plus.org/update/getDownloadUrl.php?version=8.65¶m=x64 It’s an HTTP GET.Use
param=arm64
for the ARM CPU.If the
param
is not defined or is not recognized then you will get the URL of the Windows 32-bit version of Notepad++'s installer. -
@mkupper said in Upgrading notepad++ with one click.:
Use
param=x64
to ask for the URL of the 64-bit download. For example, https://notepad-plus-plus.org/update/getDownloadUrl.php?version=8.65¶m=x64 It’s an HTTP GET.Thanks @mkupper , it certainly helps to improve the script.
Use
param=arm64
for the ARM CPU.ARM is not supported by the script. Have no ARM device to test, identify and offer support. Anyone can update the script to add ARM support if they want.
One last final (fingers-crossed) one click to update script:
Click Yes to download and install the update silently.
# https://community.notepad-plus-plus.org/topic/23039/faq-how-to-install-and-run-a-script-in-pythonscript # https://community.notepad-plus-plus.org/topic/25817/upgrading-notepad-with-one-click from Npp import notepad, MENUCOMMAND import os, subprocess, sys, tempfile import xml.etree.ElementTree if sys.version_info.major == 2: import urllib import urllib2 else: import urllib.request def main(): # Check for update version = notepad.getVersion() version = '.'.join(str(i) for i in version) url = ('https://notepad-plus-plus.org/update/' 'getDownloadUrl.php?version={}¶m={}' .format(version, 'x64' if sys.maxsize > 2**31-1 else '')) if sys.version_info.major == 2: r = urllib2.urlopen(url) content = r.read().decode('utf-8') else: with urllib.request.urlopen(url) as r: content = r.read().decode('utf-8') dic = {'NeedToBeUpdated': 'no', 'Version': '', 'Location': ''} root = xml.etree.ElementTree.fromstring(content) for child in root: if child.tag in dic: dic[child.tag] = child.text installerName = dic['Location'].split('/')[-1] if dic['NeedToBeUpdated'] == 'yes': reply = notepad.messageBox(('"{}"\n is available to download.\n\n' 'Update to Notepad++ v{}?' .format(installerName, dic['Version'])), 'NppUpdate', MESSAGEBOXFLAGS.ICONQUESTION| MESSAGEBOXFLAGS.YESNO| MESSAGEBOXFLAGS.DEFBUTTON2) if reply == MESSAGEBOXFLAGS.RESULTNO: return else: notepad.messageBox('No update', 'NppUpdate') return # Download and install tempDir = tempfile.mkdtemp(prefix='NppUpdate_') installerPath = os.path.join(tempDir, installerName) if sys.version_info.major == 2: urlsave = urllib.urlretrieve else: urlsave = urllib.request.urlretrieve urlsave(dic['Location'], installerPath) command = ('ping -n 6 localhost&' '"{}" /S&' 'rd /s /q "{}"').format(installerPath, tempDir) subprocess.Popen(command, shell=True) notepad.menuCommand(MENUCOMMAND.FILE_EXIT) main()
Thanks everyone for the help and support to achieve this stress relieving one click update Notepad++ script.
-
-
Thanks for this very useful script.
I tested it also for some non-standard installations (even for a portable N++) and found a problem - it can upgrade different N++ than the one, from which the script is launched. Here is the fixed part:
nppDir = notepad.getNppDir() command = ('ping -n 6 localhost&' '"{}" /S /D={}&' 'rd /s /q "{}"').format(installerPath, nppDir, tempDir)
-
@xomx said in Upgrading notepad++ with one click.:
I tested it also for some non-standard installations (even for a portable N++)
The script enforces no restrictions. My testing has been done from a portable N++.
it can upgrade different N++ than the one, from which the script is launched.
Yes it can upgrade not on the current path, but as a system wide install. The intention is not to upgrade a portable or upgrade one of multiple installations.
Forcing the
/D=
argument could make the situation problematic, not just for launching from a portable location, but in an environment where multiple installation can exist brings up the question of why that would be done. Is it because the installer allows this intentionally as being a good idea? Upgrading a portable to installed could be a bad event if done by accident.The script could check if
doLocalConf.xml
exists innppDir
and if not exist, safely add the/D=
argument. This would prevent portable Notepad++ being installed over with an upgrade install. Do you consider that as ok with your fix? If yes, that means from a portable is a default install in the predefined location that the installer chooses. If no, please define a possible solution.I have previously thought about a portable upgrade with a portable zip download though it has not been attempted yet and not sure if a good idea, though some users may like the concept and it may be just as convenient as an install usually is for users.
I am not sure of how chocolately and other systems do this with silent installs though might be wise to work with their behaviour so any suggestions are welcome to clarify the best result. I am open to ideas to solve this.
Thanks for the participation and appreciation in the script.
-
@xomx Thanks, I have implemented your fix with
/D=
into this version now that the portable zip is supported.# https://community.notepad-plus-plus.org/topic/23039/faq-how-to-install-and-run-a-script-in-pythonscript # https://community.notepad-plus-plus.org/topic/25817/upgrading-notepad-with-one-click from Npp import notepad, MENUCOMMAND import os, subprocess, sys, tempfile, zipfile import xml.etree.ElementTree if sys.version_info.major == 2: import urllib import urllib2 else: import urllib.request def main(): # Check for update version = notepad.getVersion() version = '.'.join(str(i) for i in version) nppDir = notepad.getNppDir() localConfigFile = os.path.join(nppDir, 'doLocalConf.xml') portable = os.path.isfile(localConfigFile) url = ('https://notepad-plus-plus.org/update/' 'getDownloadUrl.php?version={}¶m={}' .format(version, 'x64' if sys.maxsize > 2**31-1 else '')) if sys.version_info.major == 2: r = urllib2.urlopen(url) content = r.read().decode('utf-8') else: with urllib.request.urlopen(url) as r: content = r.read().decode('utf-8') dic = {'NeedToBeUpdated': 'no', 'Version': '', 'Location': ''} root = xml.etree.ElementTree.fromstring(content) for child in root: if child.tag in dic: dic[child.tag] = child.text installerName = dic['Location'].split('/')[-1] if portable: parts = installerName.split('.') for i, part in enumerate(parts): if part.lower() == 'installer': parts[i] = 'portable' elif part == 'exe': parts[i] = 'zip' installerName = '.'.join(parts) dic['Location'] = dic['Location'].rsplit('/', 1)[0] + '/' + installerName if dic['NeedToBeUpdated'] == 'yes': reply = notepad.messageBox(('"{}"\n is available to download.\n\n' 'Update to Notepad++ v{}?' .format(installerName, dic['Version'])), 'NppUpdate', MESSAGEBOXFLAGS.ICONQUESTION| MESSAGEBOXFLAGS.YESNO| MESSAGEBOXFLAGS.DEFBUTTON2) if reply == MESSAGEBOXFLAGS.RESULTNO: return else: notepad.messageBox('No update', 'NppUpdate') return # Download and install tempDir = tempfile.mkdtemp(prefix='NppUpdate_') installerPath = os.path.join(tempDir, installerName) if sys.version_info.major == 2: urlsave = urllib.urlretrieve else: urlsave = urllib.request.urlretrieve urlsave(dic['Location'], installerPath) if portable: with zipfile.ZipFile(installerPath, 'r') as z: names = z.namelist() for item in ('config.xml', 'contextMenu.xml', 'doLocalConf.xml', 'nppLogNulContentCorruptionIssue.xml', 'shortcuts.xml', 'toolbarIcons.xml', 'autoCompletion/', 'functionList/', 'localization/', 'themes/', 'userDefineLangs/'): for name in names[:]: if '/' in item: if name.startswith(item): names.remove(name) elif item == name: names.remove(name) z.extractall(tempDir + '\\zip', members=names) command = ('ping -n 6 localhost&' 'robocopy /s /e /move /r:2 /np /xx' ' "/log:{1}\\update.log" "{2}\\zip" "{1}"&' 'rd /s /q "{2}"').format(installerPath, nppDir, tempDir) else: command = ('ping -n 6 localhost&' '"{}" /S /D={}&' 'rd /s /q "{}"').format(installerPath, nppDir, tempDir) subprocess.Popen(command, shell=True) notepad.menuCommand(MENUCOMMAND.FILE_EXIT) main()
For x86 and x64 only. No support for ARM.
- If Notepad++ is portable then it downloads the zip and extracts to a temporary folder.
- If Notepad++ is installed, downloads the installer to a temporary folder.
- Control will be handed over to CMD just before Notepad++ is closed.
- Waits 5 seconds, install or unzip and move files and then removes the temporary folder.
Due to zip users may customize means that some root files and many subfolders will not be extracted from the zip as a precaution.
—
moderated fixed theversion =
line, per mpheath’s request -
-
@mpheath said in Upgrading notepad++ with one click.:
Forcing the /D= argument could make the situation problematic, not just for launching from a portable location, but in an environment where multiple installation can exist brings up the question of why that would be done.
I would expect - the N++ installation, I am running the script from, to be updated.
@mpheath said in Upgrading notepad++ with one click.:
The script could check if doLocalConf.xml exists in nppDir and if not exist, safely add the /D= argument.
Yes, I am for it.
@mpheath said in Upgrading notepad++ with one click.:
This would prevent portable Notepad++ being installed over with an upgrade install. Do you consider that as ok with your fix?
Ok. I do not want to update the portable N++ setup to the installed one either.
@mpheath said in Upgrading notepad++ with one click.:
If yes, that means from a portable is a default install in the predefined location that the installer chooses. If no, please define a possible solution.
No. For a solution - see below.
@mpheath said in Upgrading notepad++ with one click.:
I have previously thought about a portable upgrade with a portable zip download
Yes, this could be the solution for the portable N++:
- detection by the aforementioned doLocalConf.xml check
- if portable N++, changing the ‘NeedToBeUpdated’ message to something like:
“npp.8.6.7.portable.x64.zip” update is is available for your portable Notepad++ setup. Do you want to download this file to “%USERPROFILE%\Downloads” ? (for the portable setups an automatic update is not currently available)"
As the portable installations cannot be simply updated by directly overwriting from the downloaded archive (overwriting of the N++ settings…), I would left that job on the users now - after all, if a user was able to manually get a portable installation up and running, they should also be able to manually update it after.
There is also another problem with this script - the possible N++ multi-instance mode (multiple running N++ instances …). But it can be easily solved if my new PR for the NSIS N++ installer is accepted.
Edit: I wrote my reply without seeing your new post.
-
@xomx said in Upgrading notepad++ with one click.:
But it can be easily solved if my new PR for the NSIS N++ installer is accepted.
Good. I’ll take it for granted that the PR works perfect, so gave the PR a thumbs up.
I consider I have met your expectations with your last reply with the last posted script. The portable needed some protection from the installer which I considered as quite important with using the
/D=
argument. So again thanks for suggesting the fix. Let me know if you have anymore issues with the script. -
Perfect! I tested the new portable update and so far so good.
-
Thanks @PeterJones for the fix.
I rigged the version with
'0'#
to always prompt to upgrade with the last script. Peter was nice enough to fix it for me. So anyone who copied the last script, please do so again else you will update even if you have the latest version. I have copied and tested the script and now tells me thatNo update
so the mistake is fixed.@xomx Perfect now, well hope to be close as possible.
I have upgraded my existing portable many times and still working well. I have not used the backup that I zipped up before testing yet, so it seems good.
-
You can use WingetUI