Skip to content

Commit 805a927

Browse files
committed
Merge branch 'release/v1.1.0'
2 parents 4c4ae57 + a796da0 commit 805a927

File tree

7 files changed

+142
-83
lines changed

7 files changed

+142
-83
lines changed

Diff for: .github/workflows/main.yml

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ jobs:
99
matrix:
1010
os: [ubuntu-latest, windows-latest, macos-latest]
1111
python-version: [3.6, 3.7, 3.8, 3.9]
12+
exclude:
13+
- os: macos-latest
14+
python-version: "3.6"
1215
runs-on: ${{ matrix.os }}
1316
steps:
1417
- uses: actions/checkout@v2

Diff for: get-platformio.py

+1-1
Large diffs are not rendered by default.

Diff for: pioinstaller/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import logging.config
1616

17-
VERSION = (1, 0, 4)
17+
VERSION = (1, 1, 0)
1818
__version__ = ".".join([str(s) for s in VERSION])
1919

2020
__title__ = "platformio-installer"

Diff for: pioinstaller/__main__.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def python():
9999

100100
@check.command("core")
101101
@click.option("--auto-upgrade/--no-auto-upgrade", is_flag=True, default=True)
102+
@click.option("--global", is_flag=True, default=False)
102103
@click.option("--version-spec", default=None)
103104
@click.option(
104105
"--dump-state",
@@ -107,15 +108,16 @@ def python():
107108
),
108109
)
109110
@click.pass_context
110-
def core_check(ctx, auto_upgrade, version_spec, dump_state):
111+
def core_check(ctx, **kwargs):
111112
try:
112113
state = core.check(
113-
dev=ctx.obj.get("dev", False),
114-
auto_upgrade=auto_upgrade,
115-
version_spec=version_spec,
114+
develop=ctx.obj.get("dev", False),
115+
global_=kwargs.get("global"),
116+
auto_upgrade=kwargs.get("auto_upgrade"),
117+
version_spec=kwargs.get("version_spec"),
116118
)
117-
if dump_state:
118-
core.dump_state(target=str(dump_state), state=state)
119+
if kwargs.get("dump_state"):
120+
core.dump_state(target=str(kwargs.get("dump_state")), state=state)
119121
click.secho(
120122
"Found compatible PlatformIO Core %s -> %s"
121123
% (state.get("core_version"), state.get("platformio_exe")),

Diff for: pioinstaller/core.py

+78-71
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
# pylint: disable=import-outside-toplevel
16+
1517
import json
1618
import logging
1719
import os
1820
import platform
1921
import subprocess
22+
import sys
2023
import time
2124

2225
import click
@@ -140,40 +143,46 @@ def _install_platformio_core(shutdown_piohome=True, develop=False, ignore_python
140143
return True
141144

142145

143-
def check(dev=False, auto_upgrade=False, version_spec=None):
144-
# pylint: disable=bad-option-value, import-outside-toplevel, unused-import, import-error, unused-variable, cyclic-import, too-many-branches
146+
def check(develop=False, global_=False, auto_upgrade=False, version_spec=None):
145147
from pioinstaller import penv
146148

147-
platformio_exe = os.path.join(
148-
penv.get_penv_bin_dir(),
149-
"platformio.exe" if util.IS_WINDOWS else "platformio",
149+
python_exe = (
150+
os.path.normpath(sys.executable)
151+
if global_
152+
else os.path.join(
153+
penv.get_penv_bin_dir(), "python.exe" if util.IS_WINDOWS else "python"
154+
)
150155
)
151-
python_exe = os.path.join(
152-
penv.get_penv_bin_dir(), "python.exe" if util.IS_WINDOWS else "python"
156+
platformio_exe = (
157+
util.where_is_program("platformio")
158+
if global_
159+
else os.path.join(
160+
penv.get_penv_bin_dir(),
161+
"platformio.exe" if util.IS_WINDOWS else "platformio",
162+
)
153163
)
154-
result = {}
155-
156164
if not os.path.isfile(platformio_exe):
157165
raise exception.InvalidPlatformIOCore(
158166
"PlatformIO executable not found in `%s`" % penv.get_penv_bin_dir()
159167
)
160-
161-
if not os.path.isfile(os.path.join(penv.get_penv_dir(), "state.json")):
168+
try:
169+
subprocess.check_output([platformio_exe, "--version"], stderr=subprocess.STDOUT)
170+
except subprocess.CalledProcessError as e:
171+
error = e.output.decode()
162172
raise exception.InvalidPlatformIOCore(
163-
"Could not found state.json file in `%s`"
164-
% os.path.join(penv.get_penv_dir(), "state.json")
173+
"Could not run `%s --version`.\nError: %s" % (platformio_exe, str(error))
165174
)
166175

176+
result = {}
167177
try:
168-
result.update(fetch_python_state(python_exe))
178+
result = fetch_python_state(python_exe)
169179
except subprocess.CalledProcessError as e:
170180
error = e.output.decode()
171181
raise exception.InvalidPlatformIOCore(
172182
"Could not import PlatformIO module. Error: %s" % error
173183
)
174-
175184
piocore_version = convert_version(result.get("core_version"))
176-
dev = dev or bool(piocore_version.prerelease if piocore_version else False)
185+
develop = develop or bool(piocore_version.prerelease if piocore_version else False)
177186
result.update(
178187
{
179188
"core_dir": get_core_dir(),
@@ -184,71 +193,52 @@ def check(dev=False, auto_upgrade=False, version_spec=None):
184193
"installer_version": __version__,
185194
"python_exe": python_exe,
186195
"system": util.get_systype(),
187-
"is_develop_core": dev,
196+
"is_develop_core": develop,
188197
}
189198
)
190199

191200
if version_spec:
201+
_check_core_version(piocore_version, version_spec)
202+
if not global_:
203+
_check_platform_version()
204+
if auto_upgrade and not global_:
192205
try:
193-
if piocore_version not in semantic_version.Spec(version_spec):
194-
raise exception.InvalidPlatformIOCore(
195-
"PlatformIO Core version %s does not match version requirements %s."
196-
% (str(piocore_version), version_spec)
197-
)
198-
except ValueError:
199-
click.secho(
200-
"Invalid version requirements format: %s. "
201-
"More about Semantic Versioning: https://semver.org/" % version_spec
202-
)
206+
auto_upgrade_core(platformio_exe, develop)
207+
except: # pylint:disable=bare-except
208+
pass
209+
# re-fetch Pyrhon state
210+
try:
211+
result.update(fetch_python_state(python_exe))
212+
except: # pylint:disable=bare-except
213+
raise exception.InvalidPlatformIOCore("Could not import PlatformIO module")
203214

204-
with open(os.path.join(penv.get_penv_dir(), "state.json")) as fp:
205-
penv_state = json.load(fp)
206-
if penv_state.get("platform") != platform.platform(terse=True):
207-
raise exception.InvalidPlatformIOCore(
208-
"PlatformIO Core was installed using another platform `%s`. "
209-
"Your current platform: %s"
210-
% (penv_state.get("platform"), platform.platform(terse=True))
211-
)
215+
return result
212216

217+
218+
def _check_core_version(piocore_version, version_spec):
213219
try:
214-
subprocess.check_output([platformio_exe, "--version"], stderr=subprocess.STDOUT)
215-
except subprocess.CalledProcessError as e:
216-
error = e.output.decode()
217-
raise exception.InvalidPlatformIOCore(
218-
"Could not run `%s --version`.\nError: %s" % (platformio_exe, str(error))
220+
if piocore_version not in semantic_version.Spec(version_spec):
221+
raise exception.InvalidPlatformIOCore(
222+
"PlatformIO Core version %s does not match version requirements %s."
223+
% (str(piocore_version), version_spec)
224+
)
225+
except ValueError:
226+
click.secho(
227+
"Invalid version requirements format: %s. "
228+
"More about Semantic Versioning: https://semver.org/" % version_spec
219229
)
220230

221-
if not auto_upgrade:
222-
return result
223-
224-
time_now = int(round(time.time()))
225-
226-
last_piocore_version_check = penv_state.get("last_piocore_version_check")
227-
228-
if (
229-
last_piocore_version_check
230-
and (time_now - int(last_piocore_version_check)) < UPDATE_INTERVAL
231-
):
232-
return result
233-
234-
with open(os.path.join(penv.get_penv_dir(), "state.json"), "w") as fp:
235-
penv_state["last_piocore_version_check"] = time_now
236-
json.dump(penv_state, fp)
237231

238-
if not last_piocore_version_check:
239-
return result
240-
241-
# capture exception when Internet is off-line
242-
try:
243-
upgrade_core(platformio_exe, dev)
244-
except: # pylint:disable=bare-except
245-
return result
232+
def _check_platform_version():
233+
from pioinstaller import penv
246234

247-
try:
248-
result.update(fetch_python_state(python_exe))
249-
except: # pylint:disable=bare-except
250-
raise exception.InvalidPlatformIOCore("Could not import PlatformIO module")
251-
return result
235+
state = penv.load_state()
236+
if state.get("platform") != platform.platform(terse=True):
237+
raise exception.InvalidPlatformIOCore(
238+
"PlatformIO Core was installed using another platform `%s`. "
239+
"Your current platform: %s"
240+
% (state.get("platform"), platform.platform(terse=True))
241+
)
252242

253243

254244
def fetch_python_state(python_exe):
@@ -290,9 +280,25 @@ def convert_version(version):
290280
return None
291281

292282

293-
def upgrade_core(platformio_exe, dev=False):
283+
def auto_upgrade_core(platformio_exe, develop=False):
284+
from pioinstaller import penv
285+
286+
state = penv.load_state()
287+
time_now = int(round(time.time()))
288+
last_piocore_version_check = state.get("last_piocore_version_check")
289+
if (
290+
last_piocore_version_check
291+
and (time_now - int(last_piocore_version_check)) < UPDATE_INTERVAL
292+
):
293+
return None
294+
295+
state["last_piocore_version_check"] = time_now
296+
penv.save_state(state)
297+
if not last_piocore_version_check:
298+
return None
299+
294300
command = [platformio_exe, "upgrade"]
295-
if dev:
301+
if develop:
296302
command.append("--dev")
297303
try:
298304
subprocess.check_output(
@@ -304,6 +310,7 @@ def upgrade_core(platformio_exe, dev=False):
304310
raise exception.PIOInstallerException(
305311
"Could not upgrade PlatformIO Core: %s" % str(e)
306312
)
313+
return False
307314

308315

309316
def dump_state(target, state):

Diff for: pioinstaller/penv.py

+21-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def create_core_penv(penv_dir=None, ignore_pythons=None):
6868
python_exe = os.path.join(
6969
get_penv_bin_dir(penv_dir), "python.exe" if util.IS_WINDOWS else "python"
7070
)
71-
add_state_info(python_exe, penv_dir)
71+
init_state(python_exe, penv_dir)
7272
install_pip(python_exe, penv_dir)
7373
click.echo("Virtual environment has been successfully created!")
7474
return result_dir
@@ -132,7 +132,7 @@ def create_with_remote_venv(python_exe, penv_dir):
132132
return penv_dir
133133

134134

135-
def add_state_info(python_exe, penv_dir):
135+
def init_state(python_exe, penv_dir):
136136
version_code = (
137137
"import sys; version=sys.version_info; "
138138
"print('%d.%d.%d'%(version[0],version[1],version[2]))"
@@ -153,9 +153,26 @@ def add_state_info(python_exe, penv_dir):
153153
"installer_version": __version__,
154154
"platform": platform.platform(terse=True),
155155
}
156-
with open(os.path.join(penv_dir, "state.json"), "w") as fp:
156+
return save_state(state, penv_dir)
157+
158+
159+
def load_state(penv_dir=None):
160+
penv_dir = penv_dir or get_penv_dir()
161+
state_path = os.path.join(penv_dir, "state.json")
162+
if not os.path.isfile(state_path):
163+
raise exception.PIOInstallerException(
164+
"Could not found state.json file in `%s`" % state_path
165+
)
166+
with open(state_path) as fp:
167+
return json.load(fp)
168+
169+
170+
def save_state(state, penv_dir=None):
171+
penv_dir = penv_dir or get_penv_dir()
172+
state_path = os.path.join(penv_dir, "state.json")
173+
with open(state_path, "w") as fp:
157174
json.dump(state, fp)
158-
return os.path.join(penv_dir, "state.json")
175+
return state_path
159176

160177

161178
def install_pip(python_exe, penv_dir):

Diff for: pioinstaller/util.py

+30
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import re
2020
import shutil
2121
import stat
22+
import subprocess
2223
import sys
2324
import tarfile
2425

@@ -133,3 +134,32 @@ def safe_remove_dir(path, raise_exception=False):
133134

134135
def pepver_to_semver(pepver):
135136
return re.sub(r"(\.\d+)\.?(dev|a|b|rc|post)", r"\1-\2.", pepver, 1)
137+
138+
139+
def where_is_program(program, envpath=None):
140+
env = os.environ
141+
if envpath:
142+
env["PATH"] = envpath
143+
144+
# try OS's built-in commands
145+
try:
146+
result = (
147+
subprocess.check_output(
148+
["where" if IS_WINDOWS else "which", program], env=env
149+
)
150+
.decode()
151+
.strip()
152+
)
153+
if os.path.isfile(result):
154+
return result
155+
except (subprocess.CalledProcessError, OSError):
156+
pass
157+
158+
# look up in $PATH
159+
for bin_dir in env.get("PATH", "").split(os.pathsep):
160+
if os.path.isfile(os.path.join(bin_dir, program)):
161+
return os.path.join(bin_dir, program)
162+
if os.path.isfile(os.path.join(bin_dir, "%s.exe" % program)):
163+
return os.path.join(bin_dir, "%s.exe" % program)
164+
165+
return program

0 commit comments

Comments
 (0)