tools: support for embedded python

This commit is contained in:
Juraj Michálek 2020-12-16 17:40:13 +01:00
parent c535d569aa
commit 1427b3a6d8
29 changed files with 556 additions and 161 deletions

View File

@ -62,4 +62,14 @@ On Linux and macOS, it is recommended to install ninja using the OS-specific pac
.. tool-dfu-util-notes
---
.. tool-idf-python-notes
---
.. tool-idf-python-wheels-notes
---

View File

@ -0,0 +1,49 @@
IDF Windows Installer
=====================
Command-line parameters
-----------------------
Windows Installer `esp-idf-tools-setup` provides the following command-line parameters:
* ``/GITRECURSIVE=[yes|no]`` - Clone recursively all git repository submodules. Default: yes``
* ``/GITREPO=[URL|PATH]`` - URL of repository to clone ESP-IDF. Default: https://github.com/espressif/esp-idf.git
* ``/GITRESET=[yes|no]`` - Enable/Disable git reset of repository during installation. Default: yes.
* ``/HELP`` - Display command line options provided by Inno Setup installer.
* ``/IDFDIR=[PATH]`` - Path to directory where it will be installed. Default: ``{userdesktop}\esp-idf}``
* ``/IDFVERSION=[v4.3|v4.1|master]`` - Use specific IDF version. E.g. v4.1, v4.2, master. Default: empty, pick the first version in the list.
* ``/IDFVERSIONSURL=[URL]`` - Use URL to download list of IDF versions. Default: https://dl.espressif.com/dl/esp-idf/idf_versions.txt
* ``/LOG=[PATH]`` - Store installation log file in specific directory. Default: empty.
* ``/OFFLINE=[yes|no]`` - Execute installation of Python packages by PIP in offline mode. The same result can be achieved by setting the environment variable PIP_NO_INDEX. Default: no.
* ``/USEEMBEDDEDPYTHON=[yes|no]`` - Use Embedded Python version for the installation. Set to ``no`` to allow Python selection screen in the installer. Default: yes.
* ``/PYTHONWHEELSURL=[URL]`` - Specify URLs to PyPi repositories for resolving binary Python Wheel dependencies. The same result can be achieved by setting the environment variable PIP_EXTRA_INDEX_URL. Default: https://dl.espressif.com/pypi
* ``/SKIPSYSTEMCHECK=[yes|no]`` - Skip System Check page. Default: no.
* ``/VERYSILENT /SUPPRESSMSGBOXES /SP- /NOCANCEL`` - Perform silent installation.
Unattended installation
-----------------------
The unattended installation of IDF can be achieved by following command-line parameters:
.. code-block:: batch
esp-idf-tools-setup-x.x.exe /VERYSILENT /SUPPRESSMSGBOXES /SP- /NOCANCEL
The installer detaches its process from the command-line. Waiting for installation to finish could be achieved by following PowerShell script:
.. code-block:: powershell
esp-idf-tools-setup-x.x.exe /VERYSILENT /SUPPRESSMSGBOXES /SP- /NOCANCEL
$InstallerProcess = Get-Process esp-idf-tools-setup
Wait-Process -Id $InstallerProcess.id
Custom Python and custom location of Python wheels
--------------------------------------------------
The IDF installer is using by default embedded Python with reference to Python Wheel mirror.
Following parameters allows to select custom Python and custom location of Python wheels:
.. code-block:: batch
esp-idf-tools-setup-x.x.exe /USEEMBEDDEDPYTHON=no /PYTHONWHEELSURL=https://pypi.org/simple/

View File

@ -7,3 +7,4 @@ Tools
IDF Tools <idf-tools>
IDF Monitor <idf-monitor>
IDF Docker image <idf-docker-image>
IDF Windows Installer <idf-windows-installer>

View File

@ -34,7 +34,7 @@ ESP-IDF Tools Installer
The easiest way to install ESP-IDF's prerequisites is to download the ESP-IDF Tools installer from this URL:
https://dl.espressif.com/dl/esp-idf-tools-setup-2.3.exe
https://dl.espressif.com/dl/esp-idf-tools-setup-2.4.exe
.. IMPORTANT: Next time this link is updated, please go to get-started/index.rst and rewrite the section under "Alternative File Downloads ... Windows". Then delete this comment.

View File

@ -64,4 +64,14 @@ On Linux and macOS, it is recommended to install ninja using the OS package mana
.. tool-dfu-util-notes
---
.. tool-idf-python-notes
---
.. tool-idf-python-wheels-notes
---

View File

@ -0,0 +1 @@
.. include:: ../../../en/api-guides/tools/idf-windows-installer.rst

View File

@ -7,3 +7,4 @@
IDF Tools <idf-tools>
IDF 监视器 <idf-monitor>
IDF Docker image <idf-docker-image>
IDF Windows Installer <idf-windows-installer>

View File

@ -33,7 +33,7 @@ ESP-IDF 工具安装器
安装 ESP-IDF 必备工具最简易的方式是下载 ESP-IDF 工具安装器,地址如下:
https://dl.espressif.com/dl/esp-idf-tools-setup-2.3.exe
https://dl.espressif.com/dl/esp-idf-tools-setup-2.4.exe
.. 重要:下次更新此链接时,请重新写文件 get-started/index.rst 中“其它文件下载方式”这一章节,然后将此条注意事项删除。

View File

@ -1310,6 +1310,19 @@ def action_install(args):
tool_obj.install(tool_version)
def get_wheels_dir():
tools_info = load_tools_info()
wheels_package_name = 'idf-python-wheels'
if wheels_package_name not in tools_info:
return None
wheels_package = tools_info[wheels_package_name]
recommended_version = wheels_package.get_recommended_version()
wheels_dir = wheels_package.get_path_for_version(recommended_version)
if not os.path.exists(wheels_dir):
return None
return wheels_dir
def action_install_python_env(args):
idf_python_env_path, _, virtualenv_python = get_python_env_path()
@ -1339,6 +1352,15 @@ def action_install_python_env(args):
run_args += ['-r', requirements_txt]
if args.extra_wheels_dir:
run_args += ['--find-links', args.extra_wheels_dir]
if args.no_index:
run_args += ['--no-index']
if args.extra_wheels_url:
run_args += ['--extra-index-url', args.extra_wheels_url]
wheels_dir = get_wheels_dir()
if wheels_dir is not None:
run_args += ['--find-links', wheels_dir]
info('Installing Python packages from {}'.format(requirements_txt))
subprocess.check_call(run_args, stdout=sys.stdout, stderr=sys.stderr)
@ -1542,6 +1564,8 @@ def main(argv):
action='store_true')
install_python_env.add_argument('--extra-wheels-dir', help='Additional directories with wheels ' +
'to use during installation')
install_python_env.add_argument('--extra-wheels-url', help='Additional URL with wheels', default='https://dl.espressif.com/pypi')
install_python_env.add_argument('--no-index', help='Work offline without retrieving wheels index')
if IDF_MAINTAINER:
add_version = subparsers.add_parser('add-version', help='Add or update download info for a version')

View File

@ -627,6 +627,73 @@
}
}
]
},
{
"description": "Embeddable Python distribution",
"export_paths": [],
"export_vars": {},
"info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/",
"install": "never",
"license": "PSF License",
"name": "idf-python",
"platform_overrides": [
{
"install": "on_request",
"platforms": [
"win64"
]
}
],
"version_cmd": [
"python",
"--version"
],
"version_regex": "Python ([0-9.]+)",
"versions": [
{
"name": "3.9.1",
"status": "recommended",
"win64": {
"sha256": "d5a0e625dd5b2bc6872de90292d71009c17e2396e3d1575d886a94d0dfb00c87",
"size": 20362758,
"url": "https://dl.espressif.com/dl/idf-python/idf-python-3.9.1-embed-win64.zip"
}
}
]
},
{
"description": "Python Wheels distribution bundled for the specific version of IDF and Python",
"export_paths": [],
"export_vars": {},
"info_url": "https://github.com/espressif/esp-idf/tree/master/tools/windows/",
"install": "never",
"license": "Open-source licenses",
"name": "idf-python-wheels",
"platform_overrides": [
{
"install": "always",
"platforms": [
"win64"
]
}
],
"version_cmd": [
"cmd",
"/c",
"echo idf4.3_py3.9_2021-01-07"
],
"version_regex": "(idf4.3_py3.9_2021-01-07)",
"versions": [
{
"name": "idf4.3_py3.9_2021-01-07",
"status": "recommended",
"win64": {
"sha256": "2a33dbaa106aec9c5098b1af46f04c69923be947291c19855ff355b9707314b6",
"size": 8316997,
"url": "https://dl.espressif.com/dl/idf-python-wheels/idf-python-wheels-idf4.3_py3.9_2021-01-07-win64.zip"
}
}
]
}
],
"version": 1

View File

@ -12,9 +12,9 @@ Some functionality of the installer depends on additional programs:
* [7-zip](https://www.7-zip.org) — used to extract downloaded IDF archives.
* [cmdlinerunner](cmdlinerunner/cmdlinerunner.c) — a helper DLL used to run external command line programs from the installer, capture live console output, and get the exit code.
* [cmdlinerunner](cmdlinerunner/cmdlinerunner.c) — a helper DLL used to run external command-line programs from the installer, capture live console output, and get the exit code.
## Instalation of dependencies via Chocolatey
## Installation of dependencies via Chocolatey
Run with Administrator privileges:
@ -22,7 +22,7 @@ Run with Administrator privileges:
choco install inno-download-plugin
```
## Building the installer
## Building the installer
### In Docker
@ -60,3 +60,47 @@ docker run --rm -v $IDF_PATH:/idf -w /idf/tools/windows/tool_setup -it $CI_DOCKE
- `export CERTCHAIN=certchain.pem`
* Run `sign_installer.sh` script. This will ask for the `key.pem` password, and produce the signed installer in the Output directory. If you plan to run the script multiple times, you may also set `KEYPASSWORD` environment variable to the `key.pem` password, to avoid the prompt.
## Development and testing of the installer
Development and testing of the installer can be simplified by using command line parameters which can be passed to the installer.
Select Run - Parameters in Inno Setup and add parameters.
Example of parameters:
```
/SKIPSYSTEMCHECK=yes /IDFVERSIONSURL=http://localhost:8000/idf_versions.txt /GITRESET=no /GITREPO=C:/projects/esp-idf /GITRECURSIVE=no
```
These combinations of parameters will result:
* ``SKIPSYSTEMCHECK=yes`` - The screen with System Check will be skipped.
* ``IDFVERSIONURL`` - idf_versions.txt will be downloaded from localhost:8000
- it's possible to add branch name into idf_versions.txt, e.g. feature/win_inst
* ``GITRESET=no`` - Git repository won't be reset after clone, it can save time and add custom changes in case of the zip archive with repository
* ``GITREPO`` - The version will be cloned from the specific location, e.g. from a local directory
* ``GITRECURSIVE=no`` - The clone of the repo won't contain modules, it speeds up the cloning process. Use when modules are not necessary.
Documentation of parameters is available in api-guides/tools/idf-windows-installer.rst
### Testing installation in Docker with Windows containers
The testing script is stored in docker-compose.yml. The test perform full silent installation and executes build of get-started example.
Commands for testing multiple versions:
```
$env:IDF_VERSION="v4.1"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="v4.0.2"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="v3.3.4"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="release/v4.2"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="release/v4.1"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="release/v4.0"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="release/v3.3"; docker-compose.exe run idf-setup-test
$env:IDF_VERSION="master"; docker-compose.exe run idf-setup-test
```
The installation log is not displayed immediately on the screen. It's stored in the file and it's displayed when the installation finishes. The glitch of Inno Setup is that in case of failed installation it won't terminate and it keeps hanging.
Recommendation: Use Visual Studio Code with Docker plugin to work with container.
The log file is then accessible under Docker - Containers - Container - Files - Temp - install.txt - right click - Open.

View File

@ -0,0 +1,15 @@
param (
[string]$Installer="C:\Output\esp-idf-tools-setup-unsigned.exe",
[string]$IdfPath = "C:\Users\ContainerAdministrator\Desktop\esp-idf",
[string]$IdfVersion = "v4.1"
)
$Installer
$IdfPath
$IdfVersion
mkdir C:\Temp
C:\Output\esp-idf-tools-setup-unsigned.exe /VERYSILENT /LOG=C:\Temp\install.txt /SUPPRESSMSGBOXES /SP- /NOCANCEL /NORESTART /IDFVERSION=${IdfVersion}
$InstallerProcess = Get-Process esp-idf-tools-setup-unsigned
Wait-Process -Id $InstallerProcess.id
Get-Content C:\Temp\install.txt

View File

@ -0,0 +1,8 @@
param (
[string]$IdfVersion = "v4.1"
)
$ErrorActionPreference = "Stop"
New-Item -Path C:\Users\ContainerAdministrator\ -Name .espressif -ItemType "directory"
New-Item -Path C:\Users\ContainerAdministrator\.espressif -Name releases -ItemType "directory"
Copy-Item -Recurse -Verbose -Path C:\Cache\dist -Destination C:\Users\ContainerAdministrator\.espressif\dist
Copy-Item -Verbose -Path C:\Cache\releases\esp-idf-${IdfVersion}.zip -Destination C:\Users\ContainerAdministrator\.espressif\releases

View File

@ -0,0 +1,28 @@
param (
[string]$PythonPath = "C:\Python38\",
[string]$IdfPath = "C:\Users\ContainerAdministrator\Desktop\esp-idf"
)
$env:PATH+=";${PythonPath}"
Set-Location "${IdfPath}"
#.\export.ps1
$env:PYTHONPATH="C:\Users\ContainerAdministrator\Desktop\esp-idf\tools\"
# Append build script and launch via link
#Add-Content -Path ${IdfPath}\export.bat -Value ${BuildCommands}
# timeout is necessary to fix the problem when installer is writing some final files
# it seems that installer exits, but locks were not released yet
Start-Sleep -s 5
$WSShell = New-Object -comObject WScript.Shell
$Shortcut = $WSShell.CreateShortcut('C:\Users\ContainerAdministrator\Desktop\ESP-IDF Command Prompt (cmd.exe).lnk')
$Arguments = $Shortcut.Arguments -replace "/k ", "/c '"
$Command = $Shortcut.TargetPath + ' ' + $Arguments -replace '""', '"'
$Command += " && cd examples\get-started\blink\ && idf.py build'"
Invoke-Expression -Command $Command
#powershell.exe
#C:\Windows\system32\cmd.exe /c '"C:\Users\ContainerAdministrator\.espressif\idf_cmd_init.bat" "C:\Users\ContainerAdministrator\.espressif\python_env\idf4.1_py3.7_env\Scripts" "C:\Program Files\Git\cmd\" && cd examples\get-started\blink\ && idf.py build'
#cmd /c "ping -n 4 127.0.0.1 && .\export.bat && cd examples\get-started\blink\ && idf.py build"
#cmd /c "ping -n 4 127.0.0.1 && .\export.bat && cd examples\get-started\blink\ && idf.py build"
#cmd /c "timeout 4 && C:\Users\ContainerAdministrator\.espressif\idf_cmd_init.bat 'C:\' && cd examples\get-started\blink\ && idf.py build"
#& "C:\Users\ContainerAdministrator\Desktop\esp-idf\Run ESP-IDF Command Prompt (cmd.exe).lnk"

View File

@ -10,6 +10,19 @@
set -e
set -u
INSTALLER_TYPE="$1"
if [[ -z "$INSTALLER_TYPE" ]]; then
INSTALLER_TYPE="full"
fi
echo "Selected installer type: $INSTALLER_TYPE"
echo "Available installer types: full, netinst"
PACKAGES="all"
if [[ "$INSTALLER_TYPE" == "netinst" ]]; then
PACKAGES="idf-python"
fi
iscc_path=$(which iscc)
if [[ -z "$iscc_path" ]]; then
echo "Inno setup compiler (iscc) not found. Are you running wine-innosetup Docker image?"
@ -24,7 +37,7 @@ fi
echo "Downloading IDF Tools..."
mkdir -p idf_tools_tmp
export IDF_TOOLS_PATH=$PWD/idf_tools_tmp
$IDF_PATH/tools/idf_tools.py --non-interactive download --platform Windows-x86_64 all
$IDF_PATH/tools/idf_tools.py --non-interactive download --platform Windows-x86_64 $PACKAGES
$IDF_PATH/tools/idf_tools.py --tools-json tools_fallback.json --non-interactive download --platform Windows-x86_64 all
mkdir -p dist
cp idf_tools_tmp/dist/* dist/
@ -40,4 +53,5 @@ echo "Downloading idf_versions.txt..."
wget --no-verbose -O idf_versions.txt https://dl.espressif.com/dl/esp-idf/idf_versions.txt
echo "Running ISCC..."
iscc idf_tool_setup.iss
# https://jrsoftware.org/ishelp/index.php?topic=compilercmdline
iscc /F "esp-idf-tools-setup-$INSTALLER_TYPE-unsigned" idf_tool_setup.iss

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
var

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Progress & log page for command line tools ------------------------------ }

View File

@ -0,0 +1,24 @@
version: "3"
# This docker-compose is for testing the installation process.
# In starts the installation and executes also build of get-started example.
services:
idf-setup-test:
image: mcr.microsoft.com/windows/servercore:1809
command: powershell -c "C:/Scripts/Prepare-Cache.ps1 -IdfVersion ${IDF_VERSION}; C:/Scripts/Install-Idf.ps1 -Installer 'c:/Output/esp-idf-tools-setup-unsigned.exe' -IdfVersion ${IDF_VERSION}; C:/Scripts/Test-Idf.ps1; powershell ;exit $$LASTEXITCODE"
tmpfs:
- C:\Users\ContainerAdministrator\.espressif
volumes:
- type: bind
source: C:\projects\esp-idf\tools\windows\tool_setup\Output
target: C:\Output
read_only: true
- type: bind
source: C:\projects\esp-idf\tools\windows\tool_setup\Scripts
target: C:\Scripts
read_only: true
# releases volume to speed up installation and avoid downloading of files
- type: bind
source: C:\projects\esp-tests\installer-docker-runner\.espressif\
target: C:\Cache
read_only: true

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Find installed copies of Git ------------------------------ }

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select Git ------------------------------ }

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select the version of ESP-IDF to download ------------------------------ }
@ -46,7 +46,7 @@ var
Url: String;
VersionFile: String;
begin
Url := '{#IDFVersionsURL}';
Url := ExpandConstant('{param:IDFVERSIONSURL|https://dl.espressif.com/dl/esp-idf/idf_versions.txt}')
VersionFile := ExpandConstant('{tmp}\idf_versions.txt');
if idpDownloadFile(Url, VersionFile) then
begin
@ -62,6 +62,7 @@ var
Page: TInputOptionWizardPage;
VersionFile: String;
i: Integer;
SuggestedIDFDirectory: String;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnIDFDownloadPagePrepare');
@ -86,7 +87,26 @@ begin
end;
Page.SelectedValueIndex := 0;
ChoicePageSetInputText(Page, GetSuggestedIDFDirectory());
SuggestedIDFDirectory := ExpandConstant('{param:IDFDIR|' + GetSuggestedIDFDirectory() + '}');
ChoicePageSetInputText(Page, SuggestedIDFDirectory);
end;
{ Validation of PATH for IDF releases which does not support special characters. }
{ Source: https://stackoverflow.com/questions/21623515/is-it-possible-to-filter-require-installation-path-to-be-ascii-in-innosetup }
function IsCharValid(Value: Char): Boolean;
begin
Result := Ord(Value) <= $007F;
end;
function IsDirNameValid(const Value: string): Boolean;
var
I: Integer;
begin
Result := False;
for I := 1 to Length(Value) do
if not IsCharValid(Value[I]) then
Exit;
Result := True;
end;
procedure OnIDFDownloadSelectionChange(Sender: TObject);
@ -122,7 +142,24 @@ begin
end;
IDFDownloadPath := IDFPath;
IDFDownloadVersion := IDFDownloadAvailableVersions[Page.SelectedValueIndex];
{ Use parameter /IDFVE=x to override selection in the box. }
IDFDownloadVersion := ExpandConstant('{param:IDFVERSION|}');
if (IDFDownloadVersion = '') then begin
IDFDownloadVersion := IDFDownloadAvailableVersions[Page.SelectedValueIndex];
end;
{ Following ZIP versions of IDF does not support installation on path with special characters. }
{ Issue: https://github.com/espressif/esp-idf/issues/5996 }
if ((IDFDownloadVersion = 'v4.1') or (IDFDownloadVersion = 'v4.0.2') or
(IDFDownloadVersion = 'v3.3.4')) then begin
if (not IsDirNameValid(IDFPath)) then begin
MsgBox('The installation of selected version of IDF is not supported on path with special characters.' + #13#10
'Please choose a different directory.', mbError, MB_OK);
exit;
end;
end;
Result := True;
end;

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select whether to download ESP-IDF, or use an existing copy ------------------------------ }

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Downloading ESP-IDF ------------------------------ }
@ -140,7 +140,9 @@ var
IDFTempPath: String;
IDFPath: String;
NeedToClone: Boolean;
GitRepoParam: String;
GitResetParam: String;
GitRecursiveParam: String;
begin
IDFPath := IDFDownloadPath;
{ If there is a release archive to download, IDFZIPFileName and IDFZIPFileVersion will be set.
@ -158,7 +160,6 @@ begin
NeedToClone := True;
end;
ExtractTemporaryFile('7za.exe')
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);
@ -172,12 +173,19 @@ begin
if NeedToClone then
begin
CmdLine := GitExecutablePath + ' clone --recursive --progress -b ' + IDFDownloadVersion;
CmdLine := GitExecutablePath + ' clone --progress -b ' + IDFDownloadVersion;
GitRecursiveParam := ExpandConstant('{param:GITRECURSIVE|yes}');
if (GitRecursiveParam = 'yes') then begin
CmdLine := CmdLine + ' --recursive ';
end;
if IDFTempPath <> '' then
CmdLine := CmdLine + ' --reference ' + IDFTempPath;
CmdLine := CmdLine + ' https://github.com/espressif/esp-idf.git ' + IDFPath;
GitRepoParam := ExpandConstant('{param:GITREPO|https://github.com/espressif/esp-idf.git}');
CmdLine := CmdLine + ' ' + GitRepoParam +' ' + IDFPath;
Log('Cloning IDF: ' + CmdLine);
DoCmdlineInstall('Downloading ESP-IDF', 'Using git to clone ESP-IDF repository', CmdLine);
@ -202,7 +210,14 @@ begin
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);
GitRepoFixNewlines(IDFPath);
GitResetParam := ExpandConstant('{param:GITRESET|yes}');
if (GitResetParam = 'yes') then begin
GitRepoFixNewlines(IDFPath);
end else begin
Log('Git reset disabled by command line option /GITRESET=yes.');
end;
DelTree(IDFTempPath, True, True, True);
end;
end;
@ -222,51 +237,6 @@ begin
end;
end;
procedure IDFToolsSetup();
var
CmdLine: String;
IDFPath: String;
IDFToolsPyPath: String;
IDFToolsPyCmd: String;
BundledIDFToolsPyPath: String;
JSONArg: 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')
Log('idf_tools.py command: ' + IDFToolsPyCmd);
CmdLine := IDFToolsPyCmd + ' install';
Log('Installing tools:' + CmdLine);
DoCmdlineInstall('Installing ESP-IDF tools', '', CmdLine);
CmdLine := IDFToolsPyCmd + ' install-python-env';
Log('Installing Python environment:' + CmdLine);
DoCmdlineInstall('Installing Python environment', '', CmdLine);
end;
{ Find Major and Minor version in esp_idf_version.h file. }
function GetIDFVersionFromHeaderFile():String;
var
@ -300,17 +270,119 @@ begin
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;
procedure IDFToolsSetup();
var
CmdLine: String;
IDFPath: String;
IDFToolsPyPath: String;
IDFToolsPyCmd: String;
BundledIDFToolsPyPath: String;
JSONArg: String;
OfflineParameter: String;
PythonWheelsUrlParameter: 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');
OfflineParameter := ExpandConstant('{param:OFFLINE|no}');
if (OfflineParameter = 'yes') then begin
SetEnvironmentVariable('PIP_NO_INDEX', 'true');
Log('Offline installation selected. Setting environment variable PIP_NO_INDEX=1');
end else begin
PythonWheelsUrlParameter := ExpandConstant('{param:PYTHONWHEELSURL|https://dl.espressif.com/pypi}');
SetEnvironmentVariable('PIP_EXTRA_INDEX_URL', PythonWheelsUrlParameter);
Log('Adding extra Python wheels location. Setting environment variable PIP_EXTRA_INDEX_URL=' + PythonWheelsUrlParameter);
end;
Log('idf_tools.py command: ' + IDFToolsPyCmd);
CmdLine := IDFToolsPyCmd + ' install';
Log('Installing tools:' + CmdLine);
DoCmdlineInstall('Installing ESP-IDF tools', '', 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;
VersionIndex: Integer;
MajorString: String;
MinorString: String;
DotIndex: Integer;
IDFVersionString: String;
PythonVirtualEnvPath: String;
Command: String;
begin
@ -318,39 +390,14 @@ begin
Destination := ExpandConstant(LnkString + '\{#IDFCmdExeShortcutFile}');
Description := '{#IDFCmdExeShortcutDescription}';
IDFVersionString := IDFDownloadVersion;
{ Transform version vx.y or release/vx.y to x.y }
VersionIndex := pos('v', IDFVersionString);
if (VersionIndex > 0) then begin
Delete(IDFVersionString, 1, VersionIndex);
end;
{ Transform version x.y.z to x.y }
DotIndex := pos('.', IDFVersionString);
if (DotIndex > 0) then begin
MajorString := Copy(IDFVersionString, 1, DotIndex - 1);
Delete(IDFVersionString, 1, DotIndex);
{ Trim trailing version numbers. }
DotIndex := pos('.', IDFVersionString);
if (DotIndex > 0) then begin
MinorString := Copy(IDFVersionString, 1, DotIndex - 1);
IDFVersionString := MajorString + '.' + MinorString;
end else begin
IDFVersionString := MajorString + '.' + IDFVersionString;
end;
end;
{ Transform master to x.y }
if (IDFVersionString = 'master') then begin
IDFVersionString := GetIDFVersionFromHeaderFile();
end;
{ The links should contain reference to Python vitual env }
PythonVirtualEnvPath := ExpandConstant('{app}\python_env\idf') + IDFVersionString + '_py' + PythonVersion + '_env\Scripts';
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;
{ If cmd.exe command argument starts with a quote, the first and last quote chars in the command

View File

@ -1,24 +1,22 @@
; Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
; Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
; SPDX-License-Identifier: Apache-2.0
#pragma include __INCLUDE__ + ";" + ReadReg(HKLM, "Software\Mitrich Software\Inno Download Plugin", "InstallDir")
#include <idp.iss>
#define MyAppName "ESP-IDF Tools"
#define MyAppVersion "2.3"
#define MyAppVersion "2.4"
#define MyAppPublisher "Espressif Systems (Shanghai) Co. Ltd."
#define MyAppURL "https://github.com/espressif/esp-idf"
#define PythonVersion "3.7"
#define PythonInstallerName "python-3.7.3-amd64.exe"
#define PythonInstallerDownloadURL "https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64.exe"
#define PythonVersion "3.9.1"
#define PythonInstallerName "idf-python-3.9.1-embed-win64.zip"
#define PythonInstallerDownloadURL "https://dl.espressif.com/dl/idf-python/idf-python-3.9.1-embed-win64.zip"
#define GitVersion "2.21.0"
#define GitInstallerName "Git-2.21.0-64-bit.exe"
#define GitInstallerDownloadURL "https://github.com/git-for-windows/git/releases/download/v2.21.0.windows.1/Git-2.21.0-64-bit.exe"
#define IDFVersionsURL "https://dl.espressif.com/dl/esp-idf/idf_versions.txt"
#define IDFCmdExeShortcutDescription "Open ESP-IDF Command Prompt (cmd.exe)"
#define IDFCmdExeShortcutFile "ESP-IDF Command Prompt (cmd.exe).lnk"
@ -90,7 +88,6 @@ Name: wdexcl; Description: "Register the ESP-IDF Tools executables as Windows De
Name: idf_tools_use_mirror; Description: "Use Espressif download server instead of downloading tool packages from Github"; Flags: unchecked;
[Run]
Filename: "{app}\dist\{#PythonInstallerName}"; Parameters: "/passive PrependPath=1 InstallLauncherAllUsers=0 Include_dev=0 Include_tcltk=0 Include_launcher=0 Include_test=0 Include_doc=0"; Description: "Installing Python"; Check: PythonInstallRequired
Filename: "{app}\dist\{#GitInstallerName}"; Parameters: "/silent /tasks="""" /norestart"; Description: "Installing Git"; Check: GitInstallRequired
Filename: "{group}\{#IDFCmdExeShortcutFile}"; Flags: postinstall shellexec; Description: "Run ESP-IDF Command Prompt (cmd.exe)"; Check: InstallationSuccessful

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Custom steps before the main installation flow ------------------------------ }
@ -45,17 +45,6 @@ begin
ForceDirectories(ExpandConstant('{app}\dist'));
if not PythonUseExisting then
begin
DestPath := ExpandConstant('{app}\dist\{#PythonInstallerName}');
if FileExists(DestPath) then
begin
Log('Python installer already downloaded: ' + DestPath);
end else begin
idpAddFile('{#PythonInstallerDownloadURL}', DestPath);
end;
end;
if not GitUseExisting then
begin
DestPath := ExpandConstant('{app}\dist\{#GitInstallerName}');
@ -82,9 +71,6 @@ var
begin
EnvPath := GetEnv('PATH');
if not PythonUseExisting then
PythonExecutablePathUpdateAfterInstall();
if not GitUseExisting then
GitExecutablePathUpdateAfterInstall();
@ -103,6 +89,26 @@ begin
SetEnvironmentVariable('PYTHONPATH', '')
end;
procedure InstallEmbeddedPython();
var
EmbeddedPythonPath: String;
CmdLine: String;
begin
if (Pos('tools', PythonPath) <> 1) then begin
Exit;
end;
EmbeddedPythonPath := ExpandConstant('{app}\') + PythonExecutablePath;
UpdatePythonVariables(EmbeddedPythonPath);
Log('Checking existence of Embedded Python: ' + EmbeddedPythonPath);
if (FileExists(EmbeddedPythonPath)) then begin
Exit;
end;
CmdLine := ExpandConstant('{tmp}\7za.exe x -o{app}\tools\python\' + PythonVersion + '\ -r -aoa "{app}\dist\idf-python-' + PythonVersion + '-embed-win64.zip"');
DoCmdlineInstall('Extracting Python Interpreter', 'Using Embedded Python', CmdLine);
end;
<event('CurStepChanged')>
procedure PostInstallSteps(CurStep: TSetupStep);
var
@ -111,6 +117,9 @@ begin
if CurStep <> ssPostInstall then
exit;
ExtractTemporaryFile('7za.exe')
InstallEmbeddedPython();
try
AddPythonGitToPath();

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Find installed Python interpreters in Windows Registry (see PEP 514) ------------------------------ }

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Page to select Python interpreter ------------------------------ }
@ -8,7 +8,6 @@
var
PythonPage: TInputOptionWizardPage;
PythonVersion, PythonPath, PythonExecutablePath: String;
PythonUseExisting: Boolean;
function GetPythonPath(Unused: String): String;
@ -16,11 +15,6 @@ begin
Result := PythonPath;
end;
function PythonInstallRequired(): Boolean;
begin
Result := not PythonUseExisting;
end;
function PythonVersionSupported(Version: String): Boolean;
var
Major, Minor: Integer;
@ -93,40 +87,26 @@ begin
Log('OnPythonSelectionChange index=' + IntToStr(Page.SelectedValueIndex));
end;
procedure ApplyPythonConfigurationByIndex(Index:Integer);
begin
Log('ApplyPythonConfigurationByIndex index=' + IntToStr(Index));
PythonExecutablePath := InstalledPythonExecutables[Index];
PythonPath := ExtractFilePath(PythonExecutablePath);
PythonVersion := InstalledPythonVersions[Index];
Log('ApplyPythonConfigurationByIndex: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath);
end;
function OnPythonPageValidate(Sender: TWizardPage): Boolean;
var
Page: TInputOptionWizardPage;
begin
Page := TInputOptionWizardPage(Sender);
Log('OnPythonPageValidate index=' + IntToStr(Page.SelectedValueIndex));
if Page.SelectedValueIndex < InstalledPythonExecutables.Count then
begin
PythonUseExisting := True;
PythonExecutablePath := InstalledPythonExecutables[Page.SelectedValueIndex];
PythonPath := ExtractFilePath(PythonExecutablePath);
PythonVersion := InstalledPythonVersions[Page.SelectedValueIndex];
end else begin
PythonUseExisting := False;
PythonExecutablePath := '';
PythonPath := '';
PythonVersion := '{#PythonVersion}';
end;
Log('OnPythonPageValidate: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath);
ApplyPythonConfigurationByIndex(Page.SelectedValueIndex);
Result := True;
end;
procedure PythonExecutablePathUpdateAfterInstall();
var
Version, DisplayName, ExecutablePath, BaseDir: String;
procedure UpdatePythonVariables(ExecutablePath: String);
begin
if not GetPythonVersionInfoFromKey(
HKEY_CURRENT_USER, 'Software\Python', 'PythonCore', '{#PythonVersion}',
Version, DisplayName, ExecutablePath, BaseDir) then
begin
Log('Failed to find ExecutablePath for the installed copy of Python');
exit;
end;
Log('Found ExecutablePath for ' + DisplayName + ': ' + ExecutablePath);
PythonExecutablePath := ExecutablePath;
PythonPath := ExtractFilePath(PythonExecutablePath);
Log('PythonExecutablePathUpdateAfterInstall: PythonPath='+PythonPath+' PythonExecutablePath='+PythonExecutablePath);
@ -145,3 +125,18 @@ begin
@OnPythonSelectionChange,
@OnPythonPageValidate);
end;
<event('ShouldSkipPage')>
function ShouldSkipPythonPage(PageID: Integer): Boolean;
var
UseEmbeddedPythonParam: String;
begin
if (PageID = PythonPage.ID) then begin
{ Skip in case of embedded Python. }
UseEmbeddedPythonParam := ExpandConstant('{param:USEEMBEDDEDPYTHON|yes}');
if (UseEmbeddedPythonParam = 'yes') then begin
ApplyPythonConfigurationByIndex(0);
Result := True;
end;
end;
end;

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ ------------------------------ Installation summary page ------------------------------ }
@ -8,12 +8,12 @@ function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo,
begin
Result := ''
if PythonUseExisting then
if (FileExists(PythonExecutablePath)) then
begin
Result := Result + 'Using Python ' + PythonVersion + ':' + NewLine
+ Space + PythonExecutablePath + NewLine + NewLine;
end else begin
Result := Result + 'Will download and install Python ' + PythonVersion + NewLine + NewLine;
Result := Result + 'Using embedded Python ' + PythonVersion + NewLine + NewLine;
end;
if GitUseExisting then

View File

@ -1,4 +1,4 @@
{ Copyright 2019-2020 Espressif Systems (Shanghai) CO LTD
{ Copyright 2019-2021 Espressif Systems (Shanghai) CO LTD
SPDX-License-Identifier: Apache-2.0 }
{ SystemCheck states }
@ -474,6 +474,8 @@ end;
{ Execute system check }
procedure ExecuteSystemCheck();
var
UseEmbeddedPythonParam: String;
begin
{ Execute system check only once. Avoid execution in case of back button. }
if (SystemCheckState <> SYSTEM_CHECK_STATE_INIT) then begin
@ -486,7 +488,11 @@ begin
VerifyRootCertificates();
FindInstalledPythonVersions();
{ Search for the installed Python version only on explicit user request. }
UseEmbeddedPythonParam := ExpandConstant('{param:USEEMBEDDEDPYTHON|yes}');
if (UseEmbeddedPythonParam <> 'yes') then begin
FindInstalledPythonVersions();
end;
if (SystemCheckState <> SYSTEM_CHECK_STATE_STOPPED) then begin
SystemLogTitle(CustomMessage('SystemCheckForDefender') + ' ');
@ -519,6 +525,7 @@ end;
{ Invoke scan of system environment. }
procedure OnSystemCheckActivate(Sender: TWizardPage);
var SystemCheckParam:String;
begin
{ Display special controls. For some reason the first call of the page does not invoke SystemCheckOnCurPageChanged. }
FullLogButton.Visible := True;
@ -526,6 +533,12 @@ begin
StopSystemCheckButton.Visible := True;
SystemCheckViewer.Visible := True;
SystemCheckParam := ExpandConstant('{param:SKIPSYSTEMCHECK|no}');
if (SystemCheckParam = 'yes') then begin
SystemCheckState := SYSTEM_CHECK_STATE_STOPPED;
SystemLog('System Check disabled by command line option /SKIPSYSTEMCHECK.');
end;
ExecuteSystemCheck();
end;
@ -585,6 +598,7 @@ begin
InstalledPythonVersions := TStringList.Create();
InstalledPythonDisplayNames := TStringList.Create();
InstalledPythonExecutables := TStringList.Create();
PythonVersionAdd('{#PythonVersion}', 'Use Python {#PythonVersion} Embedded (Recommended)', 'tools\python\{#PythonVersion}\python.exe');
{ Create Spinner animation. }
Spinner := TStringList.Create();