Patchwork D6060: inno: replace add_path.exe with a Pascal script

login
register
mail settings
Submitter phabricator
Date March 5, 2019, 3:24 p.m.
Message ID <865e64a9aaf690c351d97b9f48eadffa@localhost.localdomain>
Download mbox | patch
Permalink /patch/39071/
State Not Applicable
Headers show

Comments

phabricator - March 5, 2019, 3:24 p.m.
This revision was automatically updated to reflect the committed changes.
Closed by commit rHG0f49b56d5d74: inno: replace add_path.exe with a Pascal script (authored by indygreg, committed by ).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D6060?vs=14335&id=14362

REVISION DETAIL
  https://phab.mercurial-scm.org/D6060

AFFECTED FILES
  contrib/packaging/inno/mercurial.iss
  contrib/packaging/inno/modpath.iss
  contrib/packaging/inno/readme.txt

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/contrib/packaging/inno/readme.txt b/contrib/packaging/inno/readme.txt
--- a/contrib/packaging/inno/readme.txt
+++ b/contrib/packaging/inno/readme.txt
@@ -40,9 +40,6 @@ 
   ISTool - optional
       http://www.istool.org/default.aspx/
 
-  add_path (you need only add_path.exe in the zip file)
-      http://www.barisione.org/apps.html#add_path
-
   Docutils
       http://docutils.sourceforge.net/
 
@@ -76,7 +73,7 @@ 
     "C:\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86_amd64
     python setup.py py2exe -b 3
 
-Copy add_path.exe and cacert.pem files into the dist directory that just got created.
+Copy cacert.pem files into the dist directory that just got created.
 
 If you are using Python 2.6 or later, or if you are using MSVC 2008 to compile
 mercurial, you must include the C runtime libraries in the installer. To do so,
@@ -99,13 +96,13 @@ 
   cd ..
 
 If you use ISTool, you open the
-C:\hg\hg-release\contrib\packaging\inno\mercurial.iss
+C:\hg\hg-release\contrib\packaging\inno-installer\mercurial.iss
 file and type Ctrl-F9 to compile the installer file.
 
 Otherwise you run the Inno Setup compiler.  Assuming it's in the path
 you should execute:
 
-  iscc contrib\packaging\inno\mercurial.iss /dVERSION=foo
+  iscc contrib\packaging\inno-installer\mercurial.iss /dVERSION=foo
 
 Where 'foo' is the version number you would like to see in the
 'Add/Remove Applications' tool.  The installer will be placed into
@@ -115,7 +112,7 @@ 
 
 If you want to build an installer for a 64-bit mercurial, add /dARCH=x64 to
 your command line:
-  iscc contrib\packaging\inno\mercurial.iss /dARCH=x64
+  iscc contrib\packaging\inno-installer\mercurial.iss /dARCH=x64
 
 To automate the steps above you may want to create a batchfile based on the
 following (MinGW build chain):
@@ -126,6 +123,6 @@ 
   cd doc
   mingw32-make html
   cd ..
-  iscc contrib\packaging\inno\mercurial.iss /dVERSION=snapshot
+  iscc contrib\packaging\inno-installer\mercurial.iss /dVERSION=snapshot
 
 and run it from the root of the hg repository (c:\hg\hg-release).
diff --git a/contrib/packaging/inno/modpath.iss b/contrib/packaging/inno/modpath.iss
new file mode 100644
--- /dev/null
+++ b/contrib/packaging/inno/modpath.iss
@@ -0,0 +1,219 @@ 
+// ----------------------------------------------------------------------------
+//
+// Inno Setup Ver:	5.4.2
+// Script Version:	1.4.2
+// Author:			Jared Breland <jbreland@legroom.net>
+// Homepage:		http://www.legroom.net/software
+// License:			GNU Lesser General Public License (LGPL), version 3
+//						http://www.gnu.org/licenses/lgpl.html
+//
+// Script Function:
+//	Allow modification of environmental path directly from Inno Setup installers
+//
+// Instructions:
+//	Copy modpath.iss to the same directory as your setup script
+//
+//	Add this statement to your [Setup] section
+//		ChangesEnvironment=true
+//
+//	Add this statement to your [Tasks] section
+//	You can change the Description or Flags
+//	You can change the Name, but it must match the ModPathName setting below
+//		Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
+//
+//	Add the following to the end of your [Code] section
+//	ModPathName defines the name of the task defined above
+//	ModPathType defines whether the 'user' or 'system' path will be modified;
+//		this will default to user if anything other than system is set
+//	setArrayLength must specify the total number of dirs to be added
+//	Result[0] contains first directory, Result[1] contains second, etc.
+//		const
+//			ModPathName = 'modifypath';
+//			ModPathType = 'user';
+//
+//		function ModPathDir(): TArrayOfString;
+//		begin
+//			setArrayLength(Result, 1);
+//			Result[0] := ExpandConstant('{app}');
+//		end;
+//		#include "modpath.iss"
+// ----------------------------------------------------------------------------
+
+procedure ModPath();
+var
+	oldpath:	String;
+	newpath:	String;
+	updatepath:	Boolean;
+	pathArr:	TArrayOfString;
+	aExecFile:	String;
+	aExecArr:	TArrayOfString;
+	i, d:		Integer;
+	pathdir:	TArrayOfString;
+	regroot:	Integer;
+	regpath:	String;
+
+begin
+	// Get constants from main script and adjust behavior accordingly
+	// ModPathType MUST be 'system' or 'user'; force 'user' if invalid
+	if ModPathType = 'system' then begin
+		regroot := HKEY_LOCAL_MACHINE;
+		regpath := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
+	end else begin
+		regroot := HKEY_CURRENT_USER;
+		regpath := 'Environment';
+	end;
+
+	// Get array of new directories and act on each individually
+	pathdir := ModPathDir();
+	for d := 0 to GetArrayLength(pathdir)-1 do begin
+		updatepath := true;
+
+		// Modify WinNT path
+		if UsingWinNT() = true then begin
+
+			// Get current path, split into an array
+			RegQueryStringValue(regroot, regpath, 'Path', oldpath);
+			oldpath := oldpath + ';';
+			i := 0;
+
+			while (Pos(';', oldpath) > 0) do begin
+				SetArrayLength(pathArr, i+1);
+				pathArr[i] := Copy(oldpath, 0, Pos(';', oldpath)-1);
+				oldpath := Copy(oldpath, Pos(';', oldpath)+1, Length(oldpath));
+				i := i + 1;
+
+				// Check if current directory matches app dir
+				if pathdir[d] = pathArr[i-1] then begin
+					// if uninstalling, remove dir from path
+					if IsUninstaller() = true then begin
+						continue;
+					// if installing, flag that dir already exists in path
+					end else begin
+						updatepath := false;
+					end;
+				end;
+
+				// Add current directory to new path
+				if i = 1 then begin
+					newpath := pathArr[i-1];
+				end else begin
+					newpath := newpath + ';' + pathArr[i-1];
+				end;
+			end;
+
+			// Append app dir to path if not already included
+			if (IsUninstaller() = false) AND (updatepath = true) then
+				newpath := newpath + ';' + pathdir[d];
+
+			// Write new path
+			RegWriteStringValue(regroot, regpath, 'Path', newpath);
+
+		// Modify Win9x path
+		end else begin
+
+			// Convert to shortened dirname
+			pathdir[d] := GetShortName(pathdir[d]);
+
+			// If autoexec.bat exists, check if app dir already exists in path
+			aExecFile := 'C:\AUTOEXEC.BAT';
+			if FileExists(aExecFile) then begin
+				LoadStringsFromFile(aExecFile, aExecArr);
+				for i := 0 to GetArrayLength(aExecArr)-1 do begin
+					if IsUninstaller() = false then begin
+						// If app dir already exists while installing, skip add
+						if (Pos(pathdir[d], aExecArr[i]) > 0) then
+							updatepath := false;
+							break;
+					end else begin
+						// If app dir exists and = what we originally set, then delete at uninstall
+						if aExecArr[i] = 'SET PATH=%PATH%;' + pathdir[d] then
+							aExecArr[i] := '';
+					end;
+				end;
+			end;
+
+			// If app dir not found, or autoexec.bat didn't exist, then (create and) append to current path
+			if (IsUninstaller() = false) AND (updatepath = true) then begin
+				SaveStringToFile(aExecFile, #13#10 + 'SET PATH=%PATH%;' + pathdir[d], True);
+
+			// If uninstalling, write the full autoexec out
+			end else begin
+				SaveStringsToFile(aExecFile, aExecArr, False);
+			end;
+		end;
+	end;
+end;
+
+// Split a string into an array using passed delimeter
+procedure MPExplode(var Dest: TArrayOfString; Text: String; Separator: String);
+var
+	i: Integer;
+begin
+	i := 0;
+	repeat
+		SetArrayLength(Dest, i+1);
+		if Pos(Separator,Text) > 0 then	begin
+			Dest[i] := Copy(Text, 1, Pos(Separator, Text)-1);
+			Text := Copy(Text, Pos(Separator,Text) + Length(Separator), Length(Text));
+			i := i + 1;
+		end else begin
+			 Dest[i] := Text;
+			 Text := '';
+		end;
+	until Length(Text)=0;
+end;
+
+
+procedure CurStepChanged(CurStep: TSetupStep);
+var
+	taskname:	String;
+begin
+	taskname := ModPathName;
+	if CurStep = ssPostInstall then
+		if IsTaskSelected(taskname) then
+			ModPath();
+end;
+
+procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
+var
+	aSelectedTasks:	TArrayOfString;
+	i:				Integer;
+	taskname:		String;
+	regpath:		String;
+	regstring:		String;
+	appid:			String;
+begin
+	// only run during actual uninstall
+	if CurUninstallStep = usUninstall then begin
+		// get list of selected tasks saved in registry at install time
+		appid := '{#emit SetupSetting("AppId")}';
+		if appid = '' then appid := '{#emit SetupSetting("AppName")}';
+		regpath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\'+appid+'_is1');
+		RegQueryStringValue(HKLM, regpath, 'Inno Setup: Selected Tasks', regstring);
+		if regstring = '' then RegQueryStringValue(HKCU, regpath, 'Inno Setup: Selected Tasks', regstring);
+
+		// check each task; if matches modpath taskname, trigger patch removal
+		if regstring <> '' then begin
+			taskname := ModPathName;
+			MPExplode(aSelectedTasks, regstring, ',');
+			if GetArrayLength(aSelectedTasks) > 0 then begin
+				for i := 0 to GetArrayLength(aSelectedTasks)-1 do begin
+					if comparetext(aSelectedTasks[i], taskname) = 0 then
+						ModPath();
+				end;
+			end;
+		end;
+	end;
+end;
+
+function NeedRestart(): Boolean;
+var
+	taskname:	String;
+begin
+	taskname := ModPathName;
+	if IsTaskSelected(taskname) and not UsingWinNT() then begin
+		Result := True;
+	end else begin
+		Result := False;
+	end;
+end;
diff --git a/contrib/packaging/inno/mercurial.iss b/contrib/packaging/inno/mercurial.iss
--- a/contrib/packaging/inno/mercurial.iss
+++ b/contrib/packaging/inno/mercurial.iss
@@ -53,6 +53,7 @@ 
 AllowNoIcons=true
 DefaultGroupName=Mercurial
 PrivilegesRequired=none
+ChangesEnvironment=true
 
 [Files]
 Source: contrib\mercurial.el; DestDir: {app}/Contrib
@@ -80,7 +81,6 @@ 
 Source: dist\msvc*.dll; DestDir: {app}; Flags: skipifsourcedoesntexist
 Source: dist\Microsoft.VC*.CRT.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist
 Source: dist\lib\library.zip; DestDir: {app}\lib
-Source: dist\add_path.exe; DestDir: {app}
 Source: doc\*.html; DestDir: {app}\Docs
 Source: doc\style.css; DestDir: {app}\Docs
 Source: mercurial\help\*.txt; DestDir: {app}\help
@@ -107,14 +107,22 @@ 
 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
 
-[Run]
-Filename: "{app}\add_path.exe"; Parameters: "{app}"; Flags: postinstall; Description: "Add the installation path to the search path"
-
-[UninstallRun]
-Filename: "{app}\add_path.exe"; Parameters: "/del {app}"
+[Tasks]
+Name: modifypath; Description: Add the installation path to the search path; Flags: unchecked
 
 [Code]
 procedure Touch(fn: String);
 begin
   SaveStringToFile(ExpandConstant(fn), '', False);
 end;
+
+const
+    ModPathName = 'modifypath';
+    ModPathType = 'user';
+
+function ModPathDir(): TArrayOfString;
+begin
+    setArrayLength(Result, 1)
+    Result[0] := ExpandConstant('{app}');
+end;
+#include "modpath.iss"