1+ local http = require (" http" )
2+ local html = require (" html" )
3+
4+ local PYTHON_URL = " https://www.python.org/ftp/python/"
5+
6+ local DOWNLOAD_SOURCE = {
7+ --- TODO support zip or web-based installers
8+ WEB_BASED = " https://www.python.org/ftp/python/%s/python-%s%s-webinstall.exe" ,
9+ ZIP = " https://www.python.org/ftp/python/%s/python-%s-embed-%s.zip" ,
10+ MSI = " " ,
11+ --- Currently only exe installers are supported
12+ EXE = " https://www.python.org/ftp/python/%s/python-%s%s.exe" ,
13+ SOURCE = " https://www.python.org/ftp/python/%s/Python-%s.tar.xz"
14+ }
15+
16+ function getMirror ()
17+ local mirror = os.getenv (" VFOX_PYTHON_MIRROR" )
18+ if mirror == nil then
19+ return " https://www.python.org/ftp/python/"
20+ end
21+ return mirror
22+ end
23+
24+ function checkIsReleaseVersion (version )
25+ local resp , err = http .head ({
26+ url = DOWNLOAD_SOURCE .SOURCE :format (version , version )
27+ })
28+ if err ~= nil or resp .status_code ~= 200 then
29+ return false
30+ end
31+ return true
32+ end
33+ function windowsCompile (ctx )
34+ local sdkInfo = ctx .sdkInfo [' python' ]
35+ local path = sdkInfo .path
36+ local filename = sdkInfo .note
37+ --- Attention system difference
38+ local qInstallFile = path .. " \\ " .. filename
39+ local qInstallPath = path
40+ -- local exitCode = os.execute('msiexec /quiet /a "' .. qInstallFile .. '" TargetDir="' .. qInstallPath .. '"')
41+ print (" Installing python, please wait patiently for a while, about two minutes." )
42+ local exitCode = os.execute (qInstallFile .. ' /quiet InstallAllUsers=0 PrependPath=0 TargetDir=' .. qInstallPath )
43+ if exitCode ~= 0 then
44+ error (" error installing python" )
45+ end
46+ print (" Cleaning up ..." )
47+ os.remove (qInstallFile )
48+ end
49+ function linuxCompile (ctx )
50+ local sdkInfo = ctx .sdkInfo [' python' ]
51+ local path = sdkInfo .path
52+ local version = sdkInfo .version
53+ local pyenv_url = " https://github.com/pyenv/pyenv.git"
54+ local dest_pyenv_path = ctx .rootPath .. " /pyenv"
55+ local status = os.execute (" git clone " .. pyenv_url .. " " .. dest_pyenv_path )
56+ if status ~= 0 then
57+ error (" git clone failed" )
58+ end
59+ local pyenv_build_path = dest_pyenv_path .. " /plugins/python-build/bin/python-build"
60+ print (" Building python ..." )
61+ status = os.execute (pyenv_build_path .. " " .. version .. " " .. path )
62+ if status ~= 0 then
63+ error (" python build failed" )
64+ end
65+ print (" Build python success!" )
66+ print (" Cleaning up ..." )
67+ status = os.execute (" rm -rf " .. dest_pyenv_path )
68+ if status ~= 0 then
69+ error (" remove build tool failed" )
70+ end
71+ end
72+ function checkAvailableReleaseForWindows (version )
73+ local archType = RUNTIME .archType
74+ if archType == " 386" then
75+ archType = " "
76+ else
77+ archType = " -" .. archType
78+ end
79+ --- Currently only exe installers are supported
80+ --- TODO support zip or web-based installers
81+ local url = DOWNLOAD_SOURCE .EXE :format (version , version , archType )
82+ local resp , err = http .head ({
83+ url = url
84+ })
85+ if err ~= nil or resp .status_code ~= 200 then
86+ error (" No available installer found for current version" )
87+ end
88+ return url , " python-" .. version .. archType .. " .exe"
89+ end
90+ function parseVersion ()
91+ local resp , err = http .get ({
92+ url = PYTHON_URL
93+ })
94+ if err ~= nil or resp .status_code ~= 200 then
95+ error (" paring release info failed." .. err )
96+ end
97+ local result = {}
98+ html .parse (resp .body ):find (" a" ):each (function (i , selection )
99+ local href = selection :attr (" href" )
100+ local sn = string.match (href , " ^%d" )
101+ local es = string.match (href , " /$" )
102+ if sn and es then
103+ local vn = string.sub (href , 1 , - 2 )
104+ if RUNTIME .osType == " windows" then
105+ if compare_versions (vn , " 3.5.0" ) >= 0 then
106+ table.insert (result , {
107+ version = string.sub (href , 1 , - 2 ),
108+ note = " " ,
109+ })
110+ end
111+ else
112+ table.insert (result , {
113+ version = vn ,
114+ note = " " ,
115+ })
116+ end
117+ end
118+ end )
119+ table.sort (result , function (a , b )
120+ return compare_versions (a .version , b .version ) > 0
121+ end )
122+ return result
123+ end
124+
125+ function compare_versions (v1 , v2 )
126+ local v1_parts = {}
127+ for part in string.gmatch (v1 , " [^.]+" ) do
128+ table.insert (v1_parts , tonumber (part ))
129+ end
130+
131+ local v2_parts = {}
132+ for part in string.gmatch (v2 , " [^.]+" ) do
133+ table.insert (v2_parts , tonumber (part ))
134+ end
135+
136+ for i = 1 , math.max (# v1_parts , # v2_parts ) do
137+ local v1_part = v1_parts [i ] or 0
138+ local v2_part = v2_parts [i ] or 0
139+ if v1_part > v2_part then
140+ return 1
141+ elseif v1_part < v2_part then
142+ return - 1
143+ end
144+ end
145+
146+ return 0
147+ end
0 commit comments