esp-idf/tools/windows/tool_setup/idf_setup.iss.inc

528 wiersze
18 KiB
PHP

{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Downloading ESP-IDF ------------------------------ }
var
IDFZIPFileVersion, IDFZIPFileName: String;
function GetIDFPath(Unused: String): String;
begin
if IDFUseExisting then
Result := IDFExistingPath
else
Result := IDFDownloadPath;
end;
function GetIDFZIPFileVersion(Version: String): String;
var
ReleaseVerPart: String;
i: Integer;
Found: Boolean;
begin
if WildCardMatch(Version, 'v*') or WildCardMatch(Version, 'v*-rc*') then
Result := Version
else if Version = 'master' then
Result := ''
else if WildCardMatch(Version, 'release/v*') then
begin
ReleaseVerPart := Version;
Log('ReleaseVerPart=' + ReleaseVerPart)
Delete(ReleaseVerPart, 1, Length('release/'));
Log('ReleaseVerPart=' + ReleaseVerPart)
Found := False;
for i := 0 to GetArrayLength(IDFDownloadAvailableVersions) - 1 do
begin
if Pos(ReleaseVerPart, IDFDownloadAvailableVersions[i]) = 1 then
begin
Result := IDFDownloadAvailableVersions[i];
Found := True;
break;
end;
end;
if not Found then
Result := '';
end;
Log('GetIDFZIPFileVersion(' + Version + ')=' + Result);
end;
procedure IDFAddDownload();
var
Url, MirrorUrl: String;
begin
IDFZIPFileVersion := GetIDFZIPFileVersion(IDFDownloadVersion);
Log('IDFZIPFileVersion: ' + IDFZIPFileVersion);
if IDFZIPFileVersion <> '' then
begin
Url := 'https://github.com/espressif/esp-idf/releases/download/' + IDFZIPFileVersion + '/esp-idf-' + IDFZIPFileVersion + '.zip';
MirrorUrl := 'https://dl.espressif.com/github_assets/espressif/esp-idf/releases/download/' + IDFZIPFileVersion + '/esp-idf-' + IDFZIPFileVersion + '.zip';
IDFZIPFileName := ExpandConstant('{app}\releases\esp-idf-' + IDFZIPFileVersion + '.zip');
if not FileExists(IDFZIPFileName) then
begin
Log('IDFZIPFileName: ' + IDFZIPFileName + ' exists');
ForceDirectories(ExpandConstant('{app}\releases'))
Log('Adding download: ' + Url + ', mirror: ' + MirrorUrl + ', destination: ' + IDFZIPFileName);
idpAddFile(Url, IDFZIPFileName);
idpAddMirror(Url, MirrorUrl);
end else begin
Log('IDFZIPFileName: ' + IDFZIPFileName + ' does not exist');
end;
end;
end;
procedure RemoveAlternatesFile(Path: String);
begin
Log('Removing ' + Path);
DeleteFile(Path);
end;
{
Replacement of the '--dissociate' flag of 'git clone', to support older versions of Git.
'--reference' is supported for submodules since git 2.12, but '--dissociate' only from 2.18.
}
procedure GitRepoDissociate(Path: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' repack -d -a'
DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the repository', CmdLine);
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git repack -d -a'
DoCmdlineInstall('Finishing ESP-IDF installation', 'Re-packing the submodules', CmdLine);
FindFileRecursive(Path + '\.git', 'alternates', @RemoveAlternatesFile);
end;
{
Initialize submodules - required to call when switching branches in existing repo.
E.g. created by offline installer
}
procedure GitUpdateSubmodules(Path: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule update --init --recursive';
Log('Updating submodules: ' + CmdLine);
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating submodules', CmdLine);
end;
{
Run git config fileMode is repairing problem when git repo was zipped on Linux and extracted on Windows.
The repo and submodules are marked as dirty which confuses users that fresh installation already contains changes.
More information: https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-config.html
}
procedure GitRepoFixFileMode(Path: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' config --local core.fileMode false';
Log('Setting core.fileMode on repository: ' + CmdLine);
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating fileMode', CmdLine);
Log('Setting core.fileMode on repository for submodules: ' + CmdLine);
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach --recursive git config --local core.fileMode false';
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating fileMode in submodules', CmdLine);
end;
{ Run git reset --hard in the repo and in the submodules, to fix the newlines. }
procedure GitResetHard(Path: String);
var
CmdLine: String;
begin
if (not IsGitResetAllowed) then begin
Log('Git reset disabled by command line option /GITRESET=no.');
Exit;
end;
CmdLine := GitExecutablePath + ' -C ' + Path + ' reset --hard';
Log('Resetting the repository: ' + CmdLine);
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines', CmdLine);
Log('Resetting the submodules: ' + CmdLine);
CmdLine := GitExecutablePath + ' -C ' + Path + ' submodule foreach git reset --hard';
DoCmdlineInstall('Finishing ESP-IDF installation', 'Updating newlines in submodules', CmdLine);
end;
{ Run git clean - clean leftovers after switching between tags }
{ The repo should be created with: git config --local clean.requireForce false}
procedure GitCleanForceDirectory(Path: String);
var
CmdLine: String;
begin
if (not IsGitCleanAllowed) then begin
Log('Git clean disabled by command line option /GITCLEAN=no.');
Exit;
end;
CmdLine := GitExecutablePath + ' -C ' + Path + ' clean --force -d';
Log('Resetting the repository: ' + CmdLine);
DoCmdlineInstall('Finishing ESP-IDF installation', 'Cleaning untracked directories', CmdLine);
end;
{
Switch to different branch. Used in offline installation.
}
procedure GitSwitchBranch(Path: String; BranchName: String);
var
CmdLine: String;
begin
CmdLine := GitExecutablePath + ' -C ' + Path + ' checkout ' + BranchName;
Log('Updating submodules: ' + CmdLine);
DoCmdlineInstall('Switching branch', 'Switching to branch', CmdLine);
GitUpdateSubmodules(Path);
GitResetHard(Path);
GitCleanForceDirectory(Path);
end;
{
There are 3 possible ways how an ESP-IDF copy can be obtained:
- Download the .zip archive with submodules included, extract to destination directory,
then do 'git reset --hard' and 'git submodule foreach git reset --hard' to correct for
possibly different newlines. This is done for release versions.
- Do a git clone of the Github repository into the destination directory.
This is done for the master branch.
- Download the .zip archive of a "close enough" release version, extract into a temporary
directory. Then do a git clone of the Github repository, using the temporary directory
as a '--reference'. This is done for other versions (such as release branches).
}
procedure IDFOfflineInstall();
var
IDFTempPath: String;
IDFPath: String;
begin
IDFPath := IDFDownloadPath;
IDFTempPath := ExpandConstant('{app}\releases\esp-idf-bundle');
Log('IDFTempPath - location of bundle: ' + IDFTempPath);
GitSwitchBranch(IDFPath, IDFDownloadVersion);
end;
procedure IDFDownloadInstall();
var
CmdLine: String;
IDFTempPath: String;
IDFPath: String;
NeedToClone: Boolean;
begin
IDFPath := IDFDownloadPath;
{ If there is a release archive to download, IDFZIPFileName and IDFZIPFileVersion will be set.
See GetIDFZIPFileVersion function.
}
if IDFZIPFileName <> '' then
begin
if IDFZIPFileVersion <> IDFDownloadVersion then
begin
{ The version of .zip file downloaded is not the same as the version the user has requested.
Will use 'git clone --reference' to obtain the correct version, using the contents
of the .zip file as reference.
}
NeedToClone := True;
end;
CmdLine := ExpandConstant('{tmp}\7za.exe x -o' + ExpandConstant('{tmp}') + ' -r -aoa "' + IDFZIPFileName + '"');
IDFTempPath := ExpandConstant('{tmp}\esp-idf-') + IDFZIPFileVersion;
Log('Extracting ESP-IDF reference repository: ' + CmdLine);
Log('Reference repository path: ' + IDFTempPath);
DoCmdlineInstall('Extracting ESP-IDF', 'Setting up reference repository', CmdLine);
end else begin
{ IDFZIPFileName is not set, meaning that we will rely on 'git clone'. }
NeedToClone := True;
Log('Not .zip release archive. Will do full clone.');
end;
if NeedToClone then
begin
CmdLine := GitExecutablePath + ' clone --progress -b ' + IDFDownloadVersion;
if (IsGitRecursive) then begin
CmdLine := CmdLine + ' --recursive ';
end;
if IDFTempPath <> '' then
CmdLine := CmdLine + ' --reference ' + IDFTempPath;
CmdLine := CmdLine + ' ' + GitRepository +' ' + IDFPath;
Log('Cloning IDF: ' + CmdLine);
DoCmdlineInstall('Downloading ESP-IDF', 'Using git to clone ESP-IDF repository', CmdLine);
if IDFTempPath <> '' then
GitRepoDissociate(IDFPath);
end else begin
Log('Copying ' + IDFTempPath + ' to ' + IDFPath);
if DirExists(IDFPath) then
begin
if not DirIsEmpty(IDFPath) then
begin
MsgBox('Destination directory exists and is not empty: ' + IDFPath, mbError, MB_OK);
RaiseException('Failed to copy ESP-IDF')
end;
end;
{ If cmd.exe command argument starts with a quote, the first and last quote chars in the command
will be removed by cmd.exe.
Keys explanation: /s+/e includes all subdirectories, /i assumes that destination is a directory,
/h copies hidden files, /q disables file name logging (making copying faster!)
}
CmdLine := ExpandConstant('cmd.exe /c ""xcopy" /s /e /i /h /q "' + IDFTempPath + '" "' + IDFPath + '""');
DoCmdlineInstall('Extracting ESP-IDF', 'Copying ESP-IDF into the destination directory', CmdLine);
GitRepoFixFileMode(IDFPath);
GitResetHard(IDFPath);
DelTree(IDFTempPath, True, True, True);
end;
end;
{ ------------------------------ IDF Tools setup, Python environment setup ------------------------------ }
function UseBundledIDFToolsPy(Version: String) : Boolean;
begin
Result := False;
{ Use bundled copy of idf_tools.py, as the copy shipped with these IDF versions can not work due to
the --no-site-packages bug.
}
if (Version = 'v4.0') or (Version = 'v3.3.1') then
begin
Log('UseBundledIDFToolsPy: version=' + Version + ', using bundled idf_tools.py');
Result := True;
end;
end;
{ Find Major and Minor version in esp_idf_version.h file. }
function GetIDFVersionFromHeaderFile():String;
var
HeaderFileName: String;
HeaderLines: TArrayOfString;
LineIndex: Integer;
LineCount: Longint;
Line: String;
MajorVersion: String;
MinorVersion: String;
begin
HeaderFileName := GetIDFPath('') + '\components\esp_common\include\esp_idf_version.h';
if (not FileExists(HeaderFileName)) then begin
Result := '';
Exit;
end;
LoadStringsFromFile(HeaderFileName, HeaderLines);
LineCount := GetArrayLength(HeaderLines);
for LineIndex := 0 to LineCount - 1 do begin
Line := HeaderLines[LineIndex];
if (pos('define ESP_IDF_VERSION_MAJOR', Line) > 0) then begin
Delete(Line, 1, 29);
MajorVersion := Trim(Line);
end else if (pos('define ESP_IDF_VERSION_MINOR', Line) > 0) then begin
Delete(Line, 1, 29);
MinorVersion := Trim(Line);
Result := MajorVersion + '.' + MinorVersion;
Exit;
end
end;
end;
{ Get short version from long version e.g. 3.7.9 -> 3.7 }
function GetShortVersion(VersionString:String):String;
var
VersionIndex: Integer;
MajorString: String;
MinorString: String;
DotIndex: Integer;
begin
{ Transform version vx.y or release/vx.y to x.y }
VersionIndex := pos('v', VersionString);
if (VersionIndex > 0) then begin
Delete(VersionString, 1, VersionIndex);
end;
{ Transform version x.y.z to x.y }
DotIndex := pos('.', VersionString);
if (DotIndex > 0) then begin
MajorString := Copy(VersionString, 1, DotIndex - 1);
Delete(VersionString, 1, DotIndex);
{ Trim trailing version numbers. }
DotIndex := pos('.', VersionString);
if (DotIndex > 0) then begin
MinorString := Copy(VersionString, 1, DotIndex - 1);
VersionString := MajorString + '.' + MinorString;
end else begin
VersionString := MajorString + '.' + VersionString;
end;
end;
Result := VersionString;
end;
{ Get IDF version string in combination with Python version. }
{ Result e.g.: idf4.1_py38 }
function GetIDFPythonEnvironmentVersion():String;
var
IDFVersionString: String;
begin
{ Transform main or master to x.y }
if (Pos('main', IDFDownloadVersion) > 0) or (Pos('master', IDFDownloadVersion) > 0) then begin
IDFVersionString := GetIDFVersionFromHeaderFile();
end else begin
IDFVersionString := GetShortVersion(IDFDownloadVersion);
end;
Result := 'idf' + IDFVersionString + '_py' + GetShortVersion(PythonVersion);
end;
function GetPythonVirtualEnvPath(): String;
var
PythonVirtualEnvPath: String;
begin
{ The links should contain reference to Python vitual env }
PythonVirtualEnvPath := ExpandConstant('{app}\python_env\') + GetIDFPythonEnvironmentVersion() + '_env\Scripts';
Log('Path to Python in virtual env: ' + PythonVirtualEnvPath);
{ Fallback in case of not existing environment. }
if (not FileExists(PythonVirtualEnvPath + '\python.exe')) then begin
PythonVirtualEnvPath := PythonPath;
Log('python.exe not found, reverting to:' + PythonPath);
end;
Result := PythonVirtualEnvPath;
end;
procedure IDFToolsSetup();
var
CmdLine: String;
IDFPath: String;
IDFToolsPyPath: String;
IDFToolsPyCmd: String;
BundledIDFToolsPyPath: String;
JSONArg: String;
PythonVirtualEnvPath: String;
begin
IDFPath := GetIDFPath('');
IDFToolsPyPath := IDFPath + '\tools\idf_tools.py';
BundledIDFToolsPyPath := ExpandConstant('{app}\idf_tools_fallback.py');
JSONArg := '';
if FileExists(IDFToolsPyPath) then
begin
Log('idf_tools.py exists in IDF directory');
if UseBundledIDFToolsPy(IDFDownloadVersion) then
begin
Log('Using the bundled idf_tools.py copy');
IDFToolsPyCmd := BundledIDFToolsPyPath;
end else begin
IDFToolsPyCmd := IDFToolsPyPath;
end;
end else begin
Log('idf_tools.py does not exist in IDF directory, using a fallback version');
IDFToolsPyCmd := BundledIDFToolsPyPath;
JSONArg := ExpandConstant('--tools "{app}\tools_fallback.json"');
end;
{ IDFPath not quoted, as it can not contain spaces }
IDFToolsPyCmd := PythonExecutablePath + ' "' + IDFToolsPyCmd + '" --idf-path ' + IDFPath + JSONArg;
SetEnvironmentVariable('PYTHONUNBUFFERED', '1');
if (IsOfflineMode) then begin
SetEnvironmentVariable('PIP_NO_INDEX', 'true');
Log('Offline installation selected. Setting environment variable PIP_NO_INDEX=1');
SetEnvironmentVariable('PIP_FIND_LINKS', ExpandConstant('{app}\tools\idf-python-wheels\' + PythonWheelsVersion));
end else begin
SetEnvironmentVariable('PIP_EXTRA_INDEX_URL', PythonWheelsUrl);
Log('Adding extra Python wheels location. Setting environment variable PIP_EXTRA_INDEX_URL=' + PythonWheelsUrl);
end;
Log('idf_tools.py command: ' + IDFToolsPyCmd);
CmdLine := IDFToolsPyCmd + ' install';
Log('Installing tools:' + CmdLine);
DoCmdlineInstall('Installing ESP-IDF tools', '', CmdLine);
CmdLine := PythonExecutablePath + ' -m virtualenv --version';
Log('Checking Python virtualenv support:' + CmdLine)
DoCmdlineInstall('Checking Python virtualenv support', '', CmdLine);
PythonVirtualEnvPath := ExpandConstant('{app}\python_env\') + GetIDFPythonEnvironmentVersion() + '_env';
CmdLine := PythonExecutablePath + ' -m virtualenv "' + PythonVirtualEnvPath + '" -p ' + '"' + PythonExecutablePath + '"';
if (DirExists(PythonVirtualEnvPath)) then begin
Log('ESP-IDF Python Virtual environment exists, refreshing the environment: ' + CmdLine);
end else begin
Log('ESP-IDF Python Virtual environment does not exist, creating the environment: ' + CmdLine);
end;
DoCmdlineInstall('Creating Python environment', '', CmdLine);
CmdLine := IDFToolsPyCmd + ' install-python-env';
Log('Installing Python environment:' + CmdLine);
DoCmdlineInstall('Installing Python environment', '', CmdLine);
end;
{ ------------------------------ Start menu shortcut ------------------------------ }
procedure CreateIDFCommandPromptShortcut(LnkString: String);
var
Destination: String;
Description: String;
Command: String;
begin
ForceDirectories(ExpandConstant(LnkString));
Destination := ExpandConstant(LnkString + '\{#IDFCmdExeShortcutFile}');
Description := '{#IDFCmdExeShortcutDescription}';
{ If cmd.exe command argument starts with a quote, the first and last quote chars in the command
will be removed by cmd.exe; each argument needs to be surrounded by quotes as well. }
Command := ExpandConstant('/k ""{app}\idf_cmd_init.bat" "') + GetPythonVirtualEnvPath() + '" "' + GitPath + '""';
Log('CreateShellLink Destination=' + Destination + ' Description=' + Description + ' Command=' + Command)
try
CreateShellLink(
Destination,
Description,
'cmd.exe',
Command,
GetIDFPath(''),
'', 0, SW_SHOWNORMAL);
except
MsgBox('Failed to create the shortcut: ' + Destination, mbError, MB_OK);
RaiseException('Failed to create the shortcut');
end;
end;
procedure CreateIDFPowershellShortcut(LnkString: String);
var
Destination: String;
Description: String;
Command: String;
GitPathWithForwardSlashes: String;
PythonPathWithForwardSlashes: String;
begin
ForceDirectories(ExpandConstant(LnkString));
Destination := ExpandConstant(LnkString + '\{#IDFPsShortcutFile}');
Description := '{#IDFPsShortcutDescription}';
GitPathWithForwardSlashes := GitPath;
PythonPathWithForwardSlashes := GetPythonVirtualEnvPath();
StringChangeEx(GitPathWithForwardSlashes, '\', '/', True);
StringChangeEx(PythonPathWithForwardSlashes, '\', '/', True);
Command := ExpandConstant('-ExecutionPolicy Bypass -NoExit -File ""{app}\idf_cmd_init.ps1"" ') + '"' + GitPathWithForwardSlashes + '" "' + PythonPathWithForwardSlashes + '"'
Log('CreateShellLink Destination=' + Destination + ' Description=' + Description + ' Command=' + Command)
try
CreateShellLink(
Destination,
Description,
'powershell.exe',
Command,
GetIDFPath(''),
'', 0, SW_SHOWNORMAL);
except
MsgBox('Failed to create the shortcut: ' + Destination, mbError, MB_OK);
RaiseException('Failed to create the shortcut');
end;
end;