forked from platformio/platformio-core
Merge branch 'release/v6.0.2'
This commit is contained in:
13
.github/workflows/core.yml
vendored
13
.github/workflows/core.yml
vendored
@ -14,15 +14,19 @@ jobs:
|
|||||||
python-version: "3.6"
|
python-version: "3.6"
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: "recursive"
|
submodules: "recursive"
|
||||||
|
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
@ -31,11 +35,8 @@ jobs:
|
|||||||
- name: Python Lint
|
- name: Python Lint
|
||||||
run: |
|
run: |
|
||||||
tox -e lint
|
tox -e lint
|
||||||
|
|
||||||
- name: Integration Tests
|
- name: Integration Tests
|
||||||
env:
|
|
||||||
TEST_EMAIL_LOGIN: ${{ secrets.TEST_EMAIL_LOGIN }}
|
|
||||||
TEST_EMAIL_PASSWORD: ${{ secrets.TEST_EMAIL_PASSWORD }}
|
|
||||||
TEST_EMAIL_IMAP_SERVER: ${{ secrets.TEST_EMAIL_IMAP_SERVER }}
|
|
||||||
run: |
|
run: |
|
||||||
tox -e testcore
|
tox -e testcore
|
||||||
|
|
||||||
|
42
.github/workflows/deployment.yml
vendored
Normal file
42
.github/workflows/deployment.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: Deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- "release/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deployment:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: production
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: "recursive"
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install tox
|
||||||
|
|
||||||
|
- name: Deployment Tests
|
||||||
|
env:
|
||||||
|
TEST_EMAIL_LOGIN: ${{ secrets.TEST_EMAIL_LOGIN }}
|
||||||
|
TEST_EMAIL_PASSWORD: ${{ secrets.TEST_EMAIL_PASSWORD }}
|
||||||
|
TEST_EMAIL_IMAP_SERVER: ${{ secrets.TEST_EMAIL_IMAP_SERVER }}
|
||||||
|
run: |
|
||||||
|
tox -e testcore
|
||||||
|
|
||||||
|
- name: Publish package to PyPI
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
|
||||||
|
uses: pypa/gh-action-pypi-publish@release/v1
|
||||||
|
with:
|
||||||
|
user: __token__
|
||||||
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
29
.github/workflows/examples.yml
vendored
29
.github/workflows/examples.yml
vendored
@ -2,22 +2,28 @@ name: Examples
|
|||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-18.04, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
python-version: [3.7]
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
PIO_INSTALL_DEVPLATFORM_OWNERNAMES: "platformio"
|
||||||
|
PIO_INSTALL_DEVPLATFORM_NAMES: "aceinna_imu,atmelavr,atmelmegaavr,atmelsam,espressif32,espressif8266,nordicnrf52,raspberrypi,ststm32,teensy"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: "recursive"
|
submodules: "recursive"
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
|
||||||
uses: actions/setup-python@v2
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v3
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
@ -25,24 +31,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Run on Linux
|
- name: Run on Linux
|
||||||
if: startsWith(matrix.os, 'ubuntu')
|
if: startsWith(matrix.os, 'ubuntu')
|
||||||
env:
|
|
||||||
PIO_INSTALL_DEVPLATFORMS_OWNERNAMES: "platformio"
|
|
||||||
PIO_INSTALL_DEVPLATFORMS_IGNORE: "ststm8,infineonxmc,intel_mcs51"
|
|
||||||
run: |
|
run: |
|
||||||
# ChipKIT issue: install 32-bit support for GCC PIC32
|
|
||||||
sudo apt-get install libc6-i386
|
|
||||||
# Free space
|
# Free space
|
||||||
sudo apt clean
|
sudo apt clean
|
||||||
docker rmi $(docker image ls -aq)
|
docker rmi $(docker image ls -aq)
|
||||||
df -h
|
df -h
|
||||||
# Run
|
|
||||||
tox -e testexamples
|
tox -e testexamples
|
||||||
|
|
||||||
- name: Run on macOS
|
- name: Run on macOS
|
||||||
if: startsWith(matrix.os, 'macos')
|
if: startsWith(matrix.os, 'macos')
|
||||||
env:
|
|
||||||
PIO_INSTALL_DEVPLATFORMS_OWNERNAMES: "platformio"
|
|
||||||
PIO_INSTALL_DEVPLATFORMS_IGNORE: "ststm8,infineonxmc,microchippic32,lattice_ice40,gd32v"
|
|
||||||
run: |
|
run: |
|
||||||
df -h
|
df -h
|
||||||
tox -e testexamples
|
tox -e testexamples
|
||||||
@ -52,8 +49,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PLATFORMIO_CORE_DIR: C:/pio
|
PLATFORMIO_CORE_DIR: C:/pio
|
||||||
PLATFORMIO_WORKSPACE_DIR: C:/pio-workspace/$PROJECT_HASH
|
PLATFORMIO_WORKSPACE_DIR: C:/pio-workspace/$PROJECT_HASH
|
||||||
PIO_INSTALL_DEVPLATFORMS_OWNERNAMES: "platformio"
|
|
||||||
PIO_INSTALL_DEVPLATFORMS_IGNORE: "ststm8,infineonxmc,riscv_gap"
|
|
||||||
run: |
|
run: |
|
||||||
tox -e testexamples
|
tox -e testexamples
|
||||||
|
|
||||||
|
69
.github/workflows/projects.yml
vendored
Normal file
69
.github/workflows/projects.yml
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
name: Projects
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
project:
|
||||||
|
- marlin:
|
||||||
|
repository: "MarlinFirmware/Marlin"
|
||||||
|
folder: "Marlin"
|
||||||
|
config_dir: "Marlin"
|
||||||
|
env_name: "mega2560"
|
||||||
|
- esphome:
|
||||||
|
repository: "esphome/esphome"
|
||||||
|
folder: "esphome"
|
||||||
|
config_dir: "esphome"
|
||||||
|
env_name: "esp32-arduino"
|
||||||
|
- smartknob:
|
||||||
|
repository: "scottbez1/smartknob"
|
||||||
|
folder: "smartknob"
|
||||||
|
config_dir: "smartknob/firmware"
|
||||||
|
env_name: "view"
|
||||||
|
- espurna:
|
||||||
|
repository: "xoseperez/espurna"
|
||||||
|
folder: "espurna"
|
||||||
|
config_dir: "espurna/code"
|
||||||
|
env_name: "nodemcu-lolin"
|
||||||
|
- OpenMQTTGateway:
|
||||||
|
repository: "1technophile/OpenMQTTGateway"
|
||||||
|
folder: "OpenMQTTGateway"
|
||||||
|
config_dir: "OpenMQTTGateway"
|
||||||
|
env_name: "esp32-m5atom"
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
exclude:
|
||||||
|
- os: windows-latest
|
||||||
|
project: {"esphome": "", "repository": "esphome/esphome", "folder": "esphome", "config_dir": "esphome", "env_name": "esp32-arduino"}
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: "recursive"
|
||||||
|
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: 3.9
|
||||||
|
|
||||||
|
- name: Install PlatformIO
|
||||||
|
run: pip install -U .
|
||||||
|
|
||||||
|
- name: Check out ${{ matrix.project.repository }}
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: "recursive"
|
||||||
|
repository: ${{ matrix.project.repository }}
|
||||||
|
path: ${{ matrix.project.folder }}
|
||||||
|
|
||||||
|
- name: Install ESPHome dependencies
|
||||||
|
# Requires esptool package as it's used in a custom prescript
|
||||||
|
if: ${{ contains(matrix.project.repository, 'esphome') }}
|
||||||
|
run: pip install esptool==3.*
|
||||||
|
|
||||||
|
- name: Compile ${{ matrix.project.repository }}
|
||||||
|
run: pio run -d ${{ matrix.project.config_dir }} -e ${{ matrix.project.env_name }}
|
||||||
|
|
13
HISTORY.rst
13
HISTORY.rst
@ -4,6 +4,7 @@ Release Notes
|
|||||||
.. |PIOCONF| replace:: `"platformio.ini" <https://docs.platformio.org/en/latest/projectconf.html>`__ configuration file
|
.. |PIOCONF| replace:: `"platformio.ini" <https://docs.platformio.org/en/latest/projectconf.html>`__ configuration file
|
||||||
.. |LDF| replace:: `LDF <https://docs.platformio.org/en/latest/librarymanager/ldf.html>`__
|
.. |LDF| replace:: `LDF <https://docs.platformio.org/en/latest/librarymanager/ldf.html>`__
|
||||||
.. |INTERPOLATION| replace:: `Interpolation of Values <https://docs.platformio.org/en/latest/projectconf/interpolation.html>`__
|
.. |INTERPOLATION| replace:: `Interpolation of Values <https://docs.platformio.org/en/latest/projectconf/interpolation.html>`__
|
||||||
|
.. |UNITTESTING| replace:: `Unit Testing <https://docs.platformio.org/en/latest/advanced/unit-testing/index.html>`__
|
||||||
|
|
||||||
.. _release_notes_6:
|
.. _release_notes_6:
|
||||||
|
|
||||||
@ -12,6 +13,16 @@ PlatformIO Core 6
|
|||||||
|
|
||||||
**A professional collaborative platform for declarative, safety-critical, and test-driven embedded development.**
|
**A professional collaborative platform for declarative, safety-critical, and test-driven embedded development.**
|
||||||
|
|
||||||
|
6.0.2 (2022-06-01)
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* Control |UNITTESTING| verbosity with a new multilevel `pio test -v <https://docs.platformio.org/en/latest/core/userguide/cmd_test.html#cmdoption-pio-test-v>`__ command option (`issue #4276 <https://github.com/platformio/platformio-core/issues/4276>`_)
|
||||||
|
* Follow symbolic links during searching for the unit test suites (`issue #4288 <https://github.com/platformio/platformio-core/issues/4288>`_)
|
||||||
|
* Show a warning when testing an empty project without a test suite (`issue #4278 <https://github.com/platformio/platformio-core/issues/4278>`_)
|
||||||
|
* Improved support for `Asking for input (prompts) <https://docs.platformio.org/en/latest/scripting/examples/asking_for_input.html>`_
|
||||||
|
* Fixed an issue when the `build_src_flags <https://docs.platformio.org/en/latest/projectconf/section_env_build.html#build-src-flags>`__ option was applied outside the project scope (`issue #4277 <https://github.com/platformio/platformio-core/issues/4277>`_)
|
||||||
|
* Fixed an issue with debugging assembly files without preprocessor (".s")
|
||||||
|
|
||||||
6.0.1 (2022-05-17)
|
6.0.1 (2022-05-17)
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@ -53,7 +64,7 @@ Please check the `Migration guide from 5.x to 6.0 <https://docs.platformio.org/e
|
|||||||
|
|
||||||
* **Unit Testing**
|
* **Unit Testing**
|
||||||
|
|
||||||
- Refactored from scratch `Unit Testing <https://docs.platformio.org/en/latest/advanced/unit-testing/index.html>`_ solution and its documentation
|
- Refactored from scratch |UNITTESTING| solution and its documentation
|
||||||
- New: `Test Hierarchy <https://docs.platformio.org/en/latest/advanced/unit-testing/structure.html>`_ (`issue #4135 <https://github.com/platformio/platformio-core/issues/4135>`_)
|
- New: `Test Hierarchy <https://docs.platformio.org/en/latest/advanced/unit-testing/structure.html>`_ (`issue #4135 <https://github.com/platformio/platformio-core/issues/4135>`_)
|
||||||
- New: `Doctest <https://docs.platformio.org/en/latest/advanced/unit-testing/frameworks/doctest.html>`__ testing framework (`issue #4240 <https://github.com/platformio/platformio-core/issues/4240>`_)
|
- New: `Doctest <https://docs.platformio.org/en/latest/advanced/unit-testing/frameworks/doctest.html>`__ testing framework (`issue #4240 <https://github.com/platformio/platformio-core/issues/4240>`_)
|
||||||
- New: `GoogleTest <https://docs.platformio.org/en/latest/advanced/unit-testing/frameworks/googletest.html>`__ testing and mocking framework (`issue #3572 <https://github.com/platformio/platformio-core/issues/3572>`_)
|
- New: `GoogleTest <https://docs.platformio.org/en/latest/advanced/unit-testing/frameworks/googletest.html>`__ testing and mocking framework (`issue #3572 <https://github.com/platformio/platformio-core/issues/3572>`_)
|
||||||
|
12
README.rst
12
README.rst
@ -8,18 +8,18 @@ PlatformIO Core
|
|||||||
.. image:: https://github.com/platformio/platformio-core/workflows/Core/badge.svg
|
.. image:: https://github.com/platformio/platformio-core/workflows/Core/badge.svg
|
||||||
:target: https://docs.platformio.org/en/latest/core/index.html
|
:target: https://docs.platformio.org/en/latest/core/index.html
|
||||||
:alt: CI Build for PlatformIO Core
|
:alt: CI Build for PlatformIO Core
|
||||||
.. image:: https://github.com/platformio/platformio-core/workflows/Examples/badge.svg
|
|
||||||
:target: https://github.com/platformio/platformio-examples
|
|
||||||
:alt: CI Build for dev-platform examples
|
|
||||||
.. image:: https://github.com/platformio/platformio-core/workflows/Docs/badge.svg
|
.. image:: https://github.com/platformio/platformio-core/workflows/Docs/badge.svg
|
||||||
:target: https://docs.platformio.org?utm_source=github&utm_medium=core
|
:target: https://docs.platformio.org?utm_source=github&utm_medium=core
|
||||||
:alt: CI Build for Docs
|
:alt: CI Build for Docs
|
||||||
|
.. image:: https://github.com/platformio/platformio-core/workflows/Examples/badge.svg
|
||||||
|
:target: https://github.com/platformio/platformio-examples
|
||||||
|
:alt: CI Build for dev-platform examples
|
||||||
|
.. image:: https://github.com/platformio/platformio-core/workflows/Projects/badge.svg
|
||||||
|
:target: https://docs.platformio.org/en/latest/tutorials/index.html#projects
|
||||||
|
:alt: CI Build for the Community Projects
|
||||||
.. image:: https://img.shields.io/pypi/v/platformio.svg
|
.. image:: https://img.shields.io/pypi/v/platformio.svg
|
||||||
:target: https://pypi.python.org/pypi/platformio/
|
:target: https://pypi.python.org/pypi/platformio/
|
||||||
:alt: Latest Version
|
:alt: Latest Version
|
||||||
.. image:: https://img.shields.io/badge/license-Apache%202.0-blue.svg
|
|
||||||
:target: https://pypi.python.org/pypi/platformio/
|
|
||||||
:alt: License
|
|
||||||
.. image:: https://img.shields.io/badge/PlatformIO-Labs-orange.svg
|
.. image:: https://img.shields.io/badge/PlatformIO-Labs-orange.svg
|
||||||
:alt: PlatformIO Labs
|
:alt: PlatformIO Labs
|
||||||
:target: https://piolabs.com/?utm_source=github&utm_medium=core
|
:target: https://piolabs.com/?utm_source=github&utm_medium=core
|
||||||
|
2
docs
2
docs
Submodule docs updated: 5bf0037c66...300060ea08
2
examples
2
examples
Submodule examples updated: 8464bbb5d9...6c52fd3277
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
VERSION = (6, 0, 1)
|
VERSION = (6, 0, 2)
|
||||||
__version__ = ".".join([str(s) for s in VERSION])
|
__version__ = ".".join([str(s) for s in VERSION])
|
||||||
|
|
||||||
__title__ = "platformio"
|
__title__ = "platformio"
|
||||||
|
@ -19,7 +19,7 @@ from traceback import format_exc
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import __version__, exception, maintenance
|
from platformio import __version__, exception, maintenance
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.compat import IS_CYGWIN, ensure_python3
|
from platformio.compat import IS_CYGWIN, ensure_python3
|
||||||
|
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ from platformio.compat import IS_CYGWIN, ensure_python3
|
|||||||
cls=PlatformioCLI, context_settings=dict(help_option_names=["-h", "--help"])
|
cls=PlatformioCLI, context_settings=dict(help_option_names=["-h", "--help"])
|
||||||
)
|
)
|
||||||
@click.version_option(__version__, prog_name="PlatformIO Core")
|
@click.version_option(__version__, prog_name="PlatformIO Core")
|
||||||
@click.option("--force", "-f", is_flag=True, help="DEPRECATED")
|
@click.option("--force", "-f", is_flag=True, help="DEPRECATED", hidden=True)
|
||||||
@click.option("--caller", "-c", help="Caller ID (service)")
|
@click.option("--caller", "-c", help="Caller ID (service)")
|
||||||
@click.option("--no-ansi", is_flag=True, help="Do not print ANSI control characters")
|
@click.option("--no-ansi", is_flag=True, help="Do not print ANSI control characters")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
@ -120,7 +120,7 @@ An unexpected error occurred. Further steps:
|
|||||||
`pip install -U platformio` command
|
`pip install -U platformio` command
|
||||||
|
|
||||||
* Try to find answer in FAQ Troubleshooting section
|
* Try to find answer in FAQ Troubleshooting section
|
||||||
https://docs.platformio.org/page/faq.html
|
https://docs.platformio.org/page/faq/index.html
|
||||||
|
|
||||||
* Report this problem to the developers
|
* Report this problem to the developers
|
||||||
https://github.com/platformio/platformio-core/issues
|
https://github.com/platformio/platformio-core/issues
|
||||||
|
44
platformio/account/cli.py
Normal file
44
platformio/account/cli.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.commands.destroy import account_destroy_cmd
|
||||||
|
from platformio.account.commands.forgot import account_forgot_cmd
|
||||||
|
from platformio.account.commands.login import account_login_cmd
|
||||||
|
from platformio.account.commands.logout import account_logout_cmd
|
||||||
|
from platformio.account.commands.password import account_password_cmd
|
||||||
|
from platformio.account.commands.register import account_register_cmd
|
||||||
|
from platformio.account.commands.show import account_show_cmd
|
||||||
|
from platformio.account.commands.token import account_token_cmd
|
||||||
|
from platformio.account.commands.update import account_update_cmd
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
"account",
|
||||||
|
commands=[
|
||||||
|
account_destroy_cmd,
|
||||||
|
account_forgot_cmd,
|
||||||
|
account_login_cmd,
|
||||||
|
account_logout_cmd,
|
||||||
|
account_password_cmd,
|
||||||
|
account_register_cmd,
|
||||||
|
account_show_cmd,
|
||||||
|
account_token_cmd,
|
||||||
|
account_update_cmd,
|
||||||
|
],
|
||||||
|
short_help="Manage PlatformIO account",
|
||||||
|
)
|
||||||
|
def cli():
|
||||||
|
pass
|
@ -16,8 +16,8 @@ import os
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from platformio import __accounts_api__, app
|
from platformio import __accounts_api__, app
|
||||||
from platformio.clients.http import HTTPClient, HTTPClientError
|
|
||||||
from platformio.exception import PlatformioException
|
from platformio.exception import PlatformioException
|
||||||
|
from platformio.http import HTTPClient, HTTPClientError
|
||||||
|
|
||||||
|
|
||||||
class AccountError(PlatformioException):
|
class AccountError(PlatformioException):
|
37
platformio/account/commands/destroy.py
Normal file
37
platformio/account/commands/destroy.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient, AccountNotAuthorized
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("destroy", short_help="Destroy account")
|
||||||
|
def account_destroy_cmd():
|
||||||
|
client = AccountClient()
|
||||||
|
click.confirm(
|
||||||
|
"Are you sure you want to delete the %s user account?\n"
|
||||||
|
"Warning! All linked data will be permanently removed and can not be restored."
|
||||||
|
% client.get_logged_username(),
|
||||||
|
abort=True,
|
||||||
|
)
|
||||||
|
client.destroy_account()
|
||||||
|
try:
|
||||||
|
client.logout()
|
||||||
|
except AccountNotAuthorized:
|
||||||
|
pass
|
||||||
|
click.secho(
|
||||||
|
"User account has been destroyed.",
|
||||||
|
fg="green",
|
||||||
|
)
|
@ -12,16 +12,18 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
import click
|
||||||
|
|
||||||
from platformio.commands.update import cli as cmd_update
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
def test_update(clirunner, validate_cliresult, isolated_pio_core):
|
@click.command("forgot", short_help="Forgot password")
|
||||||
matches = ("Platform Manager", "Library Manager")
|
@click.option("--username", prompt="Username or email")
|
||||||
result = clirunner.invoke(cmd_update)
|
def account_forgot_cmd(username):
|
||||||
validate_cliresult(result)
|
client = AccountClient()
|
||||||
assert all(m in result.output for m in matches)
|
client.forgot_password(username)
|
||||||
result = clirunner.invoke(cmd_update)
|
click.secho(
|
||||||
validate_cliresult(result)
|
"If this account is registered, we will send the "
|
||||||
assert all(m in result.output for m in matches)
|
"further instructions to your email.",
|
||||||
|
fg="green",
|
||||||
|
)
|
26
platformio/account/commands/login.py
Normal file
26
platformio/account/commands/login.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("login", short_help="Log in to PlatformIO Account")
|
||||||
|
@click.option("-u", "--username", prompt="Username or email")
|
||||||
|
@click.option("-p", "--password", prompt=True, hide_input=True)
|
||||||
|
def account_login_cmd(username, password):
|
||||||
|
client = AccountClient()
|
||||||
|
client.login(username, password)
|
||||||
|
click.secho("Successfully logged in!", fg="green")
|
24
platformio/account/commands/logout.py
Normal file
24
platformio/account/commands/logout.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("logout", short_help="Log out of PlatformIO Account")
|
||||||
|
def account_logout_cmd():
|
||||||
|
client = AccountClient()
|
||||||
|
client.logout()
|
||||||
|
click.secho("Successfully logged out!", fg="green")
|
26
platformio/account/commands/password.py
Normal file
26
platformio/account/commands/password.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("password", short_help="Change password")
|
||||||
|
@click.option("--old-password", prompt=True, hide_input=True)
|
||||||
|
@click.option("--new-password", prompt=True, hide_input=True, confirmation_prompt=True)
|
||||||
|
def account_password_cmd(old_password, new_password):
|
||||||
|
client = AccountClient()
|
||||||
|
client.change_password(old_password, new_password)
|
||||||
|
click.secho("Password successfully changed!", fg="green")
|
52
platformio/account/commands/register.py
Normal file
52
platformio/account/commands/register.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import (
|
||||||
|
validate_email,
|
||||||
|
validate_password,
|
||||||
|
validate_username,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("register", short_help="Create new PlatformIO Account")
|
||||||
|
@click.option(
|
||||||
|
"-u",
|
||||||
|
"--username",
|
||||||
|
prompt=True,
|
||||||
|
callback=lambda _, __, value: validate_username(value),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"-e", "--email", prompt=True, callback=lambda _, __, value: validate_email(value)
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"-p",
|
||||||
|
"--password",
|
||||||
|
prompt=True,
|
||||||
|
hide_input=True,
|
||||||
|
confirmation_prompt=True,
|
||||||
|
callback=lambda _, __, value: validate_password(value),
|
||||||
|
)
|
||||||
|
@click.option("--firstname", prompt=True)
|
||||||
|
@click.option("--lastname", prompt=True)
|
||||||
|
def account_register_cmd(username, email, password, firstname, lastname):
|
||||||
|
client = AccountClient()
|
||||||
|
client.registration(username, email, password, firstname, lastname)
|
||||||
|
click.secho(
|
||||||
|
"An account has been successfully created. "
|
||||||
|
"Please check your mail to activate your account and verify your email address.",
|
||||||
|
fg="green",
|
||||||
|
)
|
116
platformio/account/commands/show.py
Normal file
116
platformio/account/commands/show.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import click
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
from platformio import util
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("show", short_help="PlatformIO Account information")
|
||||||
|
@click.option("--offline", is_flag=True)
|
||||||
|
@click.option("--json-output", is_flag=True)
|
||||||
|
def account_show_cmd(offline, json_output):
|
||||||
|
client = AccountClient()
|
||||||
|
info = client.get_account_info(offline)
|
||||||
|
if json_output:
|
||||||
|
click.echo(json.dumps(info))
|
||||||
|
return
|
||||||
|
click.echo()
|
||||||
|
if info.get("profile"):
|
||||||
|
print_profile(info["profile"])
|
||||||
|
if info.get("packages"):
|
||||||
|
print_packages(info["packages"])
|
||||||
|
if info.get("subscriptions"):
|
||||||
|
print_subscriptions(info["subscriptions"])
|
||||||
|
click.echo()
|
||||||
|
|
||||||
|
|
||||||
|
def print_profile(profile):
|
||||||
|
click.secho("Profile", fg="cyan", bold=True)
|
||||||
|
click.echo("=" * len("Profile"))
|
||||||
|
data = []
|
||||||
|
if profile.get("username"):
|
||||||
|
data.append(("Username:", profile["username"]))
|
||||||
|
if profile.get("email"):
|
||||||
|
data.append(("Email:", profile["email"]))
|
||||||
|
if profile.get("firstname"):
|
||||||
|
data.append(("First name:", profile["firstname"]))
|
||||||
|
if profile.get("lastname"):
|
||||||
|
data.append(("Last name:", profile["lastname"]))
|
||||||
|
click.echo(tabulate(data, tablefmt="plain"))
|
||||||
|
|
||||||
|
|
||||||
|
def print_packages(packages):
|
||||||
|
click.echo()
|
||||||
|
click.secho("Packages", fg="cyan")
|
||||||
|
click.echo("=" * len("Packages"))
|
||||||
|
for package in packages:
|
||||||
|
click.echo()
|
||||||
|
click.secho(package.get("name"), bold=True)
|
||||||
|
click.echo("-" * len(package.get("name")))
|
||||||
|
if package.get("description"):
|
||||||
|
click.echo(package.get("description"))
|
||||||
|
data = []
|
||||||
|
expire = "-"
|
||||||
|
if "subscription" in package:
|
||||||
|
expire = util.parse_datetime(
|
||||||
|
package["subscription"].get("end_at")
|
||||||
|
or package["subscription"].get("next_bill_at")
|
||||||
|
).strftime("%Y-%m-%d")
|
||||||
|
data.append(("Expire:", expire))
|
||||||
|
services = []
|
||||||
|
for key in package:
|
||||||
|
if not key.startswith("service."):
|
||||||
|
continue
|
||||||
|
if isinstance(package[key], dict):
|
||||||
|
services.append(package[key].get("title"))
|
||||||
|
else:
|
||||||
|
services.append(package[key])
|
||||||
|
if services:
|
||||||
|
data.append(("Services:", ", ".join(services)))
|
||||||
|
click.echo(tabulate(data, tablefmt="plain"))
|
||||||
|
|
||||||
|
|
||||||
|
def print_subscriptions(subscriptions):
|
||||||
|
click.echo()
|
||||||
|
click.secho("Subscriptions", fg="cyan")
|
||||||
|
click.echo("=" * len("Subscriptions"))
|
||||||
|
for subscription in subscriptions:
|
||||||
|
click.echo()
|
||||||
|
click.secho(subscription.get("product_name"), bold=True)
|
||||||
|
click.echo("-" * len(subscription.get("product_name")))
|
||||||
|
data = [("State:", subscription.get("status"))]
|
||||||
|
begin_at = util.parse_datetime(subscription.get("begin_at")).strftime("%c")
|
||||||
|
data.append(("Start date:", begin_at or "-"))
|
||||||
|
end_at = subscription.get("end_at")
|
||||||
|
if end_at:
|
||||||
|
end_at = util.parse_datetime(subscription.get("end_at")).strftime("%c")
|
||||||
|
data.append(("End date:", end_at or "-"))
|
||||||
|
next_bill_at = subscription.get("next_bill_at")
|
||||||
|
if next_bill_at:
|
||||||
|
next_bill_at = util.parse_datetime(
|
||||||
|
subscription.get("next_bill_at")
|
||||||
|
).strftime("%c")
|
||||||
|
data.append(("Next payment:", next_bill_at or "-"))
|
||||||
|
data.append(
|
||||||
|
("Edit:", click.style(subscription.get("update_url"), fg="blue") or "-")
|
||||||
|
)
|
||||||
|
data.append(
|
||||||
|
("Cancel:", click.style(subscription.get("cancel_url"), fg="blue") or "-")
|
||||||
|
)
|
||||||
|
click.echo(tabulate(data, tablefmt="plain"))
|
32
platformio/account/commands/token.py
Normal file
32
platformio/account/commands/token.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("token", short_help="Get or regenerate Authentication Token")
|
||||||
|
@click.option("-p", "--password", prompt=True, hide_input=True)
|
||||||
|
@click.option("--regenerate", is_flag=True)
|
||||||
|
@click.option("--json-output", is_flag=True)
|
||||||
|
def account_token_cmd(password, regenerate, json_output):
|
||||||
|
client = AccountClient()
|
||||||
|
auth_token = client.auth_token(password, regenerate)
|
||||||
|
if json_output:
|
||||||
|
click.echo(json.dumps({"status": "success", "result": auth_token}))
|
||||||
|
return
|
||||||
|
click.secho("Personal Authentication Token: %s" % auth_token, fg="green")
|
59
platformio/account/commands/update.py
Normal file
59
platformio/account/commands/update.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient, AccountNotAuthorized
|
||||||
|
from platformio.account.validate import validate_email, validate_username
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("update", short_help="Update profile information")
|
||||||
|
@click.option("--current-password", prompt=True, hide_input=True)
|
||||||
|
@click.option("--username")
|
||||||
|
@click.option("--email")
|
||||||
|
@click.option("--firstname")
|
||||||
|
@click.option("--lastname")
|
||||||
|
def account_update_cmd(current_password, **kwargs):
|
||||||
|
client = AccountClient()
|
||||||
|
profile = client.get_profile()
|
||||||
|
new_profile = profile.copy()
|
||||||
|
if not any(kwargs.values()):
|
||||||
|
for field in profile:
|
||||||
|
new_profile[field] = click.prompt(
|
||||||
|
field.replace("_", " ").capitalize(), default=profile[field]
|
||||||
|
)
|
||||||
|
if field == "email":
|
||||||
|
validate_email(new_profile[field])
|
||||||
|
if field == "username":
|
||||||
|
validate_username(new_profile[field])
|
||||||
|
else:
|
||||||
|
new_profile.update({key: value for key, value in kwargs.items() if value})
|
||||||
|
client.update_profile(new_profile, current_password)
|
||||||
|
click.secho("Profile successfully updated!", fg="green")
|
||||||
|
username_changed = new_profile["username"] != profile["username"]
|
||||||
|
email_changed = new_profile["email"] != profile["email"]
|
||||||
|
if not username_changed and not email_changed:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
client.logout()
|
||||||
|
except AccountNotAuthorized:
|
||||||
|
pass
|
||||||
|
if email_changed:
|
||||||
|
click.secho(
|
||||||
|
"Please check your mail to verify your new email address and re-login. ",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
click.secho("Please re-login.", fg="yellow")
|
||||||
|
return None
|
38
platformio/account/org/cli.py
Normal file
38
platformio/account/org/cli.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.org.commands.add import org_add_cmd
|
||||||
|
from platformio.account.org.commands.create import org_create_cmd
|
||||||
|
from platformio.account.org.commands.destroy import org_destroy_cmd
|
||||||
|
from platformio.account.org.commands.list import org_list_cmd
|
||||||
|
from platformio.account.org.commands.remove import org_remove_cmd
|
||||||
|
from platformio.account.org.commands.update import org_update_cmd
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
"account",
|
||||||
|
commands=[
|
||||||
|
org_add_cmd,
|
||||||
|
org_create_cmd,
|
||||||
|
org_destroy_cmd,
|
||||||
|
org_list_cmd,
|
||||||
|
org_remove_cmd,
|
||||||
|
org_update_cmd,
|
||||||
|
],
|
||||||
|
short_help="Manage organizations",
|
||||||
|
)
|
||||||
|
def cli():
|
||||||
|
pass
|
34
platformio/account/org/commands/add.py
Normal file
34
platformio/account/org/commands/add.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("add", short_help="Add a new owner to organization")
|
||||||
|
@click.argument(
|
||||||
|
"orgname",
|
||||||
|
)
|
||||||
|
@click.argument(
|
||||||
|
"username",
|
||||||
|
)
|
||||||
|
def org_add_cmd(orgname, username):
|
||||||
|
client = AccountClient()
|
||||||
|
client.add_org_owner(orgname, username)
|
||||||
|
return click.secho(
|
||||||
|
"The new owner `%s` has been successfully added to the `%s` organization."
|
||||||
|
% (username, orgname),
|
||||||
|
fg="green",
|
||||||
|
)
|
38
platformio/account/org/commands/create.py
Normal file
38
platformio/account/org/commands/create.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_email, validate_orgname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("create", short_help="Create a new organization")
|
||||||
|
@click.argument(
|
||||||
|
"orgname",
|
||||||
|
callback=lambda _, __, value: validate_orgname(value),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--email", callback=lambda _, __, value: validate_email(value) if value else value
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--displayname",
|
||||||
|
)
|
||||||
|
def org_create_cmd(orgname, email, displayname):
|
||||||
|
client = AccountClient()
|
||||||
|
client.create_org(orgname, email, displayname)
|
||||||
|
return click.secho(
|
||||||
|
"The organization `%s` has been successfully created." % orgname,
|
||||||
|
fg="green",
|
||||||
|
)
|
34
platformio/account/org/commands/destroy.py
Normal file
34
platformio/account/org/commands/destroy.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("destroy", short_help="Destroy organization")
|
||||||
|
@click.argument("orgname")
|
||||||
|
def org_destroy_cmd(orgname):
|
||||||
|
client = AccountClient()
|
||||||
|
click.confirm(
|
||||||
|
"Are you sure you want to delete the `%s` organization account?\n"
|
||||||
|
"Warning! All linked data will be permanently removed and can not be restored."
|
||||||
|
% orgname,
|
||||||
|
abort=True,
|
||||||
|
)
|
||||||
|
client.destroy_org(orgname)
|
||||||
|
return click.secho(
|
||||||
|
"Organization `%s` has been destroyed." % orgname,
|
||||||
|
fg="green",
|
||||||
|
)
|
48
platformio/account/org/commands/list.py
Normal file
48
platformio/account/org/commands/list.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import click
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("list", short_help="List organizations and their members")
|
||||||
|
@click.option("--json-output", is_flag=True)
|
||||||
|
def org_list_cmd(json_output):
|
||||||
|
client = AccountClient()
|
||||||
|
orgs = client.list_orgs()
|
||||||
|
if json_output:
|
||||||
|
return click.echo(json.dumps(orgs))
|
||||||
|
if not orgs:
|
||||||
|
return click.echo("You do not have any organization")
|
||||||
|
for org in orgs:
|
||||||
|
click.echo()
|
||||||
|
click.secho(org.get("orgname"), fg="cyan")
|
||||||
|
click.echo("-" * len(org.get("orgname")))
|
||||||
|
data = []
|
||||||
|
if org.get("displayname"):
|
||||||
|
data.append(("Display Name:", org.get("displayname")))
|
||||||
|
if org.get("email"):
|
||||||
|
data.append(("Email:", org.get("email")))
|
||||||
|
data.append(
|
||||||
|
(
|
||||||
|
"Owners:",
|
||||||
|
", ".join((owner.get("username") for owner in org.get("owners"))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
click.echo(tabulate(data, tablefmt="plain"))
|
||||||
|
return click.echo()
|
34
platformio/account/org/commands/remove.py
Normal file
34
platformio/account/org/commands/remove.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("remove", short_help="Remove an owner from organization")
|
||||||
|
@click.argument(
|
||||||
|
"orgname",
|
||||||
|
)
|
||||||
|
@click.argument(
|
||||||
|
"username",
|
||||||
|
)
|
||||||
|
def org_remove_cmd(orgname, username):
|
||||||
|
client = AccountClient()
|
||||||
|
client.remove_org_owner(orgname, username)
|
||||||
|
return click.secho(
|
||||||
|
"The `%s` owner has been successfully removed from the `%s` organization."
|
||||||
|
% (username, orgname),
|
||||||
|
fg="green",
|
||||||
|
)
|
52
platformio/account/org/commands/update.py
Normal file
52
platformio/account/org/commands/update.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_email, validate_orgname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("update", short_help="Update organization")
|
||||||
|
@click.argument("cur_orgname")
|
||||||
|
@click.option(
|
||||||
|
"--orgname",
|
||||||
|
callback=lambda _, __, value: validate_orgname(value),
|
||||||
|
help="A new orgname",
|
||||||
|
)
|
||||||
|
@click.option("--email")
|
||||||
|
@click.option("--displayname")
|
||||||
|
def org_update_cmd(cur_orgname, **kwargs):
|
||||||
|
client = AccountClient()
|
||||||
|
org = client.get_org(cur_orgname)
|
||||||
|
del org["owners"]
|
||||||
|
new_org = org.copy()
|
||||||
|
if not any(kwargs.values()):
|
||||||
|
for field in org:
|
||||||
|
new_org[field] = click.prompt(
|
||||||
|
field.replace("_", " ").capitalize(), default=org[field]
|
||||||
|
)
|
||||||
|
if field == "email":
|
||||||
|
validate_email(new_org[field])
|
||||||
|
if field == "orgname":
|
||||||
|
validate_orgname(new_org[field])
|
||||||
|
else:
|
||||||
|
new_org.update(
|
||||||
|
{key.replace("new_", ""): value for key, value in kwargs.items() if value}
|
||||||
|
)
|
||||||
|
client.update_org(cur_orgname, new_org)
|
||||||
|
return click.secho(
|
||||||
|
"The organization `%s` has been successfully updated." % cur_orgname,
|
||||||
|
fg="green",
|
||||||
|
)
|
38
platformio/account/team/cli.py
Normal file
38
platformio/account/team/cli.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.team.commands.add import team_add_cmd
|
||||||
|
from platformio.account.team.commands.create import team_create_cmd
|
||||||
|
from platformio.account.team.commands.destroy import team_destroy_cmd
|
||||||
|
from platformio.account.team.commands.list import team_list_cmd
|
||||||
|
from platformio.account.team.commands.remove import team_remove_cmd
|
||||||
|
from platformio.account.team.commands.update import team_update_cmd
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(
|
||||||
|
"team",
|
||||||
|
commands=[
|
||||||
|
team_add_cmd,
|
||||||
|
team_create_cmd,
|
||||||
|
team_destroy_cmd,
|
||||||
|
team_list_cmd,
|
||||||
|
team_remove_cmd,
|
||||||
|
team_update_cmd,
|
||||||
|
],
|
||||||
|
short_help="Manage organization teams",
|
||||||
|
)
|
||||||
|
def cli():
|
||||||
|
pass
|
38
platformio/account/team/commands/add.py
Normal file
38
platformio/account/team/commands/add.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_orgname_teamname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("add", short_help="Add a new member to team")
|
||||||
|
@click.argument(
|
||||||
|
"orgname_teamname",
|
||||||
|
metavar="ORGNAME:TEAMNAME",
|
||||||
|
callback=lambda _, __, value: validate_orgname_teamname(value),
|
||||||
|
)
|
||||||
|
@click.argument(
|
||||||
|
"username",
|
||||||
|
)
|
||||||
|
def team_add_cmd(orgname_teamname, username):
|
||||||
|
orgname, teamname = orgname_teamname.split(":", 1)
|
||||||
|
client = AccountClient()
|
||||||
|
client.add_team_member(orgname, teamname, username)
|
||||||
|
return click.secho(
|
||||||
|
"The new member %s has been successfully added to the %s team."
|
||||||
|
% (username, teamname),
|
||||||
|
fg="green",
|
||||||
|
)
|
39
platformio/account/team/commands/create.py
Normal file
39
platformio/account/team/commands/create.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_orgname_teamname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("create", short_help="Create a new team")
|
||||||
|
@click.argument(
|
||||||
|
"orgname_teamname",
|
||||||
|
metavar="ORGNAME:TEAMNAME",
|
||||||
|
callback=lambda _, __, value: validate_orgname_teamname(
|
||||||
|
value, teamname_validate=True
|
||||||
|
),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--description",
|
||||||
|
)
|
||||||
|
def team_create_cmd(orgname_teamname, description):
|
||||||
|
orgname, teamname = orgname_teamname.split(":", 1)
|
||||||
|
client = AccountClient()
|
||||||
|
client.create_team(orgname, teamname, description)
|
||||||
|
return click.secho(
|
||||||
|
"The team %s has been successfully created." % teamname,
|
||||||
|
fg="green",
|
||||||
|
)
|
40
platformio/account/team/commands/destroy.py
Normal file
40
platformio/account/team/commands/destroy.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_orgname_teamname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("destroy", short_help="Destroy a team")
|
||||||
|
@click.argument(
|
||||||
|
"orgname_teamname",
|
||||||
|
metavar="ORGNAME:TEAMNAME",
|
||||||
|
callback=lambda _, __, value: validate_orgname_teamname(value),
|
||||||
|
)
|
||||||
|
def team_destroy_cmd(orgname_teamname):
|
||||||
|
orgname, teamname = orgname_teamname.split(":", 1)
|
||||||
|
click.confirm(
|
||||||
|
click.style(
|
||||||
|
"Are you sure you want to destroy the %s team?" % teamname, fg="yellow"
|
||||||
|
),
|
||||||
|
abort=True,
|
||||||
|
)
|
||||||
|
client = AccountClient()
|
||||||
|
client.destroy_team(orgname, teamname)
|
||||||
|
return click.secho(
|
||||||
|
"The team %s has been successfully destroyed." % teamname,
|
||||||
|
fg="green",
|
||||||
|
)
|
59
platformio/account/team/commands/list.py
Normal file
59
platformio/account/team/commands/list.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import click
|
||||||
|
from tabulate import tabulate
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("list", short_help="List teams")
|
||||||
|
@click.argument("orgname", required=False)
|
||||||
|
@click.option("--json-output", is_flag=True)
|
||||||
|
def team_list_cmd(orgname, json_output):
|
||||||
|
client = AccountClient()
|
||||||
|
data = {}
|
||||||
|
if not orgname:
|
||||||
|
for item in client.list_orgs():
|
||||||
|
teams = client.list_teams(item.get("orgname"))
|
||||||
|
data[item.get("orgname")] = teams
|
||||||
|
else:
|
||||||
|
teams = client.list_teams(orgname)
|
||||||
|
data[orgname] = teams
|
||||||
|
if json_output:
|
||||||
|
return click.echo(json.dumps(data[orgname] if orgname else data))
|
||||||
|
if not any(data.values()):
|
||||||
|
return click.secho("You do not have any teams.", fg="yellow")
|
||||||
|
for org_name in data:
|
||||||
|
for team in data[org_name]:
|
||||||
|
click.echo()
|
||||||
|
click.secho("%s:%s" % (org_name, team.get("name")), fg="cyan")
|
||||||
|
click.echo("-" * len("%s:%s" % (org_name, team.get("name"))))
|
||||||
|
table_data = []
|
||||||
|
if team.get("description"):
|
||||||
|
table_data.append(("Description:", team.get("description")))
|
||||||
|
table_data.append(
|
||||||
|
(
|
||||||
|
"Members:",
|
||||||
|
", ".join(
|
||||||
|
(member.get("username") for member in team.get("members"))
|
||||||
|
)
|
||||||
|
if team.get("members")
|
||||||
|
else "-",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
click.echo(tabulate(table_data, tablefmt="plain"))
|
||||||
|
return click.echo()
|
36
platformio/account/team/commands/remove.py
Normal file
36
platformio/account/team/commands/remove.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_orgname_teamname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("remove", short_help="Remove a member from team")
|
||||||
|
@click.argument(
|
||||||
|
"orgname_teamname",
|
||||||
|
metavar="ORGNAME:TEAMNAME",
|
||||||
|
callback=lambda _, __, value: validate_orgname_teamname(value),
|
||||||
|
)
|
||||||
|
@click.argument("username")
|
||||||
|
def team_remove_cmd(orgname_teamname, username):
|
||||||
|
orgname, teamname = orgname_teamname.split(":", 1)
|
||||||
|
client = AccountClient()
|
||||||
|
client.remove_team_member(orgname, teamname, username)
|
||||||
|
return click.secho(
|
||||||
|
"The %s member has been successfully removed from the %s team."
|
||||||
|
% (username, teamname),
|
||||||
|
fg="green",
|
||||||
|
)
|
55
platformio/account/team/commands/update.py
Normal file
55
platformio/account/team/commands/update.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio.account.client import AccountClient
|
||||||
|
from platformio.account.validate import validate_orgname_teamname, validate_teamname
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("update", short_help="Update team")
|
||||||
|
@click.argument(
|
||||||
|
"orgname_teamname",
|
||||||
|
metavar="ORGNAME:TEAMNAME",
|
||||||
|
callback=lambda _, __, value: validate_orgname_teamname(value),
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--name",
|
||||||
|
callback=lambda _, __, value: validate_teamname(value),
|
||||||
|
help="A new team name",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--description",
|
||||||
|
)
|
||||||
|
def team_update_cmd(orgname_teamname, **kwargs):
|
||||||
|
orgname, teamname = orgname_teamname.split(":", 1)
|
||||||
|
client = AccountClient()
|
||||||
|
team = client.get_team(orgname, teamname)
|
||||||
|
del team["id"]
|
||||||
|
del team["members"]
|
||||||
|
new_team = team.copy()
|
||||||
|
if not any(kwargs.values()):
|
||||||
|
for field in team:
|
||||||
|
new_team[field] = click.prompt(
|
||||||
|
field.replace("_", " ").capitalize(), default=team[field]
|
||||||
|
)
|
||||||
|
if field == "name":
|
||||||
|
validate_teamname(new_team[field])
|
||||||
|
else:
|
||||||
|
new_team.update({key: value for key, value in kwargs.items() if value})
|
||||||
|
client.update_team(orgname, teamname, new_team)
|
||||||
|
return click.secho(
|
||||||
|
"The team %s has been successfully updated." % teamname,
|
||||||
|
fg="green",
|
||||||
|
)
|
79
platformio/account/validate.py
Normal file
79
platformio/account/validate.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
|
||||||
|
def validate_username(value, field="username"):
|
||||||
|
value = str(value).strip()
|
||||||
|
if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,37}$", value, flags=re.I):
|
||||||
|
raise click.BadParameter(
|
||||||
|
"Invalid %s format. "
|
||||||
|
"%s must contain only alphanumeric characters "
|
||||||
|
"or single hyphens, cannot begin or end with a hyphen, "
|
||||||
|
"and must not be longer than 38 characters."
|
||||||
|
% (field.lower(), field.capitalize())
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_email(value):
|
||||||
|
value = str(value).strip()
|
||||||
|
if not re.match(r"^[a-z\d_.+-]+@[a-z\d\-]+\.[a-z\d\-.]+$", value, flags=re.I):
|
||||||
|
raise click.BadParameter("Invalid email address")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_password(value):
|
||||||
|
value = str(value).strip()
|
||||||
|
if not re.match(r"^(?=.*[a-z])(?=.*\d).{8,}$", value):
|
||||||
|
raise click.BadParameter(
|
||||||
|
"Invalid password format. "
|
||||||
|
"Password must contain at least 8 characters"
|
||||||
|
" including a number and a lowercase letter"
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_orgname(value):
|
||||||
|
return validate_username(value, "Organization name")
|
||||||
|
|
||||||
|
|
||||||
|
def validate_orgname_teamname(value, teamname_validate=False):
|
||||||
|
if ":" not in value:
|
||||||
|
raise click.BadParameter(
|
||||||
|
"Please specify organization and team name in the next"
|
||||||
|
" format - orgname:teamname. For example, mycompany:DreamTeam"
|
||||||
|
)
|
||||||
|
teamname = str(value.strip().split(":", 1)[1])
|
||||||
|
if teamname_validate:
|
||||||
|
validate_teamname(teamname)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_teamname(value):
|
||||||
|
if not value:
|
||||||
|
return value
|
||||||
|
value = str(value).strip()
|
||||||
|
if not re.match(r"^[a-z\d](?:[a-z\d]|[\-_ ](?=[a-z\d])){0,19}$", value, flags=re.I):
|
||||||
|
raise click.BadParameter(
|
||||||
|
"Invalid team name format. "
|
||||||
|
"Team name must only contain alphanumeric characters, "
|
||||||
|
"single hyphens, underscores, spaces. It can not "
|
||||||
|
"begin or end with a hyphen or a underscore and must"
|
||||||
|
" not be longer than 20 characters."
|
||||||
|
)
|
||||||
|
return value
|
@ -225,7 +225,7 @@ if "envdump" in COMMAND_LINE_TARGETS:
|
|||||||
click.echo(env.Dump())
|
click.echo(env.Dump())
|
||||||
env.Exit(0)
|
env.Exit(0)
|
||||||
|
|
||||||
if set(["_idedata", "idedata"]) & set(COMMAND_LINE_TARGETS):
|
if env.IsIntegrationDump():
|
||||||
projenv = None
|
projenv = None
|
||||||
try:
|
try:
|
||||||
Import("projenv")
|
Import("projenv")
|
||||||
|
@ -225,11 +225,15 @@ class InoToCPPConverter(object):
|
|||||||
return "\n".join(result)
|
return "\n".join(result)
|
||||||
|
|
||||||
|
|
||||||
def ConvertInoToCpp(env):
|
def FindInoNodes(env):
|
||||||
src_dir = glob.escape(env.subst("$PROJECT_SRC_DIR"))
|
src_dir = glob.escape(env.subst("$PROJECT_SRC_DIR"))
|
||||||
ino_nodes = env.Glob(os.path.join(src_dir, "*.ino")) + env.Glob(
|
return env.Glob(os.path.join(src_dir, "*.ino")) + env.Glob(
|
||||||
os.path.join(src_dir, "*.pde")
|
os.path.join(src_dir, "*.pde")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def ConvertInoToCpp(env):
|
||||||
|
ino_nodes = env.FindInoNodes()
|
||||||
if not ino_nodes:
|
if not ino_nodes:
|
||||||
return
|
return
|
||||||
c = InoToCPPConverter(env)
|
c = InoToCPPConverter(env)
|
||||||
@ -247,6 +251,7 @@ def _delete_file(path):
|
|||||||
|
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
|
env.AddMethod(FindInoNodes)
|
||||||
env.AddMethod(ConvertInoToCpp)
|
env.AddMethod(ConvertInoToCpp)
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,10 +19,15 @@ import os
|
|||||||
|
|
||||||
import SCons.Defaults # pylint: disable=import-error
|
import SCons.Defaults # pylint: disable=import-error
|
||||||
import SCons.Subst # pylint: disable=import-error
|
import SCons.Subst # pylint: disable=import-error
|
||||||
|
from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error
|
||||||
|
|
||||||
from platformio.proc import exec_command, where_is_program
|
from platformio.proc import exec_command, where_is_program
|
||||||
|
|
||||||
|
|
||||||
|
def IsIntegrationDump(_):
|
||||||
|
return set(["_idedata", "idedata"]) & set(COMMAND_LINE_TARGETS)
|
||||||
|
|
||||||
|
|
||||||
def DumpIntegrationIncludes(env):
|
def DumpIntegrationIncludes(env):
|
||||||
result = dict(build=[], compatlib=[], toolchain=[])
|
result = dict(build=[], compatlib=[], toolchain=[])
|
||||||
|
|
||||||
@ -60,7 +65,7 @@ def DumpIntegrationIncludes(env):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _get_gcc_defines(env):
|
def get_gcc_defines(env):
|
||||||
items = []
|
items = []
|
||||||
try:
|
try:
|
||||||
sysenv = os.environ.copy()
|
sysenv = os.environ.copy()
|
||||||
@ -83,7 +88,7 @@ def _get_gcc_defines(env):
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
def _dump_defines(env):
|
def dump_defines(env):
|
||||||
defines = []
|
defines = []
|
||||||
# global symbols
|
# global symbols
|
||||||
for item in SCons.Defaults.processDefines(env.get("CPPDEFINES", [])):
|
for item in SCons.Defaults.processDefines(env.get("CPPDEFINES", [])):
|
||||||
@ -108,12 +113,12 @@ def _dump_defines(env):
|
|||||||
|
|
||||||
# built-in GCC marcos
|
# built-in GCC marcos
|
||||||
# if env.GetCompilerType() == "gcc":
|
# if env.GetCompilerType() == "gcc":
|
||||||
# defines.extend(_get_gcc_defines(env))
|
# defines.extend(get_gcc_defines(env))
|
||||||
|
|
||||||
return defines
|
return defines
|
||||||
|
|
||||||
|
|
||||||
def _get_svd_path(env):
|
def dump_svd_path(env):
|
||||||
svd_path = env.GetProjectOption("debug_svd_path")
|
svd_path = env.GetProjectOption("debug_svd_path")
|
||||||
if svd_path:
|
if svd_path:
|
||||||
return os.path.abspath(svd_path)
|
return os.path.abspath(svd_path)
|
||||||
@ -146,13 +151,13 @@ def DumpIntegrationData(env, globalenv):
|
|||||||
data = {
|
data = {
|
||||||
"env_name": env["PIOENV"],
|
"env_name": env["PIOENV"],
|
||||||
"libsource_dirs": [env.subst(item) for item in env.GetLibSourceDirs()],
|
"libsource_dirs": [env.subst(item) for item in env.GetLibSourceDirs()],
|
||||||
"defines": _dump_defines(env),
|
"defines": dump_defines(env),
|
||||||
"includes": env.DumpIntegrationIncludes(),
|
"includes": env.DumpIntegrationIncludes(),
|
||||||
"cc_path": where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")),
|
"cc_path": where_is_program(env.subst("$CC"), env.subst("${ENV['PATH']}")),
|
||||||
"cxx_path": where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")),
|
"cxx_path": where_is_program(env.subst("$CXX"), env.subst("${ENV['PATH']}")),
|
||||||
"gdb_path": where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")),
|
"gdb_path": where_is_program(env.subst("$GDB"), env.subst("${ENV['PATH']}")),
|
||||||
"prog_path": env.subst("$PROG_PATH"),
|
"prog_path": env.subst("$PROG_PATH"),
|
||||||
"svd_path": _get_svd_path(env),
|
"svd_path": dump_svd_path(env),
|
||||||
"compiler_type": env.GetCompilerType(),
|
"compiler_type": env.GetCompilerType(),
|
||||||
"targets": globalenv.DumpTargets(),
|
"targets": globalenv.DumpTargets(),
|
||||||
"extra": dict(
|
"extra": dict(
|
||||||
@ -162,7 +167,9 @@ def DumpIntegrationData(env, globalenv):
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
data["extra"].update(env.get("IDE_EXTRA_DATA", {}))
|
data["extra"].update(
|
||||||
|
env.get("INTEGRATION_EXTRA_DATA", env.get("IDE_EXTRA_DATA", {}))
|
||||||
|
)
|
||||||
|
|
||||||
env_ = env.Clone()
|
env_ = env.Clone()
|
||||||
# https://github.com/platformio/platformio-atom-ide/issues/34
|
# https://github.com/platformio/platformio-atom-ide/issues/34
|
||||||
@ -191,6 +198,7 @@ def exists(_):
|
|||||||
|
|
||||||
|
|
||||||
def generate(env):
|
def generate(env):
|
||||||
|
env.AddMethod(IsIntegrationDump)
|
||||||
env.AddMethod(DumpIntegrationIncludes)
|
env.AddMethod(DumpIntegrationIncludes)
|
||||||
env.AddMethod(DumpIntegrationData)
|
env.AddMethod(DumpIntegrationData)
|
||||||
return env
|
return env
|
||||||
|
@ -31,8 +31,8 @@ from SCons.Script import DefaultEnvironment # pylint: disable=import-error
|
|||||||
|
|
||||||
from platformio import exception, fs, util
|
from platformio import exception, fs, util
|
||||||
from platformio.builder.tools import platformio as piotool
|
from platformio.builder.tools import platformio as piotool
|
||||||
from platformio.clients.http import HTTPClientError, InternetIsOffline
|
|
||||||
from platformio.compat import IS_WINDOWS, hashlib_encode_data, string_types
|
from platformio.compat import IS_WINDOWS, hashlib_encode_data, string_types
|
||||||
|
from platformio.http import HTTPClientError, InternetIsOffline
|
||||||
from platformio.package.exception import (
|
from platformio.package.exception import (
|
||||||
MissingPackageManifestError,
|
MissingPackageManifestError,
|
||||||
UnknownPackageError,
|
UnknownPackageError,
|
||||||
@ -60,16 +60,16 @@ class LibBuilderFactory(object):
|
|||||||
elif used_frameworks:
|
elif used_frameworks:
|
||||||
clsname = "%sLibBuilder" % used_frameworks[0].capitalize()
|
clsname = "%sLibBuilder" % used_frameworks[0].capitalize()
|
||||||
|
|
||||||
obj = getattr(sys.modules[__name__], clsname)(env, path, verbose=verbose)
|
obj = globals()[clsname](env, path, verbose=verbose)
|
||||||
|
|
||||||
# Handle PlatformIOLibBuilder.manifest.build.builder
|
# Handle PlatformIOLibBuilder.manifest.build.builder
|
||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
if isinstance(obj, PlatformIOLibBuilder) and obj._manifest.get("build", {}).get(
|
if isinstance(obj, PlatformIOLibBuilder) and obj._manifest.get("build", {}).get(
|
||||||
"builder"
|
"builder"
|
||||||
):
|
):
|
||||||
obj = getattr(
|
obj = globals()[obj._manifest.get("build", {}).get("builder")](
|
||||||
sys.modules[__name__], obj._manifest.get("build", {}).get("builder")
|
env, path, verbose=verbose
|
||||||
)(env, path, verbose=verbose)
|
)
|
||||||
|
|
||||||
assert isinstance(obj, LibBuilderBase)
|
assert isinstance(obj, LibBuilderBase)
|
||||||
return obj
|
return obj
|
||||||
@ -111,7 +111,7 @@ class LibBuilderFactory(object):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
class LibBuilderBase(object):
|
class LibBuilderBase:
|
||||||
|
|
||||||
CLASSIC_SCANNER = SCons.Scanner.C.CScanner()
|
CLASSIC_SCANNER = SCons.Scanner.C.CScanner()
|
||||||
CCONDITIONAL_SCANNER = SCons.Scanner.C.CConditionalScanner()
|
CCONDITIONAL_SCANNER = SCons.Scanner.C.CConditionalScanner()
|
||||||
@ -453,11 +453,17 @@ class LibBuilderBase(object):
|
|||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
libs = []
|
libs = []
|
||||||
|
shared_scopes = ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS")
|
||||||
for lb in self.depbuilders:
|
for lb in self.depbuilders:
|
||||||
libs.extend(lb.build())
|
libs.extend(lb.build())
|
||||||
# copy shared information to self env
|
# copy shared information to self env
|
||||||
for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"):
|
self.env.PrependUnique(
|
||||||
self.env.PrependUnique(**{key: lb.env.get(key)})
|
**{
|
||||||
|
scope: lb.env.get(scope)
|
||||||
|
for scope in shared_scopes
|
||||||
|
if lb.env.get(scope)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
for lb in self._circular_deps:
|
for lb in self._circular_deps:
|
||||||
self.env.PrependUnique(CPPPATH=lb.get_include_dirs())
|
self.env.PrependUnique(CPPPATH=lb.get_include_dirs())
|
||||||
@ -472,8 +478,13 @@ class LibBuilderBase(object):
|
|||||||
for lb in self.env.GetLibBuilders():
|
for lb in self.env.GetLibBuilders():
|
||||||
if self == lb or not lb.is_built:
|
if self == lb or not lb.is_built:
|
||||||
continue
|
continue
|
||||||
for key in ("CPPPATH", "LIBPATH", "LIBS", "LINKFLAGS"):
|
self.env.PrependUnique(
|
||||||
self.env.PrependUnique(**{key: lb.env.get(key)})
|
**{
|
||||||
|
scope: lb.env.get(scope)
|
||||||
|
for scope in shared_scopes
|
||||||
|
if lb.env.get(scope)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
do_not_archive = not self.lib_archive
|
do_not_archive = not self.lib_archive
|
||||||
if not do_not_archive:
|
if not do_not_archive:
|
||||||
@ -514,7 +525,7 @@ class ArduinoLibBuilder(LibBuilderBase):
|
|||||||
return os.path.join(self.path, "include")
|
return os.path.join(self.path, "include")
|
||||||
|
|
||||||
def get_include_dirs(self):
|
def get_include_dirs(self):
|
||||||
include_dirs = LibBuilderBase.get_include_dirs(self)
|
include_dirs = super().get_include_dirs()
|
||||||
if os.path.isdir(os.path.join(self.path, "src")):
|
if os.path.isdir(os.path.join(self.path, "src")):
|
||||||
return include_dirs
|
return include_dirs
|
||||||
if os.path.isdir(os.path.join(self.path, "utility")):
|
if os.path.isdir(os.path.join(self.path, "utility")):
|
||||||
@ -612,7 +623,7 @@ class MbedLibBuilder(LibBuilderBase):
|
|||||||
return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member
|
return LibBuilderBase.src_dir.fget(self) # pylint: disable=no-member
|
||||||
|
|
||||||
def get_include_dirs(self):
|
def get_include_dirs(self):
|
||||||
include_dirs = LibBuilderBase.get_include_dirs(self)
|
include_dirs = super().get_include_dirs()
|
||||||
if self.path not in include_dirs:
|
if self.path not in include_dirs:
|
||||||
include_dirs.append(self.path)
|
include_dirs.append(self.path)
|
||||||
|
|
||||||
@ -833,7 +844,7 @@ class PlatformIOLibBuilder(LibBuilderBase):
|
|||||||
return util.items_in_list(frameworks, self._manifest.get("frameworks") or ["*"])
|
return util.items_in_list(frameworks, self._manifest.get("frameworks") or ["*"])
|
||||||
|
|
||||||
def get_include_dirs(self):
|
def get_include_dirs(self):
|
||||||
include_dirs = LibBuilderBase.get_include_dirs(self)
|
include_dirs = super().get_include_dirs()
|
||||||
|
|
||||||
# backwards compatibility with PlatformIO 2.0
|
# backwards compatibility with PlatformIO 2.0
|
||||||
if (
|
if (
|
||||||
@ -872,14 +883,14 @@ class ProjectAsLibBuilder(LibBuilderBase):
|
|||||||
project_include_dir = self.env.subst("$PROJECT_INCLUDE_DIR")
|
project_include_dir = self.env.subst("$PROJECT_INCLUDE_DIR")
|
||||||
if os.path.isdir(project_include_dir):
|
if os.path.isdir(project_include_dir):
|
||||||
include_dirs.append(project_include_dir)
|
include_dirs.append(project_include_dir)
|
||||||
for include_dir in LibBuilderBase.get_include_dirs(self):
|
for include_dir in super().get_include_dirs():
|
||||||
if include_dir not in include_dirs:
|
if include_dir not in include_dirs:
|
||||||
include_dirs.append(include_dir)
|
include_dirs.append(include_dir)
|
||||||
return include_dirs
|
return include_dirs
|
||||||
|
|
||||||
def get_search_files(self):
|
def get_search_files(self):
|
||||||
# project files
|
# project files
|
||||||
items = LibBuilderBase.get_search_files(self)
|
items = super().get_search_files()
|
||||||
# test files
|
# test files
|
||||||
if "test" in self.env.GetBuildType():
|
if "test" in self.env.GetBuildType():
|
||||||
items.extend(
|
items.extend(
|
||||||
@ -994,7 +1005,7 @@ class ProjectAsLibBuilder(LibBuilderBase):
|
|||||||
|
|
||||||
def build(self):
|
def build(self):
|
||||||
self.is_built = True # do not build Project now
|
self.is_built = True # do not build Project now
|
||||||
result = LibBuilderBase.build(self)
|
result = super().build()
|
||||||
self.env.PrependUnique(CPPPATH=self.get_include_dirs())
|
self.env.PrependUnique(CPPPATH=self.get_include_dirs())
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@ -1027,14 +1038,15 @@ def IsCompatibleLibBuilder(env, lb, verbose=int(ARGUMENTS.get("PIOVERBOSE", 0)))
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def GetLibBuilders(env): # pylint: disable=too-many-branches
|
def GetLibBuilders(_): # pylint: disable=too-many-branches
|
||||||
if DefaultEnvironment().get("__PIO_LIB_BUILDERS", None) is not None:
|
env = DefaultEnvironment()
|
||||||
|
if env.get("__PIO_LIB_BUILDERS", None) is not None:
|
||||||
return sorted(
|
return sorted(
|
||||||
DefaultEnvironment()["__PIO_LIB_BUILDERS"],
|
env["__PIO_LIB_BUILDERS"],
|
||||||
key=lambda lb: 0 if lb.is_dependent else 1,
|
key=lambda lb: 0 if lb.is_dependent else 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
DefaultEnvironment().Replace(__PIO_LIB_BUILDERS=[])
|
env.Replace(__PIO_LIB_BUILDERS=[])
|
||||||
|
|
||||||
verbose = int(ARGUMENTS.get("PIOVERBOSE", 0))
|
verbose = int(ARGUMENTS.get("PIOVERBOSE", 0))
|
||||||
found_incompat = False
|
found_incompat = False
|
||||||
@ -1060,13 +1072,13 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
|||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
if env.IsCompatibleLibBuilder(lb):
|
if env.IsCompatibleLibBuilder(lb):
|
||||||
DefaultEnvironment().Append(__PIO_LIB_BUILDERS=[lb])
|
env.Append(__PIO_LIB_BUILDERS=[lb])
|
||||||
else:
|
else:
|
||||||
found_incompat = True
|
found_incompat = True
|
||||||
|
|
||||||
for lb in env.get("EXTRA_LIB_BUILDERS", []):
|
for lb in env.get("EXTRA_LIB_BUILDERS", []):
|
||||||
if env.IsCompatibleLibBuilder(lb):
|
if env.IsCompatibleLibBuilder(lb):
|
||||||
DefaultEnvironment().Append(__PIO_LIB_BUILDERS=[lb])
|
env.Append(__PIO_LIB_BUILDERS=[lb])
|
||||||
else:
|
else:
|
||||||
found_incompat = True
|
found_incompat = True
|
||||||
|
|
||||||
@ -1077,7 +1089,7 @@ def GetLibBuilders(env): # pylint: disable=too-many-branches
|
|||||||
"ldf-compat-mode\n"
|
"ldf-compat-mode\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
return DefaultEnvironment()["__PIO_LIB_BUILDERS"]
|
return env["__PIO_LIB_BUILDERS"]
|
||||||
|
|
||||||
|
|
||||||
def ConfigureProjectLibBuilder(env):
|
def ConfigureProjectLibBuilder(env):
|
||||||
|
@ -114,7 +114,15 @@ def ConfigureDebugTarget(env):
|
|||||||
]
|
]
|
||||||
|
|
||||||
if optimization_flags:
|
if optimization_flags:
|
||||||
env.AppendUnique(ASFLAGS=optimization_flags, LINKFLAGS=optimization_flags)
|
env.AppendUnique(
|
||||||
|
ASFLAGS=[
|
||||||
|
# skip -O flags for assembler
|
||||||
|
f
|
||||||
|
for f in optimization_flags
|
||||||
|
if f.startswith("-g")
|
||||||
|
],
|
||||||
|
LINKFLAGS=optimization_flags,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def GetExtraScripts(env, scope):
|
def GetExtraScripts(env, scope):
|
||||||
|
@ -143,6 +143,7 @@ def ProcessProgramDeps(env):
|
|||||||
|
|
||||||
def ProcessProjectDeps(env):
|
def ProcessProjectDeps(env):
|
||||||
project_lib_builder = env.ConfigureProjectLibBuilder()
|
project_lib_builder = env.ConfigureProjectLibBuilder()
|
||||||
|
projenv = project_lib_builder.env
|
||||||
|
|
||||||
# prepend project libs to the beginning of list
|
# prepend project libs to the beginning of list
|
||||||
env.Prepend(LIBS=project_lib_builder.build())
|
env.Prepend(LIBS=project_lib_builder.build())
|
||||||
@ -155,17 +156,18 @@ def ProcessProjectDeps(env):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
projenv = env.Clone()
|
|
||||||
|
|
||||||
# CPPPATH from dependencies
|
|
||||||
projenv.PrependUnique(CPPPATH=project_lib_builder.env.get("CPPPATH"))
|
|
||||||
# extra build flags from `platformio.ini`
|
|
||||||
projenv.ProcessFlags(env.get("SRC_BUILD_FLAGS"))
|
|
||||||
|
|
||||||
if "test" in env.GetBuildType():
|
if "test" in env.GetBuildType():
|
||||||
|
build_files_before_nums = len(env.get("PIOBUILDFILES", []))
|
||||||
projenv.BuildSources(
|
projenv.BuildSources(
|
||||||
"$BUILD_TEST_DIR", "$PROJECT_TEST_DIR", "$PIOTEST_SRC_FILTER"
|
"$BUILD_TEST_DIR", "$PROJECT_TEST_DIR", "$PIOTEST_SRC_FILTER"
|
||||||
)
|
)
|
||||||
|
if len(env.get("PIOBUILDFILES", [])) - build_files_before_nums < 1:
|
||||||
|
sys.stderr.write(
|
||||||
|
"Error: Nothing to build. Please put your test suites "
|
||||||
|
"to the '%s' folder\n" % env.subst("$PROJECT_TEST_DIR")
|
||||||
|
)
|
||||||
|
env.Exit(1)
|
||||||
|
|
||||||
if "test" not in env.GetBuildType() or env.GetProjectOption("test_build_src"):
|
if "test" not in env.GetBuildType() or env.GetProjectOption("test_build_src"):
|
||||||
projenv.BuildSources(
|
projenv.BuildSources(
|
||||||
"$BUILD_SRC_DIR", "$PROJECT_SRC_DIR", env.get("SRC_FILTER")
|
"$BUILD_SRC_DIR", "$PROJECT_SRC_DIR", env.get("SRC_FILTER")
|
||||||
@ -174,7 +176,7 @@ def ProcessProjectDeps(env):
|
|||||||
if not env.get("PIOBUILDFILES") and not COMMAND_LINE_TARGETS:
|
if not env.get("PIOBUILDFILES") and not COMMAND_LINE_TARGETS:
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
"Error: Nothing to build. Please put your source code files "
|
"Error: Nothing to build. Please put your source code files "
|
||||||
"to '%s' folder\n" % env.subst("$PROJECT_SRC_DIR")
|
"to the '%s' folder\n" % env.subst("$PROJECT_SRC_DIR")
|
||||||
)
|
)
|
||||||
env.Exit(1)
|
env.Exit(1)
|
||||||
|
|
||||||
@ -327,25 +329,18 @@ def BuildFrameworks(env, frameworks):
|
|||||||
)
|
)
|
||||||
env.Exit(1)
|
env.Exit(1)
|
||||||
|
|
||||||
board_frameworks = env.BoardConfig().get("frameworks", [])
|
supported_frameworks = env.BoardConfig().get("frameworks", [])
|
||||||
if frameworks == ["platformio"]:
|
for name in frameworks:
|
||||||
if board_frameworks:
|
if name == "arduino":
|
||||||
frameworks.insert(0, board_frameworks[0])
|
# Arduino IDE appends .o to the end of filename
|
||||||
else:
|
|
||||||
sys.stderr.write("Error: Please specify `board` in `platformio.ini`\n")
|
|
||||||
env.Exit(1)
|
|
||||||
|
|
||||||
for f in frameworks:
|
|
||||||
if f == "arduino":
|
|
||||||
# Arduino IDE appends .o the end of filename
|
|
||||||
Builder.match_splitext = scons_patched_match_splitext
|
Builder.match_splitext = scons_patched_match_splitext
|
||||||
if "nobuild" not in COMMAND_LINE_TARGETS:
|
if "nobuild" not in COMMAND_LINE_TARGETS:
|
||||||
env.ConvertInoToCpp()
|
env.ConvertInoToCpp()
|
||||||
|
|
||||||
if f in board_frameworks:
|
if name in supported_frameworks:
|
||||||
SConscript(env.GetFrameworkScript(f), exports="env")
|
SConscript(env.GetFrameworkScript(name), exports="env")
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("Error: This board doesn't support %s framework!\n" % f)
|
sys.stderr.write("Error: This board doesn't support %s framework!\n" % name)
|
||||||
env.Exit(1)
|
env.Exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ import click
|
|||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from platformio import app, exception, fs, util
|
from platformio import app, exception, fs, util
|
||||||
from platformio.commands.check.defect import DefectItem
|
from platformio.check.defect import DefectItem
|
||||||
from platformio.commands.check.tools import CheckToolFactory
|
from platformio.check.tools import CheckToolFactory
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
from platformio.project.helpers import find_project_dir_above, get_project_dir
|
from platformio.project.helpers import find_project_dir_above, get_project_dir
|
||||||
|
|
@ -13,9 +13,9 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from platformio import exception
|
from platformio import exception
|
||||||
from platformio.commands.check.tools.clangtidy import ClangtidyCheckTool
|
from platformio.check.tools.clangtidy import ClangtidyCheckTool
|
||||||
from platformio.commands.check.tools.cppcheck import CppcheckCheckTool
|
from platformio.check.tools.cppcheck import CppcheckCheckTool
|
||||||
from platformio.commands.check.tools.pvsstudio import PvsStudioCheckTool
|
from platformio.check.tools.pvsstudio import PvsStudioCheckTool
|
||||||
|
|
||||||
|
|
||||||
class CheckToolFactory(object):
|
class CheckToolFactory(object):
|
@ -19,7 +19,7 @@ import tempfile
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import fs, proc
|
from platformio import fs, proc
|
||||||
from platformio.commands.check.defect import DefectItem
|
from platformio.check.defect import DefectItem
|
||||||
from platformio.package.manager.core import get_core_package_dir
|
from platformio.package.manager.core import get_core_package_dir
|
||||||
from platformio.package.meta import PackageSpec
|
from platformio.package.meta import PackageSpec
|
||||||
from platformio.project.helpers import load_build_metadata
|
from platformio.project.helpers import load_build_metadata
|
@ -15,8 +15,8 @@
|
|||||||
import re
|
import re
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
from platformio.commands.check.defect import DefectItem
|
from platformio.check.defect import DefectItem
|
||||||
from platformio.commands.check.tools.base import CheckToolBase
|
from platformio.check.tools.base import CheckToolBase
|
||||||
|
|
||||||
|
|
||||||
class ClangtidyCheckTool(CheckToolBase):
|
class ClangtidyCheckTool(CheckToolBase):
|
@ -17,8 +17,8 @@ import os
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import proc
|
from platformio import proc
|
||||||
from platformio.commands.check.defect import DefectItem
|
from platformio.check.defect import DefectItem
|
||||||
from platformio.commands.check.tools.base import CheckToolBase
|
from platformio.check.tools.base import CheckToolBase
|
||||||
|
|
||||||
|
|
||||||
class CppcheckCheckTool(CheckToolBase):
|
class CppcheckCheckTool(CheckToolBase):
|
@ -20,8 +20,8 @@ from xml.etree.ElementTree import fromstring
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import proc
|
from platformio import proc
|
||||||
from platformio.commands.check.defect import DefectItem
|
from platformio.check.defect import DefectItem
|
||||||
from platformio.commands.check.tools.base import CheckToolBase
|
from platformio.check.tools.base import CheckToolBase
|
||||||
from platformio.compat import IS_WINDOWS
|
from platformio.compat import IS_WINDOWS
|
||||||
|
|
||||||
|
|
96
platformio/cli.py
Normal file
96
platformio/cli.py
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformioCLI(click.MultiCommand):
|
||||||
|
|
||||||
|
leftover_args = []
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self._pio_root_path = Path(__file__).parent
|
||||||
|
self._pio_cmd_aliases = dict(package="pkg")
|
||||||
|
|
||||||
|
def _find_pio_commands(self):
|
||||||
|
def _to_module_path(p):
|
||||||
|
return (
|
||||||
|
"platformio." + ".".join(p.relative_to(self._pio_root_path).parts)[:-3]
|
||||||
|
)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
for p in self._pio_root_path.rglob("cli.py"):
|
||||||
|
# skip this module
|
||||||
|
if p.parent == self._pio_root_path:
|
||||||
|
continue
|
||||||
|
cmd_name = p.parent.name
|
||||||
|
result[self._pio_cmd_aliases.get(cmd_name, cmd_name)] = _to_module_path(p)
|
||||||
|
|
||||||
|
# find legacy commands
|
||||||
|
for p in (self._pio_root_path / "commands").iterdir():
|
||||||
|
if p.name.startswith("_"):
|
||||||
|
continue
|
||||||
|
if (p / "command.py").is_file():
|
||||||
|
result[p.name] = _to_module_path(p / "command.py")
|
||||||
|
elif p.name.endswith(".py"):
|
||||||
|
result[p.name[:-3]] = _to_module_path(p)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def in_silence():
|
||||||
|
args = PlatformioCLI.leftover_args
|
||||||
|
return args and any(
|
||||||
|
[
|
||||||
|
args[0] == "debug" and "--interpreter" in " ".join(args),
|
||||||
|
args[0] == "upgrade",
|
||||||
|
"--json-output" in args,
|
||||||
|
"--version" in args,
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def invoke(self, ctx):
|
||||||
|
PlatformioCLI.leftover_args = ctx.args
|
||||||
|
if hasattr(ctx, "protected_args"):
|
||||||
|
PlatformioCLI.leftover_args = ctx.protected_args + ctx.args
|
||||||
|
return super().invoke(ctx)
|
||||||
|
|
||||||
|
def list_commands(self, ctx):
|
||||||
|
return sorted(list(self._find_pio_commands()))
|
||||||
|
|
||||||
|
def get_command(self, ctx, cmd_name):
|
||||||
|
commands = self._find_pio_commands()
|
||||||
|
if cmd_name not in commands:
|
||||||
|
return self._handle_obsolate_command(ctx, cmd_name)
|
||||||
|
module = importlib.import_module(commands[cmd_name])
|
||||||
|
return getattr(module, "cli")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _handle_obsolate_command(ctx, cmd_name):
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
if cmd_name == "init":
|
||||||
|
from platformio.project.commands.init import project_init_cmd
|
||||||
|
|
||||||
|
return project_init_cmd
|
||||||
|
|
||||||
|
if cmd_name == "package":
|
||||||
|
from platformio.package.cli import cli
|
||||||
|
|
||||||
|
return cli
|
||||||
|
|
||||||
|
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
|
@ -11,76 +11,3 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
import click
|
|
||||||
|
|
||||||
|
|
||||||
class PlatformioCLI(click.MultiCommand):
|
|
||||||
|
|
||||||
leftover_args = []
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self._pio_cmds_dir = os.path.dirname(__file__)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def in_silence():
|
|
||||||
args = PlatformioCLI.leftover_args
|
|
||||||
return args and any(
|
|
||||||
[
|
|
||||||
args[0] == "debug" and "--interpreter" in " ".join(args),
|
|
||||||
args[0] == "upgrade",
|
|
||||||
"--json-output" in args,
|
|
||||||
"--version" in args,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
def invoke(self, ctx):
|
|
||||||
PlatformioCLI.leftover_args = ctx.args
|
|
||||||
if hasattr(ctx, "protected_args"):
|
|
||||||
PlatformioCLI.leftover_args = ctx.protected_args + ctx.args
|
|
||||||
return super().invoke(ctx)
|
|
||||||
|
|
||||||
def list_commands(self, ctx):
|
|
||||||
cmds = []
|
|
||||||
for cmd_name in os.listdir(self._pio_cmds_dir):
|
|
||||||
if cmd_name.startswith("__init__"):
|
|
||||||
continue
|
|
||||||
if os.path.isfile(os.path.join(self._pio_cmds_dir, cmd_name, "command.py")):
|
|
||||||
cmds.append(cmd_name)
|
|
||||||
elif cmd_name.endswith(".py"):
|
|
||||||
cmds.append(cmd_name[:-3])
|
|
||||||
cmds.sort()
|
|
||||||
return cmds
|
|
||||||
|
|
||||||
def get_command(self, ctx, cmd_name):
|
|
||||||
mod = None
|
|
||||||
try:
|
|
||||||
mod_path = "platformio.commands." + cmd_name
|
|
||||||
if os.path.isfile(os.path.join(self._pio_cmds_dir, cmd_name, "command.py")):
|
|
||||||
mod_path = "platformio.commands.%s.command" % cmd_name
|
|
||||||
mod = __import__(mod_path, None, None, ["cli"])
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
return self._handle_obsolate_command(cmd_name)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
raise click.UsageError('No such command "%s"' % cmd_name, ctx)
|
|
||||||
return mod.cli
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _handle_obsolate_command(name):
|
|
||||||
# pylint: disable=import-outside-toplevel
|
|
||||||
if name == "init":
|
|
||||||
from platformio.project.commands.init import project_init_cmd
|
|
||||||
|
|
||||||
return project_init_cmd
|
|
||||||
|
|
||||||
if name == "package":
|
|
||||||
from platformio.commands.pkg import cli
|
|
||||||
|
|
||||||
return cli
|
|
||||||
|
|
||||||
raise AttributeError()
|
|
||||||
|
@ -1,154 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
import click
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio.clients.registry import RegistryClient
|
|
||||||
from platformio.commands.account import validate_username
|
|
||||||
from platformio.commands.team import validate_orgname_teamname
|
|
||||||
|
|
||||||
|
|
||||||
def validate_client(value):
|
|
||||||
if ":" in value:
|
|
||||||
validate_orgname_teamname(value)
|
|
||||||
else:
|
|
||||||
validate_username(value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@click.group("access", short_help="Manage resource access")
|
|
||||||
def cli():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def validate_urn(value):
|
|
||||||
value = str(value).strip()
|
|
||||||
if not re.match(r"^prn:reg:pkg:(\d+):(\w+)$", value, flags=re.I):
|
|
||||||
raise click.BadParameter("Invalid URN format.")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("public", short_help="Make resource public")
|
|
||||||
@click.argument(
|
|
||||||
"urn",
|
|
||||||
callback=lambda _, __, value: validate_urn(value),
|
|
||||||
)
|
|
||||||
@click.option("--urn-type", type=click.Choice(["prn:reg:pkg"]), default="prn:reg:pkg")
|
|
||||||
def access_public(urn, urn_type):
|
|
||||||
client = RegistryClient()
|
|
||||||
client.update_resource(urn=urn, private=0)
|
|
||||||
return click.secho(
|
|
||||||
"The resource %s has been successfully updated." % urn,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("private", short_help="Make resource private")
|
|
||||||
@click.argument(
|
|
||||||
"urn",
|
|
||||||
callback=lambda _, __, value: validate_urn(value),
|
|
||||||
)
|
|
||||||
@click.option("--urn-type", type=click.Choice(["prn:reg:pkg"]), default="prn:reg:pkg")
|
|
||||||
def access_private(urn, urn_type):
|
|
||||||
client = RegistryClient()
|
|
||||||
client.update_resource(urn=urn, private=1)
|
|
||||||
return click.secho(
|
|
||||||
"The resource %s has been successfully updated." % urn,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("grant", short_help="Grant access")
|
|
||||||
@click.argument("level", type=click.Choice(["admin", "maintainer", "guest"]))
|
|
||||||
@click.argument(
|
|
||||||
"client",
|
|
||||||
metavar="[<ORGNAME:TEAMNAME>|<USERNAME>]",
|
|
||||||
callback=lambda _, __, value: validate_client(value),
|
|
||||||
)
|
|
||||||
@click.argument(
|
|
||||||
"urn",
|
|
||||||
callback=lambda _, __, value: validate_urn(value),
|
|
||||||
)
|
|
||||||
@click.option("--urn-type", type=click.Choice(["prn:reg:pkg"]), default="prn:reg:pkg")
|
|
||||||
def access_grant(level, client, urn, urn_type):
|
|
||||||
reg_client = RegistryClient()
|
|
||||||
reg_client.grant_access_for_resource(urn=urn, client=client, level=level)
|
|
||||||
return click.secho(
|
|
||||||
"Access for resource %s has been granted for %s" % (urn, client),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("revoke", short_help="Revoke access")
|
|
||||||
@click.argument(
|
|
||||||
"client",
|
|
||||||
metavar="[ORGNAME:TEAMNAME|USERNAME]",
|
|
||||||
callback=lambda _, __, value: validate_client(value),
|
|
||||||
)
|
|
||||||
@click.argument(
|
|
||||||
"urn",
|
|
||||||
callback=lambda _, __, value: validate_urn(value),
|
|
||||||
)
|
|
||||||
@click.option("--urn-type", type=click.Choice(["prn:reg:pkg"]), default="prn:reg:pkg")
|
|
||||||
def access_revoke(client, urn, urn_type):
|
|
||||||
reg_client = RegistryClient()
|
|
||||||
reg_client.revoke_access_from_resource(urn=urn, client=client)
|
|
||||||
return click.secho(
|
|
||||||
"Access for resource %s has been revoked for %s" % (urn, client),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("list", short_help="List published resources")
|
|
||||||
@click.argument("owner", required=False)
|
|
||||||
@click.option("--urn-type", type=click.Choice(["prn:reg:pkg"]), default="prn:reg:pkg")
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def access_list(owner, urn_type, json_output):
|
|
||||||
reg_client = RegistryClient()
|
|
||||||
resources = reg_client.list_resources(owner=owner)
|
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps(resources))
|
|
||||||
if not resources:
|
|
||||||
return click.secho("You do not have any resources.", fg="yellow")
|
|
||||||
for resource in resources:
|
|
||||||
click.echo()
|
|
||||||
click.secho(resource.get("name"), fg="cyan")
|
|
||||||
click.echo("-" * len(resource.get("name")))
|
|
||||||
table_data = []
|
|
||||||
table_data.append(("URN:", resource.get("urn")))
|
|
||||||
table_data.append(("Owner:", resource.get("owner")))
|
|
||||||
table_data.append(
|
|
||||||
(
|
|
||||||
"Access:",
|
|
||||||
click.style("Private", fg="red")
|
|
||||||
if resource.get("private", False)
|
|
||||||
else "Public",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
table_data.append(
|
|
||||||
(
|
|
||||||
"Access level(s):",
|
|
||||||
", ".join(
|
|
||||||
(level.capitalize() for level in resource.get("access_levels"))
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
click.echo(tabulate(table_data, tablefmt="plain"))
|
|
||||||
return click.echo()
|
|
@ -1,292 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
import click
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio import util
|
|
||||||
from platformio.clients.account import AccountClient, AccountNotAuthorized
|
|
||||||
|
|
||||||
|
|
||||||
@click.group("account", short_help="Manage PlatformIO account")
|
|
||||||
def cli():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def validate_username(value, field="username"):
|
|
||||||
value = str(value).strip()
|
|
||||||
if not re.match(r"^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,37}$", value, flags=re.I):
|
|
||||||
raise click.BadParameter(
|
|
||||||
"Invalid %s format. "
|
|
||||||
"%s must contain only alphanumeric characters "
|
|
||||||
"or single hyphens, cannot begin or end with a hyphen, "
|
|
||||||
"and must not be longer than 38 characters."
|
|
||||||
% (field.lower(), field.capitalize())
|
|
||||||
)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def validate_email(value):
|
|
||||||
value = str(value).strip()
|
|
||||||
if not re.match(r"^[a-z\d_.+-]+@[a-z\d\-]+\.[a-z\d\-.]+$", value, flags=re.I):
|
|
||||||
raise click.BadParameter("Invalid email address")
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def validate_password(value):
|
|
||||||
value = str(value).strip()
|
|
||||||
if not re.match(r"^(?=.*[a-z])(?=.*\d).{8,}$", value):
|
|
||||||
raise click.BadParameter(
|
|
||||||
"Invalid password format. "
|
|
||||||
"Password must contain at least 8 characters"
|
|
||||||
" including a number and a lowercase letter"
|
|
||||||
)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("register", short_help="Create new PlatformIO Account")
|
|
||||||
@click.option(
|
|
||||||
"-u",
|
|
||||||
"--username",
|
|
||||||
prompt=True,
|
|
||||||
callback=lambda _, __, value: validate_username(value),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-e", "--email", prompt=True, callback=lambda _, __, value: validate_email(value)
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"-p",
|
|
||||||
"--password",
|
|
||||||
prompt=True,
|
|
||||||
hide_input=True,
|
|
||||||
confirmation_prompt=True,
|
|
||||||
callback=lambda _, __, value: validate_password(value),
|
|
||||||
)
|
|
||||||
@click.option("--firstname", prompt=True)
|
|
||||||
@click.option("--lastname", prompt=True)
|
|
||||||
def account_register(username, email, password, firstname, lastname):
|
|
||||||
client = AccountClient()
|
|
||||||
client.registration(username, email, password, firstname, lastname)
|
|
||||||
return click.secho(
|
|
||||||
"An account has been successfully created. "
|
|
||||||
"Please check your mail to activate your account and verify your email address.",
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("login", short_help="Log in to PlatformIO Account")
|
|
||||||
@click.option("-u", "--username", prompt="Username or email")
|
|
||||||
@click.option("-p", "--password", prompt=True, hide_input=True)
|
|
||||||
def account_login(username, password):
|
|
||||||
client = AccountClient()
|
|
||||||
client.login(username, password)
|
|
||||||
return click.secho("Successfully logged in!", fg="green")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("logout", short_help="Log out of PlatformIO Account")
|
|
||||||
def account_logout():
|
|
||||||
client = AccountClient()
|
|
||||||
client.logout()
|
|
||||||
return click.secho("Successfully logged out!", fg="green")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("password", short_help="Change password")
|
|
||||||
@click.option("--old-password", prompt=True, hide_input=True)
|
|
||||||
@click.option("--new-password", prompt=True, hide_input=True, confirmation_prompt=True)
|
|
||||||
def account_password(old_password, new_password):
|
|
||||||
client = AccountClient()
|
|
||||||
client.change_password(old_password, new_password)
|
|
||||||
return click.secho("Password successfully changed!", fg="green")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("token", short_help="Get or regenerate Authentication Token")
|
|
||||||
@click.option("-p", "--password", prompt=True, hide_input=True)
|
|
||||||
@click.option("--regenerate", is_flag=True)
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def account_token(password, regenerate, json_output):
|
|
||||||
client = AccountClient()
|
|
||||||
auth_token = client.auth_token(password, regenerate)
|
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps({"status": "success", "result": auth_token}))
|
|
||||||
return click.secho("Personal Authentication Token: %s" % auth_token, fg="green")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("forgot", short_help="Forgot password")
|
|
||||||
@click.option("--username", prompt="Username or email")
|
|
||||||
def account_forgot(username):
|
|
||||||
client = AccountClient()
|
|
||||||
client.forgot_password(username)
|
|
||||||
return click.secho(
|
|
||||||
"If this account is registered, we will send the "
|
|
||||||
"further instructions to your email.",
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("update", short_help="Update profile information")
|
|
||||||
@click.option("--current-password", prompt=True, hide_input=True)
|
|
||||||
@click.option("--username")
|
|
||||||
@click.option("--email")
|
|
||||||
@click.option("--firstname")
|
|
||||||
@click.option("--lastname")
|
|
||||||
def account_update(current_password, **kwargs):
|
|
||||||
client = AccountClient()
|
|
||||||
profile = client.get_profile()
|
|
||||||
new_profile = profile.copy()
|
|
||||||
if not any(kwargs.values()):
|
|
||||||
for field in profile:
|
|
||||||
new_profile[field] = click.prompt(
|
|
||||||
field.replace("_", " ").capitalize(), default=profile[field]
|
|
||||||
)
|
|
||||||
if field == "email":
|
|
||||||
validate_email(new_profile[field])
|
|
||||||
if field == "username":
|
|
||||||
validate_username(new_profile[field])
|
|
||||||
else:
|
|
||||||
new_profile.update({key: value for key, value in kwargs.items() if value})
|
|
||||||
client.update_profile(new_profile, current_password)
|
|
||||||
click.secho("Profile successfully updated!", fg="green")
|
|
||||||
username_changed = new_profile["username"] != profile["username"]
|
|
||||||
email_changed = new_profile["email"] != profile["email"]
|
|
||||||
if not username_changed and not email_changed:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
client.logout()
|
|
||||||
except AccountNotAuthorized:
|
|
||||||
pass
|
|
||||||
if email_changed:
|
|
||||||
return click.secho(
|
|
||||||
"Please check your mail to verify your new email address and re-login. ",
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
return click.secho("Please re-login.", fg="yellow")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("destroy", short_help="Destroy account")
|
|
||||||
def account_destroy():
|
|
||||||
client = AccountClient()
|
|
||||||
click.confirm(
|
|
||||||
"Are you sure you want to delete the %s user account?\n"
|
|
||||||
"Warning! All linked data will be permanently removed and can not be restored."
|
|
||||||
% client.get_logged_username(),
|
|
||||||
abort=True,
|
|
||||||
)
|
|
||||||
client.destroy_account()
|
|
||||||
try:
|
|
||||||
client.logout()
|
|
||||||
except AccountNotAuthorized:
|
|
||||||
pass
|
|
||||||
return click.secho(
|
|
||||||
"User account has been destroyed.",
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("show", short_help="PlatformIO Account information")
|
|
||||||
@click.option("--offline", is_flag=True)
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def account_show(offline, json_output):
|
|
||||||
client = AccountClient()
|
|
||||||
info = client.get_account_info(offline)
|
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps(info))
|
|
||||||
click.echo()
|
|
||||||
if info.get("profile"):
|
|
||||||
print_profile(info["profile"])
|
|
||||||
if info.get("packages"):
|
|
||||||
print_packages(info["packages"])
|
|
||||||
if info.get("subscriptions"):
|
|
||||||
print_subscriptions(info["subscriptions"])
|
|
||||||
return click.echo()
|
|
||||||
|
|
||||||
|
|
||||||
def print_profile(profile):
|
|
||||||
click.secho("Profile", fg="cyan", bold=True)
|
|
||||||
click.echo("=" * len("Profile"))
|
|
||||||
data = []
|
|
||||||
if profile.get("username"):
|
|
||||||
data.append(("Username:", profile["username"]))
|
|
||||||
if profile.get("email"):
|
|
||||||
data.append(("Email:", profile["email"]))
|
|
||||||
if profile.get("firstname"):
|
|
||||||
data.append(("First name:", profile["firstname"]))
|
|
||||||
if profile.get("lastname"):
|
|
||||||
data.append(("Last name:", profile["lastname"]))
|
|
||||||
click.echo(tabulate(data, tablefmt="plain"))
|
|
||||||
|
|
||||||
|
|
||||||
def print_packages(packages):
|
|
||||||
click.echo()
|
|
||||||
click.secho("Packages", fg="cyan")
|
|
||||||
click.echo("=" * len("Packages"))
|
|
||||||
for package in packages:
|
|
||||||
click.echo()
|
|
||||||
click.secho(package.get("name"), bold=True)
|
|
||||||
click.echo("-" * len(package.get("name")))
|
|
||||||
if package.get("description"):
|
|
||||||
click.echo(package.get("description"))
|
|
||||||
data = []
|
|
||||||
expire = "-"
|
|
||||||
if "subscription" in package:
|
|
||||||
expire = util.parse_datetime(
|
|
||||||
package["subscription"].get("end_at")
|
|
||||||
or package["subscription"].get("next_bill_at")
|
|
||||||
).strftime("%Y-%m-%d")
|
|
||||||
data.append(("Expire:", expire))
|
|
||||||
services = []
|
|
||||||
for key in package:
|
|
||||||
if not key.startswith("service."):
|
|
||||||
continue
|
|
||||||
if isinstance(package[key], dict):
|
|
||||||
services.append(package[key].get("title"))
|
|
||||||
else:
|
|
||||||
services.append(package[key])
|
|
||||||
if services:
|
|
||||||
data.append(("Services:", ", ".join(services)))
|
|
||||||
click.echo(tabulate(data, tablefmt="plain"))
|
|
||||||
|
|
||||||
|
|
||||||
def print_subscriptions(subscriptions):
|
|
||||||
click.echo()
|
|
||||||
click.secho("Subscriptions", fg="cyan")
|
|
||||||
click.echo("=" * len("Subscriptions"))
|
|
||||||
for subscription in subscriptions:
|
|
||||||
click.echo()
|
|
||||||
click.secho(subscription.get("product_name"), bold=True)
|
|
||||||
click.echo("-" * len(subscription.get("product_name")))
|
|
||||||
data = [("State:", subscription.get("status"))]
|
|
||||||
begin_at = util.parse_datetime(subscription.get("begin_at")).strftime("%c")
|
|
||||||
data.append(("Start date:", begin_at or "-"))
|
|
||||||
end_at = subscription.get("end_at")
|
|
||||||
if end_at:
|
|
||||||
end_at = util.parse_datetime(subscription.get("end_at")).strftime("%c")
|
|
||||||
data.append(("End date:", end_at or "-"))
|
|
||||||
next_bill_at = subscription.get("next_bill_at")
|
|
||||||
if next_bill_at:
|
|
||||||
next_bill_at = util.parse_datetime(
|
|
||||||
subscription.get("next_bill_at")
|
|
||||||
).strftime("%c")
|
|
||||||
data.append(("Next payment:", next_bill_at or "-"))
|
|
||||||
data.append(
|
|
||||||
("Edit:", click.style(subscription.get("update_url"), fg="blue") or "-")
|
|
||||||
)
|
|
||||||
data.append(
|
|
||||||
("Cancel:", click.style(subscription.get("cancel_url"), fg="blue") or "-")
|
|
||||||
)
|
|
||||||
click.echo(tabulate(data, tablefmt="plain"))
|
|
@ -20,10 +20,10 @@ import tempfile
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import app, fs
|
from platformio import app, fs
|
||||||
from platformio.commands.run.command import cli as cmd_run
|
|
||||||
from platformio.exception import CIBuildEnvsEmpty
|
from platformio.exception import CIBuildEnvsEmpty
|
||||||
from platformio.project.commands.init import project_init_cmd, validate_boards
|
from platformio.project.commands.init import project_init_cmd, validate_boards
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
|
from platformio.run.cli import cli as cmd_run
|
||||||
|
|
||||||
|
|
||||||
def validate_path(ctx, param, value): # pylint: disable=unused-argument
|
def validate_path(ctx, param, value): # pylint: disable=unused-argument
|
||||||
|
@ -24,7 +24,7 @@ import click
|
|||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from platformio import exception, fs, util
|
from platformio import exception, fs, util
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.commands.lib.helpers import get_builtin_libs, save_project_libdeps
|
from platformio.commands.lib.helpers import get_builtin_libs, save_project_libdeps
|
||||||
from platformio.package.exception import NotGlobalLibDir, UnknownPackageError
|
from platformio.package.exception import NotGlobalLibDir, UnknownPackageError
|
||||||
from platformio.package.manager.library import LibraryPackageManager
|
from platformio.package.manager.library import LibraryPackageManager
|
||||||
@ -69,13 +69,6 @@ def get_project_global_lib_dir():
|
|||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx, **options):
|
def cli(ctx, **options):
|
||||||
in_silence = PlatformioCLI.in_silence()
|
in_silence = PlatformioCLI.in_silence()
|
||||||
if not in_silence:
|
|
||||||
click.secho(
|
|
||||||
"\nWARNING!!! This command is deprecated and will be removed in "
|
|
||||||
"the next releases. \nPlease use `pio pkg` instead.\n",
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
|
|
||||||
storage_cmds = ("install", "uninstall", "update", "list")
|
storage_cmds = ("install", "uninstall", "update", "list")
|
||||||
# skip commands that don't need storage folder
|
# skip commands that don't need storage folder
|
||||||
if ctx.invoked_subcommand not in storage_cmds or (
|
if ctx.invoked_subcommand not in storage_cmds or (
|
||||||
@ -148,6 +141,11 @@ def cli(ctx, **options):
|
|||||||
def lib_install( # pylint: disable=too-many-arguments,unused-argument
|
def lib_install( # pylint: disable=too-many-arguments,unused-argument
|
||||||
ctx, libraries, save, silent, interactive, force
|
ctx, libraries, save, silent, interactive, force
|
||||||
):
|
):
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg install` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
storage_libdeps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, [])
|
storage_libdeps = ctx.meta.get(CTX_META_STORAGE_LIBDEPS_KEY, [])
|
||||||
|
|
||||||
@ -211,6 +209,11 @@ def _save_deps(ctx, pkgs, action="add"):
|
|||||||
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
|
@click.option("-s", "--silent", is_flag=True, help="Suppress progress reporting")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def lib_uninstall(ctx, libraries, save, silent):
|
def lib_uninstall(ctx, libraries, save, silent):
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg uninstall` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
uninstalled_pkgs = {}
|
uninstalled_pkgs = {}
|
||||||
for storage_dir in storage_dirs:
|
for storage_dir in storage_dirs:
|
||||||
@ -246,6 +249,13 @@ def lib_update( # pylint: disable=too-many-arguments
|
|||||||
"This command is deprecated, please use `pio pkg outdated` instead"
|
"This command is deprecated, please use `pio pkg outdated` instead"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg update` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
json_result = {}
|
json_result = {}
|
||||||
for storage_dir in storage_dirs:
|
for storage_dir in storage_dirs:
|
||||||
@ -305,6 +315,12 @@ def lib_update( # pylint: disable=too-many-arguments
|
|||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def lib_list(ctx, json_output):
|
def lib_list(ctx, json_output):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg list` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
storage_dirs = ctx.meta[CTX_META_STORAGE_DIRS_KEY]
|
||||||
json_result = {}
|
json_result = {}
|
||||||
for storage_dir in storage_dirs:
|
for storage_dir in storage_dirs:
|
||||||
@ -348,6 +364,12 @@ def lib_list(ctx, json_output):
|
|||||||
help="Do not prompt, automatically paginate with delay",
|
help="Do not prompt, automatically paginate with delay",
|
||||||
)
|
)
|
||||||
def lib_search(query, json_output, page, noninteractive, **filters):
|
def lib_search(query, json_output, page, noninteractive, **filters):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg search` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
regclient = LibraryPackageManager().get_registry_client_instance()
|
regclient = LibraryPackageManager().get_registry_client_instance()
|
||||||
if not query:
|
if not query:
|
||||||
query = []
|
query = []
|
||||||
@ -444,6 +466,12 @@ def lib_builtin(storage, json_output):
|
|||||||
@click.argument("library", metavar="[LIBRARY]")
|
@click.argument("library", metavar="[LIBRARY]")
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def lib_show(library, json_output):
|
def lib_show(library, json_output):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg show` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
lm = LibraryPackageManager()
|
lm = LibraryPackageManager()
|
||||||
lm.set_log_level(logging.ERROR if json_output else logging.DEBUG)
|
lm.set_log_level(logging.ERROR if json_output else logging.DEBUG)
|
||||||
lib_id = lm.reveal_registry_package_id(library)
|
lib_id = lm.reveal_registry_package_id(library)
|
||||||
|
@ -1,165 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
import click
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio.clients.account import AccountClient
|
|
||||||
from platformio.commands.account import validate_email, validate_username
|
|
||||||
|
|
||||||
|
|
||||||
@click.group("org", short_help="Manage organizations")
|
|
||||||
def cli():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def validate_orgname(value):
|
|
||||||
return validate_username(value, "Organization name")
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("create", short_help="Create a new organization")
|
|
||||||
@click.argument(
|
|
||||||
"orgname",
|
|
||||||
callback=lambda _, __, value: validate_orgname(value),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--email", callback=lambda _, __, value: validate_email(value) if value else value
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--displayname",
|
|
||||||
)
|
|
||||||
def org_create(orgname, email, displayname):
|
|
||||||
client = AccountClient()
|
|
||||||
client.create_org(orgname, email, displayname)
|
|
||||||
return click.secho(
|
|
||||||
"The organization `%s` has been successfully created." % orgname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("list", short_help="List organizations and their members")
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def org_list(json_output):
|
|
||||||
client = AccountClient()
|
|
||||||
orgs = client.list_orgs()
|
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps(orgs))
|
|
||||||
if not orgs:
|
|
||||||
return click.echo("You do not have any organization")
|
|
||||||
for org in orgs:
|
|
||||||
click.echo()
|
|
||||||
click.secho(org.get("orgname"), fg="cyan")
|
|
||||||
click.echo("-" * len(org.get("orgname")))
|
|
||||||
data = []
|
|
||||||
if org.get("displayname"):
|
|
||||||
data.append(("Display Name:", org.get("displayname")))
|
|
||||||
if org.get("email"):
|
|
||||||
data.append(("Email:", org.get("email")))
|
|
||||||
data.append(
|
|
||||||
(
|
|
||||||
"Owners:",
|
|
||||||
", ".join((owner.get("username") for owner in org.get("owners"))),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
click.echo(tabulate(data, tablefmt="plain"))
|
|
||||||
return click.echo()
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("update", short_help="Update organization")
|
|
||||||
@click.argument("cur_orgname")
|
|
||||||
@click.option(
|
|
||||||
"--orgname",
|
|
||||||
callback=lambda _, __, value: validate_orgname(value),
|
|
||||||
help="A new orgname",
|
|
||||||
)
|
|
||||||
@click.option("--email")
|
|
||||||
@click.option("--displayname")
|
|
||||||
def org_update(cur_orgname, **kwargs):
|
|
||||||
client = AccountClient()
|
|
||||||
org = client.get_org(cur_orgname)
|
|
||||||
del org["owners"]
|
|
||||||
new_org = org.copy()
|
|
||||||
if not any(kwargs.values()):
|
|
||||||
for field in org:
|
|
||||||
new_org[field] = click.prompt(
|
|
||||||
field.replace("_", " ").capitalize(), default=org[field]
|
|
||||||
)
|
|
||||||
if field == "email":
|
|
||||||
validate_email(new_org[field])
|
|
||||||
if field == "orgname":
|
|
||||||
validate_orgname(new_org[field])
|
|
||||||
else:
|
|
||||||
new_org.update(
|
|
||||||
{key.replace("new_", ""): value for key, value in kwargs.items() if value}
|
|
||||||
)
|
|
||||||
client.update_org(cur_orgname, new_org)
|
|
||||||
return click.secho(
|
|
||||||
"The organization `%s` has been successfully updated." % cur_orgname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("destroy", short_help="Destroy organization")
|
|
||||||
@click.argument("orgname")
|
|
||||||
def account_destroy(orgname):
|
|
||||||
client = AccountClient()
|
|
||||||
click.confirm(
|
|
||||||
"Are you sure you want to delete the `%s` organization account?\n"
|
|
||||||
"Warning! All linked data will be permanently removed and can not be restored."
|
|
||||||
% orgname,
|
|
||||||
abort=True,
|
|
||||||
)
|
|
||||||
client.destroy_org(orgname)
|
|
||||||
return click.secho(
|
|
||||||
"Organization `%s` has been destroyed." % orgname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("add", short_help="Add a new owner to organization")
|
|
||||||
@click.argument(
|
|
||||||
"orgname",
|
|
||||||
)
|
|
||||||
@click.argument(
|
|
||||||
"username",
|
|
||||||
)
|
|
||||||
def org_add_owner(orgname, username):
|
|
||||||
client = AccountClient()
|
|
||||||
client.add_org_owner(orgname, username)
|
|
||||||
return click.secho(
|
|
||||||
"The new owner `%s` has been successfully added to the `%s` organization."
|
|
||||||
% (username, orgname),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("remove", short_help="Remove an owner from organization")
|
|
||||||
@click.argument(
|
|
||||||
"orgname",
|
|
||||||
)
|
|
||||||
@click.argument(
|
|
||||||
"username",
|
|
||||||
)
|
|
||||||
def org_remove_owner(orgname, username):
|
|
||||||
client = AccountClient()
|
|
||||||
client.remove_org_owner(orgname, username)
|
|
||||||
return click.secho(
|
|
||||||
"The `%s` owner has been successfully removed from the `%s` organization."
|
|
||||||
% (username, orgname),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
@ -18,7 +18,6 @@ import os
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio.commands import PlatformioCLI
|
|
||||||
from platformio.commands.boards import print_boards
|
from platformio.commands.boards import print_boards
|
||||||
from platformio.exception import UserSideException
|
from platformio.exception import UserSideException
|
||||||
from platformio.package.exception import UnknownPackageError
|
from platformio.package.exception import UnknownPackageError
|
||||||
@ -31,18 +30,19 @@ from platformio.platform.factory import PlatformFactory
|
|||||||
|
|
||||||
@click.group(short_help="Platform manager", hidden=True)
|
@click.group(short_help="Platform manager", hidden=True)
|
||||||
def cli():
|
def cli():
|
||||||
if not PlatformioCLI.in_silence():
|
pass
|
||||||
click.secho(
|
|
||||||
"\nWARNING!!! This command is deprecated and will be removed in "
|
|
||||||
"the next releases. \nPlease use `pio pkg` instead.\n",
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("search", short_help="Search for development platform")
|
@cli.command("search", short_help="Search for development platform")
|
||||||
@click.argument("query", required=False)
|
@click.argument("query", required=False)
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def platform_search(query, json_output):
|
def platform_search(query, json_output):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg search` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
platforms = []
|
platforms = []
|
||||||
for platform in _get_registry_platforms():
|
for platform in _get_registry_platforms():
|
||||||
if query == "all":
|
if query == "all":
|
||||||
@ -94,6 +94,12 @@ def platform_frameworks(query, json_output):
|
|||||||
@cli.command("list", short_help="List installed development platforms")
|
@cli.command("list", short_help="List installed development platforms")
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def platform_list(json_output):
|
def platform_list(json_output):
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg list` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
platforms = []
|
platforms = []
|
||||||
pm = PlatformPackageManager()
|
pm = PlatformPackageManager()
|
||||||
for pkg in pm.get_installed():
|
for pkg in pm.get_installed():
|
||||||
@ -112,6 +118,12 @@ def platform_list(json_output):
|
|||||||
@click.argument("platform")
|
@click.argument("platform")
|
||||||
@click.option("--json-output", is_flag=True)
|
@click.option("--json-output", is_flag=True)
|
||||||
def platform_show(platform, json_output): # pylint: disable=too-many-branches
|
def platform_show(platform, json_output): # pylint: disable=too-many-branches
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg show` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
data = _get_platform_data(platform)
|
data = _get_platform_data(platform)
|
||||||
if not data:
|
if not data:
|
||||||
raise UnknownPlatform(platform)
|
raise UnknownPlatform(platform)
|
||||||
@ -195,6 +207,12 @@ def platform_install( # pylint: disable=too-many-arguments,too-many-locals
|
|||||||
silent,
|
silent,
|
||||||
force,
|
force,
|
||||||
):
|
):
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg install` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
def _find_pkg_names(p, candidates):
|
def _find_pkg_names(p, candidates):
|
||||||
result = []
|
result = []
|
||||||
for candidate in candidates:
|
for candidate in candidates:
|
||||||
@ -251,6 +269,11 @@ def platform_install( # pylint: disable=too-many-arguments,too-many-locals
|
|||||||
@cli.command("uninstall", short_help="Uninstall development platform")
|
@cli.command("uninstall", short_help="Uninstall development platform")
|
||||||
@click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]")
|
@click.argument("platforms", nargs=-1, required=True, metavar="[PLATFORM...]")
|
||||||
def platform_uninstall(platforms):
|
def platform_uninstall(platforms):
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg uninstall` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
pm = PlatformPackageManager()
|
pm = PlatformPackageManager()
|
||||||
pm.set_log_level(logging.DEBUG)
|
pm.set_log_level(logging.DEBUG)
|
||||||
for platform in platforms:
|
for platform in platforms:
|
||||||
@ -285,6 +308,13 @@ def platform_update( # pylint: disable=too-many-locals, too-many-arguments
|
|||||||
"This command is deprecated, please use `pio pkg outdated` instead"
|
"This command is deprecated, please use `pio pkg outdated` instead"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not json_output:
|
||||||
|
click.secho(
|
||||||
|
"\nWARNING: This command is deprecated and will be removed in "
|
||||||
|
"the next releases. \nPlease use `pio pkg update` instead.\n",
|
||||||
|
fg="yellow",
|
||||||
|
)
|
||||||
|
|
||||||
pm = PlatformPackageManager()
|
pm = PlatformPackageManager()
|
||||||
pm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
pm.set_log_level(logging.WARN if silent else logging.DEBUG)
|
||||||
platforms = platforms or pm.get_installed()
|
platforms = platforms or pm.get_installed()
|
||||||
|
@ -1,191 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import json
|
|
||||||
import platform
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import click
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio import __version__, compat, fs, proc, util
|
|
||||||
from platformio.commands.system.completion import (
|
|
||||||
ShellType,
|
|
||||||
get_completion_install_path,
|
|
||||||
install_completion_code,
|
|
||||||
uninstall_completion_code,
|
|
||||||
)
|
|
||||||
from platformio.commands.system.prune import (
|
|
||||||
prune_cached_data,
|
|
||||||
prune_core_packages,
|
|
||||||
prune_platform_packages,
|
|
||||||
)
|
|
||||||
from platformio.package.manager.library import LibraryPackageManager
|
|
||||||
from platformio.package.manager.platform import PlatformPackageManager
|
|
||||||
from platformio.package.manager.tool import ToolPackageManager
|
|
||||||
from platformio.project.config import ProjectConfig
|
|
||||||
|
|
||||||
|
|
||||||
@click.group("system", short_help="Miscellaneous system commands")
|
|
||||||
def cli():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("info", short_help="Display system-wide information")
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def system_info(json_output):
|
|
||||||
project_config = ProjectConfig()
|
|
||||||
data = {}
|
|
||||||
data["core_version"] = {"title": "PlatformIO Core", "value": __version__}
|
|
||||||
data["python_version"] = {
|
|
||||||
"title": "Python",
|
|
||||||
"value": "{0}.{1}.{2}-{3}.{4}".format(*list(sys.version_info)),
|
|
||||||
}
|
|
||||||
data["system"] = {"title": "System Type", "value": util.get_systype()}
|
|
||||||
data["platform"] = {"title": "Platform", "value": platform.platform(terse=True)}
|
|
||||||
data["filesystem_encoding"] = {
|
|
||||||
"title": "File System Encoding",
|
|
||||||
"value": compat.get_filesystem_encoding(),
|
|
||||||
}
|
|
||||||
data["locale_encoding"] = {
|
|
||||||
"title": "Locale Encoding",
|
|
||||||
"value": compat.get_locale_encoding(),
|
|
||||||
}
|
|
||||||
data["core_dir"] = {
|
|
||||||
"title": "PlatformIO Core Directory",
|
|
||||||
"value": project_config.get("platformio", "core_dir"),
|
|
||||||
}
|
|
||||||
data["platformio_exe"] = {
|
|
||||||
"title": "PlatformIO Core Executable",
|
|
||||||
"value": proc.where_is_program(
|
|
||||||
"platformio.exe" if compat.IS_WINDOWS else "platformio"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
data["python_exe"] = {
|
|
||||||
"title": "Python Executable",
|
|
||||||
"value": proc.get_pythonexe_path(),
|
|
||||||
}
|
|
||||||
data["global_lib_nums"] = {
|
|
||||||
"title": "Global Libraries",
|
|
||||||
"value": len(LibraryPackageManager().get_installed()),
|
|
||||||
}
|
|
||||||
data["dev_platform_nums"] = {
|
|
||||||
"title": "Development Platforms",
|
|
||||||
"value": len(PlatformPackageManager().get_installed()),
|
|
||||||
}
|
|
||||||
data["package_tool_nums"] = {
|
|
||||||
"title": "Tools & Toolchains",
|
|
||||||
"value": len(
|
|
||||||
ToolPackageManager(
|
|
||||||
project_config.get("platformio", "packages_dir")
|
|
||||||
).get_installed()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
click.echo(
|
|
||||||
json.dumps(data)
|
|
||||||
if json_output
|
|
||||||
else tabulate([(item["title"], item["value"]) for item in data.values()])
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("prune", short_help="Remove unused data")
|
|
||||||
@click.option("--force", "-f", is_flag=True, help="Do not prompt for confirmation")
|
|
||||||
@click.option(
|
|
||||||
"--dry-run", is_flag=True, help="Do not prune, only show data that will be removed"
|
|
||||||
)
|
|
||||||
@click.option("--cache", is_flag=True, help="Prune only cached data")
|
|
||||||
@click.option(
|
|
||||||
"--core-packages", is_flag=True, help="Prune only unnecessary core packages"
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--platform-packages",
|
|
||||||
is_flag=True,
|
|
||||||
help="Prune only unnecessary development platform packages",
|
|
||||||
)
|
|
||||||
def system_prune(force, dry_run, cache, core_packages, platform_packages):
|
|
||||||
if dry_run:
|
|
||||||
click.secho(
|
|
||||||
"Dry run mode (do not prune, only show data that will be removed)",
|
|
||||||
fg="yellow",
|
|
||||||
)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
reclaimed_cache = 0
|
|
||||||
reclaimed_core_packages = 0
|
|
||||||
reclaimed_platform_packages = 0
|
|
||||||
prune_all = not any([cache, core_packages, platform_packages])
|
|
||||||
|
|
||||||
if cache or prune_all:
|
|
||||||
reclaimed_cache = prune_cached_data(force, dry_run)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
if core_packages or prune_all:
|
|
||||||
reclaimed_core_packages = prune_core_packages(force, dry_run)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
if platform_packages or prune_all:
|
|
||||||
reclaimed_platform_packages = prune_platform_packages(force, dry_run)
|
|
||||||
click.echo()
|
|
||||||
|
|
||||||
click.secho(
|
|
||||||
"Total reclaimed space: %s"
|
|
||||||
% fs.humanize_file_size(
|
|
||||||
reclaimed_cache + reclaimed_core_packages + reclaimed_platform_packages
|
|
||||||
),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.group("completion", short_help="Shell completion support")
|
|
||||||
def completion():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@completion.command("install", short_help="Install shell completion files/code")
|
|
||||||
@click.argument("shell", type=click.Choice([t.value for t in ShellType]))
|
|
||||||
@click.option(
|
|
||||||
"--path",
|
|
||||||
type=click.Path(file_okay=True, dir_okay=False, readable=True, resolve_path=True),
|
|
||||||
help="Custom installation path of the code to be evaluated by the shell. "
|
|
||||||
"The standard installation path is used by default.",
|
|
||||||
)
|
|
||||||
def completion_install(shell, path):
|
|
||||||
shell = ShellType(shell)
|
|
||||||
path = path or get_completion_install_path(shell)
|
|
||||||
install_completion_code(shell, path)
|
|
||||||
click.echo(
|
|
||||||
"PlatformIO CLI completion has been installed for %s shell to %s \n"
|
|
||||||
"Please restart a current shell session."
|
|
||||||
% (click.style(shell.name, fg="cyan"), click.style(path, fg="blue"))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@completion.command("uninstall", short_help="Uninstall shell completion files/code")
|
|
||||||
@click.argument("shell", type=click.Choice([t.value for t in ShellType]))
|
|
||||||
@click.option(
|
|
||||||
"--path",
|
|
||||||
type=click.Path(file_okay=True, dir_okay=False, readable=True, resolve_path=True),
|
|
||||||
help="Custom installation path of the code to be evaluated by the shell. "
|
|
||||||
"The standard installation path is used by default.",
|
|
||||||
)
|
|
||||||
def completion_uninstall(shell, path):
|
|
||||||
shell = ShellType(shell)
|
|
||||||
path = path or get_completion_install_path(shell)
|
|
||||||
uninstall_completion_code(shell, path)
|
|
||||||
click.echo(
|
|
||||||
"PlatformIO CLI completion has been uninstalled for %s shell from %s \n"
|
|
||||||
"Please restart a current shell session."
|
|
||||||
% (click.style(shell.name, fg="cyan"), click.style(path, fg="blue"))
|
|
||||||
)
|
|
@ -1,212 +0,0 @@
|
|||||||
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# pylint: disable=unused-argument
|
|
||||||
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
|
|
||||||
import click
|
|
||||||
from tabulate import tabulate
|
|
||||||
|
|
||||||
from platformio.clients.account import AccountClient
|
|
||||||
|
|
||||||
|
|
||||||
def validate_orgname_teamname(value, teamname_validate=False):
|
|
||||||
if ":" not in value:
|
|
||||||
raise click.BadParameter(
|
|
||||||
"Please specify organization and team name in the next"
|
|
||||||
" format - orgname:teamname. For example, mycompany:DreamTeam"
|
|
||||||
)
|
|
||||||
teamname = str(value.strip().split(":", 1)[1])
|
|
||||||
if teamname_validate:
|
|
||||||
validate_teamname(teamname)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def validate_teamname(value):
|
|
||||||
if not value:
|
|
||||||
return value
|
|
||||||
value = str(value).strip()
|
|
||||||
if not re.match(r"^[a-z\d](?:[a-z\d]|[\-_ ](?=[a-z\d])){0,19}$", value, flags=re.I):
|
|
||||||
raise click.BadParameter(
|
|
||||||
"Invalid team name format. "
|
|
||||||
"Team name must only contain alphanumeric characters, "
|
|
||||||
"single hyphens, underscores, spaces. It can not "
|
|
||||||
"begin or end with a hyphen or a underscore and must"
|
|
||||||
" not be longer than 20 characters."
|
|
||||||
)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
@click.group("team", short_help="Manage organization teams")
|
|
||||||
def cli():
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("create", short_help="Create a new team")
|
|
||||||
@click.argument(
|
|
||||||
"orgname_teamname",
|
|
||||||
metavar="ORGNAME:TEAMNAME",
|
|
||||||
callback=lambda _, __, value: validate_orgname_teamname(
|
|
||||||
value, teamname_validate=True
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--description",
|
|
||||||
)
|
|
||||||
def team_create(orgname_teamname, description):
|
|
||||||
orgname, teamname = orgname_teamname.split(":", 1)
|
|
||||||
client = AccountClient()
|
|
||||||
client.create_team(orgname, teamname, description)
|
|
||||||
return click.secho(
|
|
||||||
"The team %s has been successfully created." % teamname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("list", short_help="List teams")
|
|
||||||
@click.argument("orgname", required=False)
|
|
||||||
@click.option("--json-output", is_flag=True)
|
|
||||||
def team_list(orgname, json_output):
|
|
||||||
client = AccountClient()
|
|
||||||
data = {}
|
|
||||||
if not orgname:
|
|
||||||
for item in client.list_orgs():
|
|
||||||
teams = client.list_teams(item.get("orgname"))
|
|
||||||
data[item.get("orgname")] = teams
|
|
||||||
else:
|
|
||||||
teams = client.list_teams(orgname)
|
|
||||||
data[orgname] = teams
|
|
||||||
if json_output:
|
|
||||||
return click.echo(json.dumps(data[orgname] if orgname else data))
|
|
||||||
if not any(data.values()):
|
|
||||||
return click.secho("You do not have any teams.", fg="yellow")
|
|
||||||
for org_name in data:
|
|
||||||
for team in data[org_name]:
|
|
||||||
click.echo()
|
|
||||||
click.secho("%s:%s" % (org_name, team.get("name")), fg="cyan")
|
|
||||||
click.echo("-" * len("%s:%s" % (org_name, team.get("name"))))
|
|
||||||
table_data = []
|
|
||||||
if team.get("description"):
|
|
||||||
table_data.append(("Description:", team.get("description")))
|
|
||||||
table_data.append(
|
|
||||||
(
|
|
||||||
"Members:",
|
|
||||||
", ".join(
|
|
||||||
(member.get("username") for member in team.get("members"))
|
|
||||||
)
|
|
||||||
if team.get("members")
|
|
||||||
else "-",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
click.echo(tabulate(table_data, tablefmt="plain"))
|
|
||||||
return click.echo()
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("update", short_help="Update team")
|
|
||||||
@click.argument(
|
|
||||||
"orgname_teamname",
|
|
||||||
metavar="ORGNAME:TEAMNAME",
|
|
||||||
callback=lambda _, __, value: validate_orgname_teamname(value),
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--name",
|
|
||||||
callback=lambda _, __, value: validate_teamname(value),
|
|
||||||
help="A new team name",
|
|
||||||
)
|
|
||||||
@click.option(
|
|
||||||
"--description",
|
|
||||||
)
|
|
||||||
def team_update(orgname_teamname, **kwargs):
|
|
||||||
orgname, teamname = orgname_teamname.split(":", 1)
|
|
||||||
client = AccountClient()
|
|
||||||
team = client.get_team(orgname, teamname)
|
|
||||||
del team["id"]
|
|
||||||
del team["members"]
|
|
||||||
new_team = team.copy()
|
|
||||||
if not any(kwargs.values()):
|
|
||||||
for field in team:
|
|
||||||
new_team[field] = click.prompt(
|
|
||||||
field.replace("_", " ").capitalize(), default=team[field]
|
|
||||||
)
|
|
||||||
if field == "name":
|
|
||||||
validate_teamname(new_team[field])
|
|
||||||
else:
|
|
||||||
new_team.update({key: value for key, value in kwargs.items() if value})
|
|
||||||
client.update_team(orgname, teamname, new_team)
|
|
||||||
return click.secho(
|
|
||||||
"The team %s has been successfully updated." % teamname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("destroy", short_help="Destroy a team")
|
|
||||||
@click.argument(
|
|
||||||
"orgname_teamname",
|
|
||||||
metavar="ORGNAME:TEAMNAME",
|
|
||||||
callback=lambda _, __, value: validate_orgname_teamname(value),
|
|
||||||
)
|
|
||||||
def team_destroy(orgname_teamname):
|
|
||||||
orgname, teamname = orgname_teamname.split(":", 1)
|
|
||||||
click.confirm(
|
|
||||||
click.style(
|
|
||||||
"Are you sure you want to destroy the %s team?" % teamname, fg="yellow"
|
|
||||||
),
|
|
||||||
abort=True,
|
|
||||||
)
|
|
||||||
client = AccountClient()
|
|
||||||
client.destroy_team(orgname, teamname)
|
|
||||||
return click.secho(
|
|
||||||
"The team %s has been successfully destroyed." % teamname,
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("add", short_help="Add a new member to team")
|
|
||||||
@click.argument(
|
|
||||||
"orgname_teamname",
|
|
||||||
metavar="ORGNAME:TEAMNAME",
|
|
||||||
callback=lambda _, __, value: validate_orgname_teamname(value),
|
|
||||||
)
|
|
||||||
@click.argument(
|
|
||||||
"username",
|
|
||||||
)
|
|
||||||
def team_add_member(orgname_teamname, username):
|
|
||||||
orgname, teamname = orgname_teamname.split(":", 1)
|
|
||||||
client = AccountClient()
|
|
||||||
client.add_team_member(orgname, teamname, username)
|
|
||||||
return click.secho(
|
|
||||||
"The new member %s has been successfully added to the %s team."
|
|
||||||
% (username, teamname),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command("remove", short_help="Remove a member from team")
|
|
||||||
@click.argument(
|
|
||||||
"orgname_teamname",
|
|
||||||
metavar="ORGNAME:TEAMNAME",
|
|
||||||
callback=lambda _, __, value: validate_orgname_teamname(value),
|
|
||||||
)
|
|
||||||
@click.argument("username")
|
|
||||||
def team_remove_owner(orgname_teamname, username):
|
|
||||||
orgname, teamname = orgname_teamname.split(":", 1)
|
|
||||||
client = AccountClient()
|
|
||||||
client.remove_team_member(orgname, teamname, username)
|
|
||||||
return click.secho(
|
|
||||||
"The %s member has been successfully removed from the %s team."
|
|
||||||
% (username, teamname),
|
|
||||||
fg="green",
|
|
||||||
)
|
|
@ -20,8 +20,8 @@ from zipfile import ZipFile
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import VERSION, __version__, app, exception
|
from platformio import VERSION, __version__, app, exception
|
||||||
from platformio.clients.http import fetch_remote_content
|
|
||||||
from platformio.compat import IS_WINDOWS
|
from platformio.compat import IS_WINDOWS
|
||||||
|
from platformio.http import fetch_remote_content
|
||||||
from platformio.package.manager.core import update_core_packages
|
from platformio.package.manager.core import update_core_packages
|
||||||
from platformio.proc import exec_command, get_pythonexe_path
|
from platformio.proc import exec_command, get_pythonexe_path
|
||||||
from platformio.project.helpers import get_project_cache_dir
|
from platformio.project.helpers import get_project_cache_dir
|
||||||
|
@ -61,7 +61,7 @@ from platformio.project.options import ProjectOptions
|
|||||||
@click.option("--interface", type=click.Choice(["gdb"]))
|
@click.option("--interface", type=click.Choice(["gdb"]))
|
||||||
@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED)
|
@click.argument("__unprocessed", nargs=-1, type=click.UNPROCESSED)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def debug_cmd(
|
def cli(
|
||||||
ctx,
|
ctx,
|
||||||
project_dir,
|
project_dir,
|
||||||
project_conf,
|
project_conf,
|
@ -20,12 +20,12 @@ from fnmatch import fnmatch
|
|||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.commands.run.command import cli as cmd_run
|
|
||||||
from platformio.commands.run.command import print_processing_header
|
|
||||||
from platformio.compat import IS_WINDOWS, is_bytes
|
from platformio.compat import IS_WINDOWS, is_bytes
|
||||||
from platformio.debug.exception import DebugInvalidOptionsError
|
from platformio.debug.exception import DebugInvalidOptionsError
|
||||||
from platformio.device.list import list_serial_ports
|
from platformio.device.list import list_serial_ports
|
||||||
|
from platformio.run.cli import cli as cmd_run
|
||||||
|
from platformio.run.cli import print_processing_header
|
||||||
from platformio.test.helpers import list_test_names
|
from platformio.test.helpers import list_test_names
|
||||||
from platformio.test.result import TestSuite
|
from platformio.test.result import TestSuite
|
||||||
from platformio.test.runners.base import TestRunnerOptions
|
from platformio.test.runners.base import TestRunnerOptions
|
||||||
|
@ -56,7 +56,7 @@ class MissedUdevRules(InvalidUdevRules):
|
|||||||
|
|
||||||
MESSAGE = (
|
MESSAGE = (
|
||||||
"Warning! Please install `99-platformio-udev.rules`. \nMore details: "
|
"Warning! Please install `99-platformio-udev.rules`. \nMore details: "
|
||||||
"https://docs.platformio.org/page/faq.html#platformio-udev-rules"
|
"https://docs.platformio.org/en/latest/core/installation/udev-rules.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class OutdatedUdevRules(InvalidUdevRules):
|
|||||||
MESSAGE = (
|
MESSAGE = (
|
||||||
"Warning! Your `{0}` are outdated. Please update or reinstall them."
|
"Warning! Your `{0}` are outdated. Please update or reinstall them."
|
||||||
"\nMore details: "
|
"\nMore details: "
|
||||||
"https://docs.platformio.org/page/faq.html#platformio-udev-rules"
|
"https://docs.platformio.org/en/latest/core/installation/udev-rules.html"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ import mimetypes
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio.commands.home.helpers import is_port_used
|
from platformio.home.helpers import is_port_used
|
||||||
from platformio.commands.home.run import run_server
|
from platformio.home.run import run_server
|
||||||
|
|
||||||
|
|
||||||
@click.command("home", short_help="GUI to manage PlatformIO")
|
@click.command("home", short_help="GUI to manage PlatformIO")
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
from ajsonrpc.core import JSONRPC20DispatchException
|
from ajsonrpc.core import JSONRPC20DispatchException
|
||||||
|
|
||||||
from platformio.clients.account import AccountClient
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
|
|
||||||
class AccountRPC:
|
class AccountRPC:
|
@ -16,8 +16,8 @@ import json
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
from platformio.cache import ContentCache
|
from platformio.cache import ContentCache
|
||||||
from platformio.commands.home.rpc.handlers.os import OSRPC
|
|
||||||
from platformio.compat import aio_create_task
|
from platformio.compat import aio_create_task
|
||||||
|
from platformio.home.rpc.handlers.os import OSRPC
|
||||||
|
|
||||||
|
|
||||||
class MiscRPC:
|
class MiscRPC:
|
@ -24,9 +24,9 @@ import click
|
|||||||
|
|
||||||
from platformio import __default_requests_timeout__, fs
|
from platformio import __default_requests_timeout__, fs
|
||||||
from platformio.cache import ContentCache
|
from platformio.cache import ContentCache
|
||||||
from platformio.clients.http import ensure_internet_on
|
|
||||||
from platformio.commands.home import helpers
|
|
||||||
from platformio.device.list import list_logical_devices
|
from platformio.device.list import list_logical_devices
|
||||||
|
from platformio.home import helpers
|
||||||
|
from platformio.http import ensure_internet_on
|
||||||
|
|
||||||
|
|
||||||
class OSRPC:
|
class OSRPC:
|
@ -25,8 +25,8 @@ from ajsonrpc.core import JSONRPC20DispatchException
|
|||||||
from starlette.concurrency import run_in_threadpool
|
from starlette.concurrency import run_in_threadpool
|
||||||
|
|
||||||
from platformio import __main__, __version__, fs, proc
|
from platformio import __main__, __version__, fs, proc
|
||||||
from platformio.commands.home import helpers
|
|
||||||
from platformio.compat import get_locale_encoding, is_bytes
|
from platformio.compat import get_locale_encoding, is_bytes
|
||||||
|
from platformio.home import helpers
|
||||||
|
|
||||||
|
|
||||||
class MultiThreadingStdStream(object):
|
class MultiThreadingStdStream(object):
|
@ -21,8 +21,8 @@ import time
|
|||||||
from ajsonrpc.core import JSONRPC20DispatchException
|
from ajsonrpc.core import JSONRPC20DispatchException
|
||||||
|
|
||||||
from platformio import exception, fs
|
from platformio import exception, fs
|
||||||
from platformio.commands.home.rpc.handlers.app import AppRPC
|
from platformio.home.rpc.handlers.app import AppRPC
|
||||||
from platformio.commands.home.rpc.handlers.piocore import PIOCoreRPC
|
from platformio.home.rpc.handlers.piocore import PIOCoreRPC
|
||||||
from platformio.package.manager.platform import PlatformPackageManager
|
from platformio.package.manager.platform import PlatformPackageManager
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
from platformio.project.exception import ProjectError
|
from platformio.project.exception import ProjectError
|
@ -24,16 +24,16 @@ from starlette.routing import Mount, Route, WebSocketRoute
|
|||||||
from starlette.staticfiles import StaticFiles
|
from starlette.staticfiles import StaticFiles
|
||||||
from starlette.status import HTTP_403_FORBIDDEN
|
from starlette.status import HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
from platformio.commands.home.rpc.handlers.account import AccountRPC
|
|
||||||
from platformio.commands.home.rpc.handlers.app import AppRPC
|
|
||||||
from platformio.commands.home.rpc.handlers.ide import IDERPC
|
|
||||||
from platformio.commands.home.rpc.handlers.misc import MiscRPC
|
|
||||||
from platformio.commands.home.rpc.handlers.os import OSRPC
|
|
||||||
from platformio.commands.home.rpc.handlers.piocore import PIOCoreRPC
|
|
||||||
from platformio.commands.home.rpc.handlers.project import ProjectRPC
|
|
||||||
from platformio.commands.home.rpc.server import WebSocketJSONRPCServerFactory
|
|
||||||
from platformio.compat import aio_get_running_loop
|
from platformio.compat import aio_get_running_loop
|
||||||
from platformio.exception import PlatformioException
|
from platformio.exception import PlatformioException
|
||||||
|
from platformio.home.rpc.handlers.account import AccountRPC
|
||||||
|
from platformio.home.rpc.handlers.app import AppRPC
|
||||||
|
from platformio.home.rpc.handlers.ide import IDERPC
|
||||||
|
from platformio.home.rpc.handlers.misc import MiscRPC
|
||||||
|
from platformio.home.rpc.handlers.os import OSRPC
|
||||||
|
from platformio.home.rpc.handlers.piocore import PIOCoreRPC
|
||||||
|
from platformio.home.rpc.handlers.project import ProjectRPC
|
||||||
|
from platformio.home.rpc.server import WebSocketJSONRPCServerFactory
|
||||||
from platformio.package.manager.core import get_core_package_dir
|
from platformio.package.manager.core import get_core_package_dir
|
||||||
from platformio.proc import force_exit
|
from platformio.proc import force_exit
|
||||||
|
|
@ -115,7 +115,7 @@ class HTTPClient(object):
|
|||||||
)
|
)
|
||||||
if with_authorization and "Authorization" not in headers:
|
if with_authorization and "Authorization" not in headers:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from platformio.clients.account import AccountClient
|
from platformio.account.client import AccountClient
|
||||||
|
|
||||||
headers["Authorization"] = (
|
headers["Authorization"] = (
|
||||||
"Bearer %s" % AccountClient().fetch_authentication_token()
|
"Bearer %s" % AccountClient().fetch_authentication_token()
|
@ -21,15 +21,15 @@ import semantic_version
|
|||||||
|
|
||||||
from platformio import __version__, app, exception, fs, telemetry
|
from platformio import __version__, app, exception, fs, telemetry
|
||||||
from platformio.cache import cleanup_content_cache
|
from platformio.cache import cleanup_content_cache
|
||||||
from platformio.clients import http
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.commands import PlatformioCLI
|
|
||||||
from platformio.commands.platform import platform_update as cmd_platform_update
|
from platformio.commands.platform import platform_update as cmd_platform_update
|
||||||
from platformio.commands.system.prune import calculate_unnecessary_system_data
|
|
||||||
from platformio.commands.upgrade import get_latest_version
|
from platformio.commands.upgrade import get_latest_version
|
||||||
|
from platformio.http import HTTPClientError, InternetIsOffline, ensure_internet_on
|
||||||
from platformio.package.manager.core import update_core_packages
|
from platformio.package.manager.core import update_core_packages
|
||||||
from platformio.package.manager.tool import ToolPackageManager
|
from platformio.package.manager.tool import ToolPackageManager
|
||||||
from platformio.package.meta import PackageSpec
|
from platformio.package.meta import PackageSpec
|
||||||
from platformio.package.version import pepver_to_semver
|
from platformio.package.version import pepver_to_semver
|
||||||
|
from platformio.system.prune import calculate_unnecessary_system_data
|
||||||
|
|
||||||
|
|
||||||
def on_platformio_start(ctx, force, caller):
|
def on_platformio_start(ctx, force, caller):
|
||||||
@ -51,8 +51,8 @@ def on_platformio_end(ctx, result): # pylint: disable=unused-argument
|
|||||||
check_platformio_upgrade()
|
check_platformio_upgrade()
|
||||||
check_prune_system()
|
check_prune_system()
|
||||||
except (
|
except (
|
||||||
http.HTTPClientError,
|
HTTPClientError,
|
||||||
http.InternetIsOffline,
|
InternetIsOffline,
|
||||||
exception.GetLatestVersionError,
|
exception.GetLatestVersionError,
|
||||||
):
|
):
|
||||||
click.secho(
|
click.secho(
|
||||||
@ -142,8 +142,8 @@ def after_upgrade(ctx):
|
|||||||
)
|
)
|
||||||
click.secho("Please remove multiple PIO Cores from a system:", fg="yellow")
|
click.secho("Please remove multiple PIO Cores from a system:", fg="yellow")
|
||||||
click.secho(
|
click.secho(
|
||||||
"https://docs.platformio.org/page/faq.html"
|
"https://docs.platformio.org/en/latest/core"
|
||||||
"#multiple-platformio-cores-in-a-system",
|
"/installation/troubleshooting.html",
|
||||||
fg="cyan",
|
fg="cyan",
|
||||||
)
|
)
|
||||||
click.secho("*" * terminal_width, fg="yellow")
|
click.secho("*" * terminal_width, fg="yellow")
|
||||||
@ -213,7 +213,7 @@ def check_platformio_upgrade():
|
|||||||
if not last_checked_time:
|
if not last_checked_time:
|
||||||
return
|
return
|
||||||
|
|
||||||
http.ensure_internet_on(raise_exception=True)
|
ensure_internet_on(raise_exception=True)
|
||||||
|
|
||||||
# Update PlatformIO Core packages
|
# Update PlatformIO Core packages
|
||||||
update_core_packages()
|
update_core_packages()
|
||||||
|
@ -264,7 +264,8 @@ def _uninstall_project_unused_libdeps(project_env, options):
|
|||||||
lm.uninstall(spec)
|
lm.uninstall(spec)
|
||||||
except UnknownPackageError:
|
except UnknownPackageError:
|
||||||
pass
|
pass
|
||||||
storage_dir.mkdir(parents=True, exist_ok=True)
|
if not storage_dir.is_dir():
|
||||||
|
storage_dir.mkdir(parents=True)
|
||||||
integrity_dat.write_text("\n".join(lib_deps), encoding="utf-8")
|
integrity_dat.write_text("\n".join(lib_deps), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,14 +21,14 @@ import click
|
|||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from platformio import fs
|
from platformio import fs
|
||||||
from platformio.clients.account import AccountClient
|
from platformio.account.client import AccountClient
|
||||||
from platformio.clients.registry import RegistryClient
|
|
||||||
from platformio.exception import UserSideException
|
from platformio.exception import UserSideException
|
||||||
from platformio.package.manifest.parser import ManifestParserFactory
|
from platformio.package.manifest.parser import ManifestParserFactory
|
||||||
from platformio.package.manifest.schema import ManifestSchema
|
from platformio.package.manifest.schema import ManifestSchema
|
||||||
from platformio.package.meta import PackageType
|
from platformio.package.meta import PackageType
|
||||||
from platformio.package.pack import PackagePacker
|
from platformio.package.pack import PackagePacker
|
||||||
from platformio.package.unpack import FileUnpacker, TARArchiver
|
from platformio.package.unpack import FileUnpacker, TARArchiver
|
||||||
|
from platformio.registry.client import RegistryClient
|
||||||
|
|
||||||
|
|
||||||
def validate_datetime(ctx, param, value): # pylint: disable=unused-argument
|
def validate_datetime(ctx, param, value): # pylint: disable=unused-argument
|
||||||
|
@ -17,7 +17,7 @@ import math
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import util
|
from platformio import util
|
||||||
from platformio.clients.registry import RegistryClient
|
from platformio.registry.client import RegistryClient
|
||||||
|
|
||||||
|
|
||||||
@click.command("search", short_help="Search for packages")
|
@click.command("search", short_help="Search for packages")
|
||||||
|
@ -18,10 +18,10 @@ import click
|
|||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
|
|
||||||
from platformio import fs, util
|
from platformio import fs, util
|
||||||
from platformio.clients.registry import RegistryClient
|
|
||||||
from platformio.exception import UserSideException
|
from platformio.exception import UserSideException
|
||||||
from platformio.package.manager._registry import PackageManagerRegistryMixin
|
from platformio.package.manager._registry import PackageManagerRegistryMixin
|
||||||
from platformio.package.meta import PackageSpec, PackageType
|
from platformio.package.meta import PackageSpec, PackageType
|
||||||
|
from platformio.registry.client import RegistryClient
|
||||||
|
|
||||||
|
|
||||||
@click.command("show", short_help="Show package information")
|
@click.command("show", short_help="Show package information")
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio.clients.account import AccountClient
|
from platformio.account.client import AccountClient
|
||||||
from platformio.clients.registry import RegistryClient
|
|
||||||
from platformio.package.meta import PackageSpec, PackageType
|
from platformio.package.meta import PackageSpec, PackageType
|
||||||
|
from platformio.registry.client import RegistryClient
|
||||||
|
|
||||||
|
|
||||||
@click.command("unpublish", short_help="Remove a pushed package from the registry")
|
@click.command("unpublish", short_help="Remove a pushed package from the registry")
|
||||||
|
@ -12,97 +12,15 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import json
|
|
||||||
import time
|
import time
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from platformio import __registry_mirror_hosts__
|
|
||||||
from platformio.cache import ContentCache
|
|
||||||
from platformio.clients.http import HTTPClient
|
|
||||||
from platformio.clients.registry import RegistryClient
|
|
||||||
from platformio.package.exception import UnknownPackageError
|
from platformio.package.exception import UnknownPackageError
|
||||||
from platformio.package.meta import PackageSpec
|
from platformio.package.meta import PackageSpec
|
||||||
from platformio.package.version import cast_version_to_semver
|
from platformio.package.version import cast_version_to_semver
|
||||||
|
from platformio.registry.client import RegistryClient
|
||||||
|
from platformio.registry.mirror import RegistryFileMirrorIterator
|
||||||
class RegistryFileMirrorIterator(object):
|
|
||||||
|
|
||||||
HTTP_CLIENT_INSTANCES = {}
|
|
||||||
|
|
||||||
def __init__(self, download_url):
|
|
||||||
self.download_url = download_url
|
|
||||||
self._url_parts = urlparse(download_url)
|
|
||||||
self._mirror = "%s://%s" % (self._url_parts.scheme, self._url_parts.netloc)
|
|
||||||
self._visited_mirrors = []
|
|
||||||
|
|
||||||
def __iter__(self): # pylint: disable=non-iterator-returned
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __next__(self):
|
|
||||||
cache_key = ContentCache.key_from_args(
|
|
||||||
"head", self.download_url, self._visited_mirrors
|
|
||||||
)
|
|
||||||
with ContentCache("http") as cc:
|
|
||||||
result = cc.get(cache_key)
|
|
||||||
if result is not None:
|
|
||||||
try:
|
|
||||||
headers = json.loads(result)
|
|
||||||
return (
|
|
||||||
headers["Location"],
|
|
||||||
headers["X-PIO-Content-SHA256"],
|
|
||||||
)
|
|
||||||
except (ValueError, KeyError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
http = self.get_http_client()
|
|
||||||
response = http.send_request(
|
|
||||||
"head",
|
|
||||||
self._url_parts.path,
|
|
||||||
allow_redirects=False,
|
|
||||||
params=dict(bypass=",".join(self._visited_mirrors))
|
|
||||||
if self._visited_mirrors
|
|
||||||
else None,
|
|
||||||
x_with_authorization=RegistryClient.allowed_private_packages(),
|
|
||||||
)
|
|
||||||
stop_conditions = [
|
|
||||||
response.status_code not in (302, 307),
|
|
||||||
not response.headers.get("Location"),
|
|
||||||
not response.headers.get("X-PIO-Mirror"),
|
|
||||||
response.headers.get("X-PIO-Mirror") in self._visited_mirrors,
|
|
||||||
]
|
|
||||||
if any(stop_conditions):
|
|
||||||
raise StopIteration
|
|
||||||
self._visited_mirrors.append(response.headers.get("X-PIO-Mirror"))
|
|
||||||
cc.set(
|
|
||||||
cache_key,
|
|
||||||
json.dumps(
|
|
||||||
{
|
|
||||||
"Location": response.headers.get("Location"),
|
|
||||||
"X-PIO-Content-SHA256": response.headers.get(
|
|
||||||
"X-PIO-Content-SHA256"
|
|
||||||
),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
"1h",
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
response.headers.get("Location"),
|
|
||||||
response.headers.get("X-PIO-Content-SHA256"),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_http_client(self):
|
|
||||||
if self._mirror not in RegistryFileMirrorIterator.HTTP_CLIENT_INSTANCES:
|
|
||||||
endpoints = [self._mirror]
|
|
||||||
for host in __registry_mirror_hosts__:
|
|
||||||
endpoint = f"https://dl.{host}"
|
|
||||||
if endpoint not in endpoints:
|
|
||||||
endpoints.append(endpoint)
|
|
||||||
RegistryFileMirrorIterator.HTTP_CLIENT_INSTANCES[self._mirror] = HTTPClient(
|
|
||||||
endpoints
|
|
||||||
)
|
|
||||||
return RegistryFileMirrorIterator.HTTP_CLIENT_INSTANCES[self._mirror]
|
|
||||||
|
|
||||||
|
|
||||||
class PackageManagerRegistryMixin(object):
|
class PackageManagerRegistryMixin(object):
|
||||||
|
@ -21,7 +21,7 @@ import click
|
|||||||
import semantic_version
|
import semantic_version
|
||||||
|
|
||||||
from platformio import fs, util
|
from platformio import fs, util
|
||||||
from platformio.commands import PlatformioCLI
|
from platformio.cli import PlatformioCLI
|
||||||
from platformio.compat import ci_strings_are_equal
|
from platformio.compat import ci_strings_are_equal
|
||||||
from platformio.package.exception import ManifestException, MissingPackageManifestError
|
from platformio.package.exception import ManifestException, MissingPackageManifestError
|
||||||
from platformio.package.lockfile import LockFile
|
from platformio.package.lockfile import LockFile
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from platformio import util
|
from platformio import util
|
||||||
from platformio.clients.http import HTTPClientError, InternetIsOffline
|
from platformio.http import HTTPClientError, InternetIsOffline
|
||||||
from platformio.package.exception import UnknownPackageError
|
from platformio.package.exception import UnknownPackageError
|
||||||
from platformio.package.manager.base import BasePackageManager
|
from platformio.package.manager.base import BasePackageManager
|
||||||
from platformio.package.manager.core import get_installed_core_packages
|
from platformio.package.manager.core import get_installed_core_packages
|
||||||
|
@ -21,8 +21,8 @@ import tarfile
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from platformio import util
|
from platformio import util
|
||||||
from platformio.clients.http import fetch_remote_content
|
|
||||||
from platformio.compat import get_object_members, string_types
|
from platformio.compat import get_object_members, string_types
|
||||||
|
from platformio.http import fetch_remote_content
|
||||||
from platformio.package.exception import ManifestParserError, UnknownManifestError
|
from platformio.package.exception import ManifestParserError, UnknownManifestError
|
||||||
from platformio.project.helpers import is_platformio_project
|
from platformio.project.helpers import is_platformio_project
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ import requests
|
|||||||
import semantic_version
|
import semantic_version
|
||||||
from marshmallow import Schema, ValidationError, fields, validate, validates
|
from marshmallow import Schema, ValidationError, fields, validate, validates
|
||||||
|
|
||||||
from platformio.clients.http import fetch_remote_content
|
from platformio.http import fetch_remote_content
|
||||||
from platformio.package.exception import ManifestValidationError
|
from platformio.package.exception import ManifestValidationError
|
||||||
from platformio.util import memoized
|
from platformio.util import memoized
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from platformio import proc
|
from platformio import proc
|
||||||
@ -47,12 +46,12 @@ class VCSClientFactory(object):
|
|||||||
if not type_:
|
if not type_:
|
||||||
raise VCSBaseException("VCS: Unknown repository type %s" % remote_url)
|
raise VCSBaseException("VCS: Unknown repository type %s" % remote_url)
|
||||||
try:
|
try:
|
||||||
obj = getattr(sys.modules[__name__], "%sClient" % type_.capitalize())(
|
obj = globals()["%sClient" % type_.capitalize()](
|
||||||
src_dir, remote_url, tag, silent
|
src_dir, remote_url, tag, silent
|
||||||
)
|
)
|
||||||
assert isinstance(obj, VCSClientBase)
|
assert isinstance(obj, VCSClientBase)
|
||||||
return obj
|
return obj
|
||||||
except (AttributeError, AssertionError):
|
except (KeyError, AssertionError):
|
||||||
raise VCSBaseException("VCS: Unknown repository type %s" % remote_url)
|
raise VCSBaseException("VCS: Unknown repository type %s" % remote_url)
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
from platformio import fs
|
from platformio import fs
|
||||||
from platformio.compat import load_python_module
|
from platformio.compat import load_python_module
|
||||||
from platformio.package.meta import PackageItem
|
from platformio.package.meta import PackageItem
|
||||||
from platformio.platform.base import PlatformBase
|
from platformio.platform import base
|
||||||
from platformio.platform.exception import UnknownPlatform
|
from platformio.platform.exception import UnknownPlatform
|
||||||
|
|
||||||
|
|
||||||
@ -29,14 +30,16 @@ class PlatformFactory(object):
|
|||||||
return "%sPlatform" % name.lower().capitalize()
|
return "%sPlatform" % name.lower().capitalize()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def load_module(name, path):
|
def load_platform_module(name, path):
|
||||||
|
# backward compatibiility with the legacy dev-platforms
|
||||||
|
sys.modules["platformio.managers.platform"] = base
|
||||||
try:
|
try:
|
||||||
return load_python_module("platformio.platform.%s" % name, path)
|
return load_python_module("platformio.platform.%s" % name, path)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise UnknownPlatform(name)
|
raise UnknownPlatform(name)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls, pkg_or_spec, autoinstall=False) -> PlatformBase:
|
def new(cls, pkg_or_spec, autoinstall=False) -> base.PlatformBase:
|
||||||
# pylint: disable=import-outside-toplevel
|
# pylint: disable=import-outside-toplevel
|
||||||
from platformio.package.manager.platform import PlatformPackageManager
|
from platformio.package.manager.platform import PlatformPackageManager
|
||||||
|
|
||||||
@ -72,16 +75,16 @@ class PlatformFactory(object):
|
|||||||
platform_cls = None
|
platform_cls = None
|
||||||
if os.path.isfile(os.path.join(platform_dir, "platform.py")):
|
if os.path.isfile(os.path.join(platform_dir, "platform.py")):
|
||||||
platform_cls = getattr(
|
platform_cls = getattr(
|
||||||
cls.load_module(
|
cls.load_platform_module(
|
||||||
platform_name, os.path.join(platform_dir, "platform.py")
|
platform_name, os.path.join(platform_dir, "platform.py")
|
||||||
),
|
),
|
||||||
cls.get_clsname(platform_name),
|
cls.get_clsname(platform_name),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
platform_cls = type(
|
platform_cls = type(
|
||||||
str(cls.get_clsname(platform_name)), (PlatformBase,), {}
|
str(cls.get_clsname(platform_name)), (base.PlatformBase,), {}
|
||||||
)
|
)
|
||||||
|
|
||||||
_instance = platform_cls(os.path.join(platform_dir, "platform.json"))
|
_instance = platform_cls(os.path.join(platform_dir, "platform.json"))
|
||||||
assert isinstance(_instance, PlatformBase)
|
assert isinstance(_instance, base.PlatformBase)
|
||||||
return _instance
|
return _instance
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user