micropython-stubber 1.24.1__py3-none-any.whl → 1.24.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {micropython_stubber-1.24.1.dist-info → micropython_stubber-1.24.4.dist-info}/METADATA +9 -29
  2. micropython_stubber-1.24.4.dist-info/RECORD +107 -0
  3. {micropython_stubber-1.24.1.dist-info → micropython_stubber-1.24.4.dist-info}/WHEEL +1 -1
  4. stubber/__init__.py +1 -1
  5. stubber/board/createstubs.py +44 -38
  6. stubber/board/createstubs_db.py +17 -12
  7. stubber/board/createstubs_db_min.py +63 -63
  8. stubber/board/createstubs_db_mpy.mpy +0 -0
  9. stubber/board/createstubs_mem.py +17 -12
  10. stubber/board/createstubs_mem_min.py +99 -99
  11. stubber/board/createstubs_mem_mpy.mpy +0 -0
  12. stubber/board/createstubs_min.py +111 -112
  13. stubber/board/createstubs_mpy.mpy +0 -0
  14. stubber/board/modulelist.txt +27 -27
  15. stubber/codemod/board.py +1 -1
  16. stubber/codemod/enrich.py +13 -13
  17. stubber/codemod/merge_docstub.py +83 -53
  18. stubber/codemod/visitors/type_helpers.py +143 -41
  19. stubber/commands/enrich_folder_cmd.py +17 -17
  20. stubber/commands/get_docstubs_cmd.py +27 -9
  21. stubber/commands/get_frozen_cmd.py +1 -0
  22. stubber/commands/merge_cmd.py +2 -4
  23. stubber/merge_config.py +5 -36
  24. stubber/minify.py +3 -3
  25. stubber/modcat.py +118 -0
  26. stubber/publish/merge_docstubs.py +22 -5
  27. stubber/publish/stubpackage.py +33 -28
  28. stubber/rst/lookup.py +6 -23
  29. stubber/rst/reader.py +8 -13
  30. stubber/stubs_from_docs.py +2 -1
  31. stubber/tools/manifestfile.py +2 -1
  32. stubber/{cst_transformer.py → typing_collector.py} +36 -4
  33. micropython_stubber-1.24.1.dist-info/RECORD +0 -161
  34. mpflash/README.md +0 -220
  35. mpflash/libusb_flash.ipynb +0 -203
  36. mpflash/mpflash/__init__.py +0 -0
  37. mpflash/mpflash/add_firmware.py +0 -98
  38. mpflash/mpflash/ask_input.py +0 -236
  39. mpflash/mpflash/basicgit.py +0 -324
  40. mpflash/mpflash/bootloader/__init__.py +0 -2
  41. mpflash/mpflash/bootloader/activate.py +0 -60
  42. mpflash/mpflash/bootloader/detect.py +0 -82
  43. mpflash/mpflash/bootloader/manual.py +0 -101
  44. mpflash/mpflash/bootloader/micropython.py +0 -12
  45. mpflash/mpflash/bootloader/touch1200.py +0 -36
  46. mpflash/mpflash/cli_download.py +0 -129
  47. mpflash/mpflash/cli_flash.py +0 -224
  48. mpflash/mpflash/cli_group.py +0 -111
  49. mpflash/mpflash/cli_list.py +0 -87
  50. mpflash/mpflash/cli_main.py +0 -39
  51. mpflash/mpflash/common.py +0 -217
  52. mpflash/mpflash/config.py +0 -44
  53. mpflash/mpflash/connected.py +0 -96
  54. mpflash/mpflash/download.py +0 -364
  55. mpflash/mpflash/downloaded.py +0 -138
  56. mpflash/mpflash/errors.py +0 -9
  57. mpflash/mpflash/flash/__init__.py +0 -55
  58. mpflash/mpflash/flash/esp.py +0 -59
  59. mpflash/mpflash/flash/stm32.py +0 -19
  60. mpflash/mpflash/flash/stm32_dfu.py +0 -104
  61. mpflash/mpflash/flash/uf2/__init__.py +0 -88
  62. mpflash/mpflash/flash/uf2/boardid.py +0 -15
  63. mpflash/mpflash/flash/uf2/linux.py +0 -136
  64. mpflash/mpflash/flash/uf2/macos.py +0 -42
  65. mpflash/mpflash/flash/uf2/uf2disk.py +0 -12
  66. mpflash/mpflash/flash/uf2/windows.py +0 -43
  67. mpflash/mpflash/flash/worklist.py +0 -170
  68. mpflash/mpflash/list.py +0 -106
  69. mpflash/mpflash/logger.py +0 -41
  70. mpflash/mpflash/mpboard_id/__init__.py +0 -98
  71. mpflash/mpflash/mpboard_id/add_boards.py +0 -262
  72. mpflash/mpflash/mpboard_id/board.py +0 -37
  73. mpflash/mpflash/mpboard_id/board_id.py +0 -90
  74. mpflash/mpflash/mpboard_id/board_info.zip +0 -0
  75. mpflash/mpflash/mpboard_id/store.py +0 -48
  76. mpflash/mpflash/mpremoteboard/__init__.py +0 -271
  77. mpflash/mpflash/mpremoteboard/mpy_fw_info.py +0 -152
  78. mpflash/mpflash/mpremoteboard/runner.py +0 -140
  79. mpflash/mpflash/vendor/board_database.py +0 -185
  80. mpflash/mpflash/vendor/click_aliases.py +0 -91
  81. mpflash/mpflash/vendor/dfu.py +0 -165
  82. mpflash/mpflash/vendor/pydfu.py +0 -605
  83. mpflash/mpflash/vendor/readme.md +0 -12
  84. mpflash/mpflash/versions.py +0 -123
  85. mpflash/poetry.lock +0 -2603
  86. mpflash/pyproject.toml +0 -66
  87. mpflash/stm32_udev_rules.md +0 -63
  88. stubber/codemod/test_enrich.py +0 -87
  89. {micropython_stubber-1.24.1.dist-info → micropython_stubber-1.24.4.dist-info}/LICENSE +0 -0
  90. {micropython_stubber-1.24.1.dist-info → micropython_stubber-1.24.4.dist-info}/entry_points.txt +0 -0
@@ -1,98 +0,0 @@
1
- import shutil
2
- from pathlib import Path
3
- from typing import Union
4
-
5
- import jsonlines
6
- import requests
7
- from loguru import logger as log
8
-
9
- # re-use logic from mpremote
10
- from mpremote.mip import _rewrite_url as rewrite_url # type: ignore
11
-
12
- from mpflash.common import FWInfo
13
- from mpflash.config import config
14
- from mpflash.versions import get_preview_mp_version, get_stable_mp_version
15
-
16
-
17
- def add_firmware(
18
- source: Union[Path, str],
19
- new_fw: FWInfo,
20
- *,
21
- force: bool = False,
22
- custom: bool = False,
23
- description: str = "",
24
- ) -> bool:
25
- """Add a firmware to the firmware folder.
26
-
27
- stored in the port folder, with the same filename as the source.
28
-
29
- """
30
- # Check minimal info needed
31
- if not new_fw.port or not new_fw.board:
32
- log.error("Port and board are required")
33
- return False
34
- if not isinstance(source, Path) and not source.startswith("http"):
35
- log.error(f"Invalid source {source}")
36
- return False
37
-
38
- # use sensible defaults
39
- source_2 = Path(source)
40
- new_fw.ext = new_fw.ext or source_2.suffix
41
- new_fw.variant = new_fw.variant or new_fw.board
42
- new_fw.custom = new_fw.custom or custom
43
- new_fw.description = new_fw.description or description
44
- if not new_fw.version:
45
- # TODO: Get version from filename
46
- # or use the last preview version
47
- new_fw.version = get_preview_mp_version() if new_fw.preview else get_stable_mp_version()
48
-
49
- config.firmware_folder.mkdir(exist_ok=True)
50
-
51
- fw_filename = config.firmware_folder / new_fw.port / source_2.name
52
-
53
- new_fw.filename = str(fw_filename.relative_to(config.firmware_folder))
54
- new_fw.firmware = source.as_uri() if isinstance(source, Path) else source
55
-
56
- if not copy_firmware(source, fw_filename, force):
57
- log.error(f"Failed to copy {source} to {fw_filename}")
58
- return False
59
- # add to inventory
60
- with jsonlines.open(config.firmware_folder / "firmware.jsonl", "a") as writer:
61
- log.info(f"Adding {new_fw.port} {new_fw.board}")
62
- log.info(f" to {fw_filename}")
63
-
64
- writer.write(new_fw.to_dict())
65
- return True
66
-
67
-
68
- def copy_firmware(source: Union[Path, str], fw_filename: Path, force: bool = False):
69
- """Add a firmware to the firmware folder.
70
- stored in the port folder, with the same filename as the source.
71
- """
72
- if fw_filename.exists() and not force:
73
- log.error(f" {fw_filename} already exists. Use --force to overwrite")
74
- return False
75
- fw_filename.parent.mkdir(exist_ok=True)
76
- if isinstance(source, Path):
77
- if not source.exists():
78
- log.error(f"File {source} does not exist")
79
- return False
80
- # file copy
81
- log.debug(f"Copy {source} to {fw_filename}")
82
- shutil.copy(source, fw_filename)
83
- return True
84
- # handle github urls
85
- url = rewrite_url(source)
86
- if str(source).startswith("http://") or str(source).startswith("https://"):
87
- log.debug(f"Download {url} to {fw_filename}")
88
- response = requests.get(url)
89
-
90
- if response.status_code == 200:
91
- with open(fw_filename, "wb") as file:
92
- file.write(response.content)
93
- log.info("File downloaded and saved successfully.")
94
- return True
95
- else:
96
- print("Failed to download the file.")
97
- return False
98
- return False
@@ -1,236 +0,0 @@
1
- """
2
- Interactive input for mpflash.
3
-
4
- Note: The prompts can use "{version}" and "{action}" to insert the version and action in the prompt without needing an f-string.
5
- The values are provided from the answers dictionary.
6
- """
7
-
8
- from typing import List, Sequence, Tuple, Union
9
-
10
- from loguru import logger as log
11
-
12
- from .common import DownloadParams, FlashParams, ParamType
13
- from .config import config
14
- from .mpboard_id import (get_known_boards_for_port, get_known_ports,
15
- known_stored_boards)
16
- from .mpremoteboard import MPRemoteBoard
17
- from .versions import micropython_versions
18
-
19
-
20
- def ask_missing_params(
21
- params: ParamType,
22
- ) -> ParamType:
23
- """
24
- Asks the user for parameters that have not been supplied on the commandline and returns the updated params.
25
-
26
- Args:
27
- params (ParamType): The parameters to be updated.
28
-
29
- Returns:
30
- ParamType: The updated parameters.
31
- """
32
- if not config.interactive:
33
- # no interactivity allowed
34
- log.info("Interactive mode disabled. Skipping ask for user input.")
35
- return params
36
-
37
- import inquirer
38
-
39
- log.trace(f"ask_missing_params: {params}")
40
-
41
- # if action flash, single input
42
- # if action download, multiple input
43
- multi_select = isinstance(params, DownloadParams)
44
- action = "download" if isinstance(params, DownloadParams) else "flash"
45
-
46
- questions = []
47
- answers: dict[str, Union[str, List]] = {"action": action}
48
- if not multi_select:
49
- if not params.serial or "?" in params.serial:
50
- questions.append(ask_serialport(multi_select=False, bluetooth=False))
51
- else:
52
- answers["serial"] = params.serial
53
-
54
- if params.versions == [] or "?" in params.versions:
55
- questions.append(ask_mp_version(multi_select=multi_select, action=action))
56
- else:
57
- # versions is used to show only the boards for the selected versions
58
- answers["versions"] = params.versions # type: ignore
59
-
60
- if not params.boards or "?" in params.boards:
61
- questions.extend(ask_port_board(multi_select=multi_select, action=action))
62
- if questions:
63
- answers = inquirer.prompt(questions, answers=answers) # type: ignore
64
- if not answers:
65
- # input cancelled by user
66
- return [] # type: ignore
67
- log.trace(f"answers: {answers}")
68
- if isinstance(params, FlashParams) and "serial" in answers:
69
- if isinstance(answers["serial"], str):
70
- answers["serial"] = [answers["serial"]]
71
- params.serial = [s.split()[0] for s in answers["serial"]] # split to remove the description
72
- if "port" in answers:
73
- # params.ports = [p for p in params.ports if p != "?"] # remove the "?" if present
74
- if isinstance(answers["port"], str):
75
- params.ports.append(answers["port"])
76
- elif isinstance(answers["port"], list): # type: ignore
77
- params.ports.extend(answers["port"])
78
- else:
79
- raise ValueError(f"Unexpected type for answers['port']: {type(answers['port'])}")
80
-
81
- if "boards" in answers:
82
- params.boards = [b for b in params.boards if b != "?"] # remove the "?" if present
83
- params.boards.extend(answers["boards"] if isinstance(answers["boards"], list) else [answers["boards"]])
84
- if "versions" in answers:
85
- params.versions = [v for v in params.versions if v != "?"] # remove the "?" if present
86
- # make sure it is a list
87
- if isinstance(answers["versions"], (list, tuple)):
88
- params.versions.extend(answers["versions"])
89
- else:
90
- params.versions.append(answers["versions"])
91
- # remove duplicates
92
- params.ports = list(set(params.ports))
93
- params.boards = list(set(params.boards))
94
- params.versions = list(set(params.versions))
95
- log.trace(f"ask_missing_params returns: {params}")
96
-
97
- return params
98
-
99
-
100
- def filter_matching_boards(answers: dict) -> Sequence[Tuple[str, str]]:
101
- """
102
- Filters the known boards based on the selected versions and returns the filtered boards.
103
-
104
- Args:
105
- answers (dict): The user's answers.
106
-
107
- Returns:
108
- Sequence[Tuple[str, str]]: The filtered boards.
109
- """
110
- versions = None
111
- # if version is not asked ; then need to get the version from the inputs
112
- if "versions" in answers:
113
- versions = list(answers["versions"])
114
- if "stable" in versions:
115
- versions.remove("stable")
116
- versions.append(micropython_versions()[-2]) # latest stable
117
- elif "preview" in versions:
118
- versions.remove("preview")
119
- versions.extend((micropython_versions()[-1], micropython_versions()[-2])) # latest preview and stable
120
-
121
- some_boards = known_stored_boards(answers["port"], versions) # or known_mp_boards(answers["port"])
122
-
123
- if some_boards:
124
- # Create a dictionary where the keys are the second elements of the tuples
125
- # This will automatically remove duplicates because dictionaries cannot have duplicate keys
126
- unique_dict = {item[1]: item for item in some_boards}
127
- # Get the values of the dictionary, which are the unique items from the original list
128
- some_boards = list(unique_dict.values())
129
- else:
130
- some_boards = [(f"No {answers['port']} boards found for version(s) {versions}", "")]
131
- return some_boards
132
-
133
-
134
- def ask_port_board(*, multi_select: bool, action: str):
135
- """
136
- Asks the user for the port and board selection.
137
-
138
- Args:
139
- questions (list): The list of questions to be asked.
140
- action (str): The action to be performed.
141
-
142
- Returns:
143
- None
144
- """
145
- # import only when needed to reduce load time
146
- import inquirer
147
-
148
- # if action flash, single input
149
- # if action download, multiple input
150
- inquirer_ux = inquirer.Checkbox if multi_select else inquirer.List
151
- return [
152
- inquirer.List(
153
- "port",
154
- message="Which port do you want to {action} " + "to {serial} ?" if action == "flash" else "?",
155
- choices=get_known_ports(),
156
- # autocomplete=True,
157
- ),
158
- inquirer_ux(
159
- "boards",
160
- message=(
161
- "Which {port} board firmware do you want to {action} " + "to {serial} ?" if action == "flash" else "?"
162
- ),
163
- choices=filter_matching_boards,
164
- validate=at_least_one_validation, # type: ignore
165
- # validate=lambda _, x: True if x else "Please select at least one board", # type: ignore
166
- ),
167
- ]
168
-
169
- def at_least_one_validation(answers, current) -> bool:
170
- import inquirer.errors
171
- if not current:
172
- raise inquirer.errors.ValidationError("", reason="Please select at least one item.")
173
- if isinstance(current, list) and not any(current):
174
- raise inquirer.errors.ValidationError("", reason="Please select at least one item.")
175
- return True
176
-
177
- def ask_mp_version(multi_select: bool, action: str):
178
- """
179
- Asks the user for the version selection.
180
-
181
- Args:
182
- questions (list): The list of questions to be asked.
183
- action (str): The action to be performed.
184
-
185
- Returns:
186
-
187
- """
188
- # import only when needed to reduce load time
189
- import inquirer
190
- import inquirer.errors
191
-
192
- input_ux = inquirer.Checkbox if multi_select else inquirer.List
193
-
194
- mp_versions: List[str] = micropython_versions()
195
- mp_versions.reverse() # newest first
196
-
197
- # remove the versions for which there are no known boards in the board_info.json
198
- # todo: this may be a little slow
199
- mp_versions = [v for v in mp_versions if "preview" in v or get_known_boards_for_port("stm32", [v])]
200
-
201
- message = "Which version(s) do you want to {action} " + ("to {serial} ?" if action == "flash" else "?")
202
- q = input_ux(
203
- # inquirer.List(
204
- "versions",
205
- message=message,
206
- # Hints would be nice , but needs a hint for each and every option
207
- # hints=["Use space to select multiple options"],
208
- choices=mp_versions,
209
- autocomplete=True,
210
- validate=at_least_one_validation, # type: ignore
211
- )
212
- return q
213
-
214
-
215
- def ask_serialport(*, multi_select: bool = False, bluetooth: bool = False):
216
- """
217
- Asks the user for the serial port selection.
218
-
219
- Args:
220
- questions (list): The list of questions to be asked.
221
- action (str): The action to be performed.
222
-
223
- Returns:
224
- None
225
- """
226
- # import only when needed to reduce load time
227
- import inquirer
228
-
229
- comports = MPRemoteBoard.connected_boards(bluetooth=bluetooth, description=True)
230
- return inquirer.List(
231
- "serial",
232
- message="Which serial port do you want to {action} ?",
233
- choices=comports,
234
- other=True,
235
- validate=lambda _, x: True if x else "Please select or enter a serial port", # type: ignore
236
- )
@@ -1,324 +0,0 @@
1
- """
2
- Simple Git module, where needed via powershell
3
-
4
- Some of the functions are based on the PyGithub module
5
- """
6
-
7
- import os
8
- import subprocess
9
- from pathlib import Path
10
- from typing import List, Optional, Union
11
-
12
- import cachetools.func
13
- from github import Auth, BadCredentialsException, Github
14
- from loguru import logger as log
15
- from packaging.version import parse
16
-
17
- # from mpflash.versions import SET_PREVIEW
18
-
19
- # Token with no permissions to avoid throttling
20
- # https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28#getting-a-higher-rate-limit
21
- PAT_NO_ACCESS = (
22
- "github_pat_"
23
- + "11AAHPVFQ0G4NTaQ73Bw5J"
24
- + "_fAp7K9sZ1qL8VFnI9g78eUlCdmOXHB3WzSdj2jtEYb4XF3N7PDJBl32qIxq"
25
- )
26
- PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
27
- GH_CLIENT = Github(auth=Auth.Token(PAT))
28
-
29
-
30
- def _run_local_git(
31
- cmd: List[str],
32
- repo: Optional[Union[Path, str]] = None,
33
- expect_stderr=False,
34
- capture_output=True,
35
- echo_output=True,
36
- ):
37
- "run a external (git) command in the repo's folder and deal with some of the errors"
38
- try:
39
- if repo:
40
- if isinstance(repo, str):
41
- repo = Path(repo)
42
- result = subprocess.run(
43
- cmd,
44
- capture_output=capture_output,
45
- check=True,
46
- cwd=repo.absolute().as_posix(),
47
- encoding="utf-8",
48
- )
49
- else:
50
- result = subprocess.run(
51
- cmd, capture_output=capture_output, check=True, encoding="utf-8"
52
- )
53
- except (NotADirectoryError, FileNotFoundError) as e: # pragma: no cover
54
- return None
55
- except subprocess.CalledProcessError as e: # pragma: no cover
56
- # add some logging for github actions
57
- log.error(f"{str(e)} : { e.stderr}")
58
- return None
59
- if result.stderr and result.stderr != b"":
60
- stderr = result.stderr
61
- if "cloning into" in stderr.lower():
62
- # log.info(stderr)
63
- expect_stderr = True
64
- if "warning" in stderr.lower():
65
- log.warning(stderr)
66
- expect_stderr = True
67
- elif capture_output and echo_output: # pragma: no cover
68
- log.info(stderr)
69
- if not expect_stderr:
70
- raise ChildProcessError(stderr)
71
-
72
- if result.returncode and result.returncode < 0:
73
- raise ChildProcessError(result.stderr)
74
- return result
75
-
76
-
77
- def clone(remote_repo: str, path: Path, shallow: bool = False, tag: Optional[str] = None) -> bool:
78
- """git clone [--depth 1] [--branch <tag_name>] <remote> <directory>"""
79
- cmd = ["git", "clone"]
80
- if shallow:
81
- cmd += ["--depth", "1"]
82
- if tag in {"preview", "latest", "master"}:
83
- tag = None
84
- cmd += [remote_repo, "--branch", tag, str(path)] if tag else [remote_repo, str(path)]
85
- if result := _run_local_git(cmd, expect_stderr=True, capture_output=False):
86
- return result.returncode == 0
87
- else:
88
- return False
89
-
90
-
91
- def get_local_tag(
92
- repo: Optional[Union[str, Path]] = None, abbreviate: bool = True
93
- ) -> Union[str, None]:
94
- """
95
- get the most recent git version tag of a local repo
96
- repo Path should be in the form of : repo = "./repo/micropython"
97
-
98
- returns the tag or None
99
- """
100
- if not repo:
101
- repo = Path(".")
102
- elif isinstance(repo, str):
103
- repo = Path(repo)
104
-
105
- result = _run_local_git(
106
- # ["git", "describe", "--tags"],
107
- ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"],
108
- repo=repo.as_posix(),
109
- expect_stderr=True,
110
- )
111
- if not result:
112
- return None
113
- tag: str = result.stdout
114
- tag = tag.replace("\r", "").replace("\n", "")
115
- if not abbreviate or "-" not in tag:
116
- return tag
117
- if "-preview" in tag:
118
- tag = tag.split("-preview")[0] + "-preview"
119
- return tag
120
-
121
-
122
- def get_local_tags(repo: Optional[Path] = None, minver: Optional[str] = None) -> List[str]:
123
- """
124
- get list of all tags of a local repo
125
- """
126
- if not repo:
127
- repo = Path(".")
128
-
129
- result = _run_local_git(["git", "tag", "-l"], repo=repo.as_posix(), expect_stderr=True)
130
- if not result or result.returncode != 0:
131
- return []
132
- tags = result.stdout.replace("\r", "").split("\n")
133
- tags = [tag for tag in tags if tag.startswith("v")]
134
- if minver:
135
- tags = [tag for tag in tags if parse(tag) >= parse(minver)]
136
- return sorted(tags)
137
-
138
-
139
- from github.GithubException import BadCredentialsException
140
-
141
-
142
- @cachetools.func.ttl_cache(maxsize=16, ttl=60) # 60 seconds
143
- def get_tags(repo: str, minver: Optional[str] = None) -> List[str]:
144
- """
145
- Get list of tag of a repote github repo.
146
- only the last -preview tag is kept
147
- """
148
- if not repo or not isinstance(repo, str) or "/" not in repo: # type: ignore
149
- return []
150
- try:
151
- gh_repo = GH_CLIENT.get_repo(repo)
152
- except BadCredentialsException as e:
153
- log.error(f"Github authentication error - {e}")
154
- return []
155
- except ConnectionError as e:
156
- # TODO: unable to capture the exeption
157
- log.warning(f"Unable to get tags - {e}")
158
- return []
159
- tags = [tag.name for tag in gh_repo.get_tags()]
160
- if minver:
161
- tags = [tag for tag in tags if parse(tag) >= parse(minver)]
162
- # remove all but the last preview
163
- tags = [t for t in sorted(tags[:-1]) if "-preview" not in t] + sorted(tags)[-1:]
164
- return tags
165
-
166
-
167
- def checkout_tag(tag: str, repo: Optional[Union[str, Path]] = None) -> bool:
168
- """
169
- checkout a specific git tag
170
- """
171
- cmd = ["git", "checkout", tag, "--quiet", "--force"]
172
- result = _run_local_git(cmd, repo=repo, expect_stderr=True, capture_output=True)
173
- if not result:
174
- return False
175
- # actually a good result
176
- msg = {result.stdout}
177
- if msg != {""}:
178
- log.warning(f"git message: {msg}")
179
- return True
180
-
181
-
182
- def sync_submodules(repo: Union[Path, str]) -> bool:
183
- """
184
- make sure any submodules are in sync
185
- """
186
- cmds = [
187
- ["git", "submodule", "sync", "--quiet"],
188
- # ["git", "submodule", "update", "--quiet"],
189
- ["git", "submodule", "update", "--init", "lib/micropython-lib"],
190
- ]
191
- for cmd in cmds:
192
- if result := _run_local_git(cmd, repo=repo, expect_stderr=True):
193
- # actually a good result
194
- log.debug(result.stderr)
195
- else:
196
- return False
197
- checkout_arduino_lib(Path(repo))
198
- return True
199
-
200
-
201
- def checkout_arduino_lib(mpy_path: Path):
202
- """
203
- Checkout the arduino-lib submodule repo if it exists
204
-
205
- This is needed as some of the arduino boards freeze modules originationg from the arduino-lib
206
- """
207
- # arduino_lib_path = mpy_path / "lib/arduino-lib"
208
- if (mpy_path / "lib/arduino-lib").exists():
209
- cmd = ["git", "submodule", "update", "--init", "lib/arduino-lib"]
210
- try:
211
- result = subprocess.run(cmd, cwd=mpy_path, check=True)
212
- log.info(f"checkout arduino-lib: {result.returncode}")
213
- except subprocess.CalledProcessError as e:
214
- log.warning("Could not check out arduino-lib, error: ", e)
215
-
216
-
217
- def checkout_commit(commit_hash: str, repo: Optional[Union[Path, str]] = None) -> bool:
218
- """
219
- Checkout a specific commit
220
- """
221
- cmd = ["git", "checkout", commit_hash, "--quiet", "--force"]
222
- result = _run_local_git(cmd, repo=repo, expect_stderr=True)
223
- if not result:
224
- return False
225
- # actually a good result
226
- log.debug(result.stderr)
227
- return True
228
-
229
-
230
- def switch_tag(tag: Union[str, Path], repo: Optional[Union[Path, str]] = None) -> bool:
231
- """
232
- switch to the specified version tag of a local repo
233
- repo should be in the form of : path/.git
234
- repo = '../micropython/.git'
235
- returns None
236
- """
237
-
238
- cmd = ["git", "switch", "--detach", tag, "--quiet", "--force"]
239
- result = _run_local_git(cmd, repo=repo, expect_stderr=True)
240
- if not result:
241
- return False
242
- # actually a good result
243
- log.debug(result.stderr)
244
- return True
245
-
246
-
247
- def switch_branch(branch: str, repo: Optional[Union[Path, str]] = None) -> bool:
248
- """
249
- switch to the specified branch in a local repo"
250
- repo should be in the form of : path/.git
251
- repo = '../micropython/.git'
252
- returns None
253
- """
254
- cmd = ["git", "switch", branch, "--quiet", "--force"]
255
- result = _run_local_git(cmd, repo=repo, expect_stderr=True)
256
- if not result:
257
- return False
258
- # actually a good result
259
- log.debug(result.stderr)
260
- return True
261
-
262
-
263
- def fetch(repo: Union[Path, str]) -> bool:
264
- """
265
- fetches a repo and all tags
266
- repo should be in the form of : path/.git
267
- repo = '../micropython/.git'
268
- returns True on success
269
- """
270
- if not repo:
271
- raise NotADirectoryError
272
-
273
- cmd = ["git", "fetch", "--all", "--tags", "--quiet"]
274
- result = _run_local_git(cmd, repo=repo, echo_output=False)
275
- return result.returncode == 0 if result else False
276
-
277
-
278
- def pull(repo: Union[Path, str], branch: str = "main") -> bool:
279
- """
280
- pull a repo origin into main
281
- repo should be in the form of : path/.git
282
- repo = '../micropython/.git'
283
- returns True on success
284
- """
285
- if not repo:
286
- raise NotADirectoryError
287
- repo = Path(repo)
288
- # first checkout HEAD
289
- cmd = ["git", "checkout", branch, "--quiet", "--force"]
290
- result = _run_local_git(cmd, repo=repo, expect_stderr=True)
291
- if not result:
292
- log.error("error during git checkout main", result)
293
- return False
294
-
295
- cmd = ["git", "pull", "origin", branch, "--quiet", "--autostash"]
296
- result = _run_local_git(cmd, repo=repo, expect_stderr=True)
297
- if not result:
298
- log.error("error durign pull", result)
299
- return False
300
- return result.returncode == 0
301
-
302
-
303
- def get_git_describe(folder: Optional[str] = None):
304
- """
305
- Based on MicroPython makeversionhdr.py
306
- returns : current git tag, commits ,commit hash : "v1.19.1-841-g3446"
307
- """
308
- # Note: git describe doesn't work if no tag is available
309
- try:
310
- git_describe = subprocess.check_output(
311
- ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"],
312
- stderr=subprocess.STDOUT,
313
- universal_newlines=True,
314
- cwd=folder,
315
- ).strip()
316
- except subprocess.CalledProcessError as er:
317
- if er.returncode == 128:
318
- # git exit code of 128 means no repository found
319
- return None
320
- git_describe = ""
321
- except OSError:
322
- return None
323
- # format
324
- return git_describe
@@ -1,2 +0,0 @@
1
- from .activate import enter_bootloader # type: ignore
2
- from .detect import in_bootloader # type: ignore