mpflash 0.9.1__py3-none-any.whl → 0.9.1.post2__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.
mpflash/basicgit.py ADDED
@@ -0,0 +1,284 @@
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, 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 = "github_pat" + "_11AAHPVFQ0qAkDnSUaMKSp" + "_ZkDl5NRRwBsUN6EYg9ahp1Dvj4FDDONnXVgimxC2EtpY7Q7BUKBoQ0Jq72X"
22
+ PAT = os.environ.get("GITHUB_TOKEN") or PAT_NO_ACCESS
23
+ GH_CLIENT = Github(auth=Auth.Token(PAT))
24
+
25
+
26
+ def _run_local_git(
27
+ cmd: List[str],
28
+ repo: Optional[Union[Path, str]] = None,
29
+ expect_stderr=False,
30
+ capture_output=True,
31
+ echo_output=True,
32
+ ):
33
+ "run a external (git) command in the repo's folder and deal with some of the errors"
34
+ try:
35
+ if repo:
36
+ if isinstance(repo, str):
37
+ repo = Path(repo)
38
+ result = subprocess.run(cmd, capture_output=capture_output, check=True, cwd=repo.absolute().as_posix(), encoding="utf-8")
39
+ else:
40
+ result = subprocess.run(cmd, capture_output=capture_output, check=True, encoding="utf-8")
41
+ except (NotADirectoryError, FileNotFoundError) as e: # pragma: no cover
42
+ return None
43
+ except subprocess.CalledProcessError as e: # pragma: no cover
44
+ # add some logging for github actions
45
+ log.error(f"{str(e)} : { e.stderr}")
46
+ return None
47
+ if result.stderr and result.stderr != b"":
48
+ stderr = result.stderr
49
+ if "cloning into" in stderr.lower():
50
+ # log.info(stderr)
51
+ expect_stderr = True
52
+ if "warning" in stderr.lower():
53
+ log.warning(stderr)
54
+ expect_stderr = True
55
+ elif capture_output and echo_output: # pragma: no cover
56
+ log.info(stderr)
57
+ if not expect_stderr:
58
+ raise ChildProcessError(stderr)
59
+
60
+ if result.returncode and result.returncode < 0:
61
+ raise ChildProcessError(result.stderr)
62
+ return result
63
+
64
+
65
+ def clone(remote_repo: str, path: Path, shallow: bool = False, tag: Optional[str] = None) -> bool:
66
+ """git clone [--depth 1] [--branch <tag_name>] <remote> <directory>"""
67
+ cmd = ["git", "clone"]
68
+ if shallow:
69
+ cmd += ["--depth", "1"]
70
+ if tag in {"preview", "latest", "master"}:
71
+ tag = None
72
+ cmd += [remote_repo, "--branch", tag, str(path)] if tag else [remote_repo, str(path)]
73
+ if result := _run_local_git(cmd, expect_stderr=True, capture_output=False):
74
+ return result.returncode == 0
75
+ else:
76
+ return False
77
+
78
+
79
+ def get_local_tag(repo: Optional[Union[str, Path]] = None, abbreviate: bool = True) -> Union[str, None]:
80
+ """
81
+ get the most recent git version tag of a local repo
82
+ repo Path should be in the form of : repo = "./repo/micropython"
83
+
84
+ returns the tag or None
85
+ """
86
+ if not repo:
87
+ repo = Path(".")
88
+ elif isinstance(repo, str):
89
+ repo = Path(repo)
90
+
91
+ result = _run_local_git(
92
+ # ["git", "describe", "--tags"],
93
+ ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"],
94
+ repo=repo.as_posix(),
95
+ expect_stderr=True,
96
+ )
97
+ if not result:
98
+ return None
99
+ tag: str = result.stdout
100
+ tag = tag.replace("\r", "").replace("\n", "")
101
+ if not abbreviate or "-" not in tag:
102
+ return tag
103
+ if "-preview" in tag:
104
+ tag = tag.split("-preview")[0] + "-preview"
105
+ return tag
106
+
107
+
108
+ def get_local_tags(repo: Optional[Path] = None, minver: Optional[str] = None) -> List[str]:
109
+ """
110
+ get list of all tags of a local repo
111
+ """
112
+ if not repo:
113
+ repo = Path(".")
114
+
115
+ result = _run_local_git(["git", "tag", "-l"], repo=repo.as_posix(), expect_stderr=True)
116
+ if not result or result.returncode != 0:
117
+ return []
118
+ tags = result.stdout.replace("\r", "").split("\n")
119
+ tags = [tag for tag in tags if tag.startswith("v")]
120
+ if minver:
121
+ tags = [tag for tag in tags if parse(tag) >= parse(minver)]
122
+ return sorted(tags)
123
+
124
+
125
+ @cachetools.func.ttl_cache(maxsize=16, ttl=60) # 60 seconds
126
+ def get_tags(repo: str, minver: Optional[str] = None) -> List[str]:
127
+ """
128
+ Get list of tag of a repote github repo
129
+ """
130
+ if not repo or not isinstance(repo, str) or "/" not in repo: # type: ignore
131
+ return []
132
+ try:
133
+ gh_repo = GH_CLIENT.get_repo(repo)
134
+ except ConnectionError as e:
135
+ # TODO: unable to capture the exeption
136
+ log.warning(f"Unable to get tags - {e}")
137
+ return []
138
+ tags = [tag.name for tag in gh_repo.get_tags()]
139
+ if minver:
140
+ tags = [tag for tag in tags if parse(tag) >= parse(minver)]
141
+ return sorted(tags)
142
+
143
+
144
+ def checkout_tag(tag: str, repo: Optional[Union[str, Path]] = None) -> bool:
145
+ """
146
+ checkout a specific git tag
147
+ """
148
+ cmd = ["git", "checkout", tag, "--quiet", "--force"]
149
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True, capture_output=True)
150
+ if not result:
151
+ return False
152
+ # actually a good result
153
+ msg = {result.stdout}
154
+ if msg != {""}:
155
+ log.warning(f"git message: {msg}")
156
+ return True
157
+
158
+
159
+ def sync_submodules(repo: Optional[Union[Path, str]] = None) -> bool:
160
+ """
161
+ make sure any submodules are in sync
162
+ """
163
+ cmds = [
164
+ ["git", "submodule", "sync", "--quiet"],
165
+ # ["git", "submodule", "update", "--quiet"],
166
+ ["git", "submodule", "update", "--init", "lib/micropython-lib"],
167
+ ]
168
+ for cmd in cmds:
169
+ if result := _run_local_git(cmd, repo=repo, expect_stderr=True):
170
+ # actually a good result
171
+ log.debug(result.stderr)
172
+ else:
173
+ return False
174
+ return True
175
+
176
+
177
+ def checkout_commit(commit_hash: str, repo: Optional[Union[Path, str]] = None) -> bool:
178
+ """
179
+ Checkout a specific commit
180
+ """
181
+ cmd = ["git", "checkout", commit_hash, "--quiet", "--force"]
182
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True)
183
+ if not result:
184
+ return False
185
+ # actually a good result
186
+ log.debug(result.stderr)
187
+ return True
188
+
189
+
190
+ def switch_tag(tag: Union[str, Path], repo: Optional[Union[Path, str]] = None) -> bool:
191
+ """
192
+ switch to the specified version tag of a local repo
193
+ repo should be in the form of : path/.git
194
+ repo = '../micropython/.git'
195
+ returns None
196
+ """
197
+
198
+ cmd = ["git", "switch", "--detach", tag, "--quiet", "--force"]
199
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True)
200
+ if not result:
201
+ return False
202
+ # actually a good result
203
+ log.debug(result.stderr)
204
+ return True
205
+
206
+
207
+ def switch_branch(branch: str, repo: Optional[Union[Path, str]] = None) -> bool:
208
+ """
209
+ switch to the specified branch in a local repo"
210
+ repo should be in the form of : path/.git
211
+ repo = '../micropython/.git'
212
+ returns None
213
+ """
214
+ cmd = ["git", "switch", branch, "--quiet", "--force"]
215
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True)
216
+ if not result:
217
+ return False
218
+ # actually a good result
219
+ log.debug(result.stderr)
220
+ return True
221
+
222
+
223
+ def fetch(repo: Union[Path, str]) -> bool:
224
+ """
225
+ fetches a repo
226
+ repo should be in the form of : path/.git
227
+ repo = '../micropython/.git'
228
+ returns True on success
229
+ """
230
+ if not repo:
231
+ raise NotADirectoryError
232
+
233
+ cmd = ["git", "fetch", "--all", "--tags", "--quiet"]
234
+ result = _run_local_git(cmd, repo=repo, echo_output=False)
235
+ return result.returncode == 0 if result else False
236
+
237
+
238
+ def pull(repo: Union[Path, str], branch: str = "main") -> bool:
239
+ """
240
+ pull a repo origin into main
241
+ repo should be in the form of : path/.git
242
+ repo = '../micropython/.git'
243
+ returns True on success
244
+ """
245
+ if not repo:
246
+ raise NotADirectoryError
247
+ repo = Path(repo)
248
+ # first checkout HEAD
249
+ cmd = ["git", "checkout", branch, "--quiet", "--force"]
250
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True)
251
+ if not result:
252
+ log.error("error during git checkout main", result)
253
+ return False
254
+
255
+ cmd = ["git", "pull", "origin", branch, "--quiet", "--autostash"]
256
+ result = _run_local_git(cmd, repo=repo, expect_stderr=True)
257
+ if not result:
258
+ log.error("error durign pull", result)
259
+ return False
260
+ return result.returncode == 0
261
+
262
+
263
+ def get_git_describe(folder: Optional[str] = None):
264
+ """
265
+ Based on MicroPython makeversionhdr.py
266
+ returns : current git tag, commits ,commit hash : "v1.19.1-841-g3446"
267
+ """
268
+ # Note: git describe doesn't work if no tag is available
269
+ try:
270
+ git_describe = subprocess.check_output(
271
+ ["git", "describe", "--tags", "--dirty", "--always", "--match", "v[1-9].*"],
272
+ stderr=subprocess.STDOUT,
273
+ universal_newlines=True,
274
+ cwd=folder,
275
+ ).strip()
276
+ except subprocess.CalledProcessError as er:
277
+ if er.returncode == 128:
278
+ # git exit code of 128 means no repository found
279
+ return None
280
+ git_describe = ""
281
+ except OSError:
282
+ return None
283
+ # format
284
+ return git_describe
mpflash/flash/worklist.py CHANGED
@@ -6,12 +6,11 @@ from typing import Dict, List, Optional, Tuple
6
6
  from loguru import logger as log
7
7
 
8
8
  from mpflash.common import FWInfo, filtered_comports
9
+ from mpflash.downloaded import find_downloaded_firmware
9
10
  from mpflash.errors import MPFlashError
10
-
11
- from ..downloaded import find_downloaded_firmware
12
- from ..list import show_mcus
13
- from ..mpboard_id import find_known_board
14
- from ..mpremoteboard import MPRemoteBoard
11
+ from mpflash.list import show_mcus
12
+ from mpflash.mpboard_id import find_known_board
13
+ from mpflash.mpremoteboard import MPRemoteBoard
15
14
 
16
15
  # #########################################################################################################
17
16
  WorkList = List[Tuple[MPRemoteBoard, FWInfo]]
@@ -41,9 +40,7 @@ def auto_update(
41
40
  wl: WorkList = []
42
41
  for mcu in conn_boards:
43
42
  if mcu.family not in ("micropython", "unknown"):
44
- log.warning(
45
- f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware"
46
- )
43
+ log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
47
44
  continue
48
45
  board_firmwares = find_downloaded_firmware(
49
46
  fw_folder=fw_folder,
@@ -12,7 +12,7 @@ import rich.table
12
12
  from rich.console import Console
13
13
  from rich.progress import track
14
14
 
15
- import basicgit as git
15
+ import mpflash.basicgit as git
16
16
  from mpflash.logger import log
17
17
  from mpflash.mpboard_id import Board
18
18
  from mpflash.mpboard_id.store import write_boardinfo_json
@@ -222,11 +222,7 @@ def make_table(board_list: List[Board]) -> rich.table.Table:
222
222
 
223
223
  def ask_mpy_path():
224
224
  """Ask the user for the path to the MicroPython repository."""
225
- questions = [
226
- inquirer.Text(
227
- "mpy_path", message="Enter the path to the MicroPython repository", default=".\\repos\\micropython"
228
- )
229
- ]
225
+ questions = [inquirer.Text("mpy_path", message="Enter the path to the MicroPython repository", default=".\\repos\\micropython")]
230
226
  if answers := inquirer.prompt(questions):
231
227
  return Path(answers["mpy_path"])
232
228
  else:
mpflash/versions.py CHANGED
@@ -4,10 +4,13 @@
4
4
  #############################################################
5
5
  """
6
6
 
7
- from cache_to_disk import cache_to_disk, NoCacheCondition
7
+ from pathlib import Path
8
+
9
+ from cache_to_disk import NoCacheCondition, cache_to_disk
8
10
  from loguru import logger as log
9
11
  from packaging.version import parse
10
12
 
13
+ import mpflash.basicgit as git
11
14
  from mpflash.common import GH_CLIENT
12
15
 
13
16
  OLDEST_VERSION = "1.16"
@@ -27,7 +30,7 @@ def clean_version(
27
30
  commit: bool = False,
28
31
  drop_v: bool = False,
29
32
  flat: bool = False,
30
- ):
33
+ ): # sourcery skip: assign-if-exp
31
34
  "Clean up and transform the many flavours of versions"
32
35
  # 'v1.13.0-103-gb137d064e' --> 'v1.13-103'
33
36
  if version in {"", "-"}:
@@ -48,14 +51,12 @@ def clean_version(
48
51
  if len(nibbles) == 1:
49
52
  version = nibbles[0]
50
53
  elif build and not is_preview:
54
+ # HACK: this is not always right, but good enough most of the time
51
55
  version = "-".join(nibbles) if commit else "-".join(nibbles[:-1])
56
+ elif is_preview:
57
+ version = "-".join((nibbles[0], V_PREVIEW))
52
58
  else:
53
- # version = "-".join((nibbles[0], LATEST))
54
- # HACK: this is not always right, but good enough most of the time
55
- if is_preview:
56
- version = "-".join((nibbles[0], V_PREVIEW))
57
- else:
58
- version = V_PREVIEW
59
+ version = V_PREVIEW
59
60
  if flat:
60
61
  version = version.strip().replace(".", "_").replace("-", "_")
61
62
  else:
@@ -122,3 +123,13 @@ def get_preview_mp_version() -> str:
122
123
  # read the versions from the git tags
123
124
  all_versions = micropython_versions(minver=OLDEST_VERSION)
124
125
  return [v for v in all_versions if v.endswith(V_PREVIEW)][-1]
126
+
127
+
128
+ # Do not cache , same path will have different versions checked out
129
+ def checkedout_version(path: Path, flat: bool = False) -> str:
130
+ """Get the checked-out version of the repo"""
131
+ version = git.get_local_tag(path.as_posix())
132
+ if not version:
133
+ raise ValueError("No valid Tag found")
134
+ version = clean_version(version, flat=flat, drop_v=False)
135
+ return version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mpflash
3
- Version: 0.9.1
3
+ Version: 0.9.1.post2
4
4
  Summary: Flash and download tool for MicroPython firmwares
5
5
  Home-page: https://github.com/Josverl/micropython-stubber/blob/main/src/mpflash/README.md
6
6
  License: MIT
@@ -1,6 +1,7 @@
1
1
  mpflash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  mpflash/add_firmware.py,sha256=h-Nu9AnXO6ug2CurmgLoUVG1gNy6CA1NjwQl1nUoMZ4,3330
3
3
  mpflash/ask_input.py,sha256=EsPPlPS_wLC8j9f4o68yKIcqex0dV5tRH7k3rP3spG0,8710
4
+ mpflash/basicgit.py,sha256=r_bI2U6QYFiS8ypUd6KtrjyZjK4JCANyK80L6wEzFoU,9213
4
5
  mpflash/bootloader/__init__.py,sha256=cRIxVRtUc4jZAgtFggRNhEn0BW-9WFpzm5xRy5B4B2U,105
5
6
  mpflash/bootloader/activate.py,sha256=sN2YuIuFGjLBd_PdG6P3N1yLuLyjnsVWDksrTMhzr_M,2301
6
7
  mpflash/bootloader/detect.py,sha256=eXL_JPcowb8g0tpZmj9DQXYbpfZFoSrzq86lScKhkT4,2608
@@ -28,11 +29,11 @@ mpflash/flash/uf2/linux.py,sha256=4azbcx_YqLZ3RyYNWljejHG_Y6SU-wREL8hhkTYqCjI,40
28
29
  mpflash/flash/uf2/macos.py,sha256=sncXJsc2FVfm9rvLDjcEu7ZIyrDeHmazHiNQTUaf1Y0,1187
29
30
  mpflash/flash/uf2/uf2disk.py,sha256=dQ8_U6e3qkFOyfXZDpWAsvEBIlMr-ZzLkzTDD8SADqM,286
30
31
  mpflash/flash/uf2/windows.py,sha256=k9Yv71YswPnLx-Z5rf4KjhtVkEWr8SU8EXpeRv87h3A,1290
31
- mpflash/flash/worklist.py,sha256=K16sbvzJCgkHNssYlBA3ezayI02RMuIcp19XAs74XeQ,5835
32
+ mpflash/flash/worklist.py,sha256=1uBvn-T35Oey04g6xxNxo5t68q5_tp18eZcRAamF0tY,5828
32
33
  mpflash/list.py,sha256=O0tX4BvclmDMnnjMxCN9Zh8hdL6vnuvS9pLNxYLBya8,3112
33
34
  mpflash/logger.py,sha256=BAVrSXMGZLfSDRFbtVBtvb7Rl0sTJxooCgBS5t-6bXo,1057
34
35
  mpflash/mpboard_id/__init__.py,sha256=rQrPCN30GP-lfB2a2deA-lQ6iKvaKPK_xbtBoIavGsM,3716
35
- mpflash/mpboard_id/add_boards.py,sha256=0tP-4Ibc5_BBTQx1oBFXmKo80n31BrW6E5KrWKpP2FU,9407
36
+ mpflash/mpboard_id/add_boards.py,sha256=ehQn560S0XxAD3nsUMo4o_f6w8XTVAfO0GCnfTKa6-4,9379
36
37
  mpflash/mpboard_id/board.py,sha256=yQ8IDHQS09AelvTvmPhpmsL4oX3L7IXGqHorkxDOkoE,1114
37
38
  mpflash/mpboard_id/board_id.py,sha256=wzGrxJu_ciOVT7n2861lhoKmPAjh1QjWnAdfcqNUUqc,2871
38
39
  mpflash/mpboard_id/board_info.zip,sha256=F6YowS96DAqjten4ySe4MXgZwPtE-saZOUfY5OQkqKk,19759
@@ -44,9 +45,9 @@ mpflash/vendor/click_aliases.py,sha256=K98inhtze8td1dw312kexJS7OX_0ojlptPQ5Z0SHx
44
45
  mpflash/vendor/dfu.py,sha256=jGsiD3lbSV1Ar9qJubhoY_hy-L8FI-K55aow8vgwoYQ,5590
45
46
  mpflash/vendor/pydfu.py,sha256=1ObubGsPFrQ7T9M3JRlIPNIG2xx8uYffaEe0Y6bdf_g,19937
46
47
  mpflash/vendor/readme.md,sha256=ZVg7kuUYyXcWcrWkaSJ0CunwebCqu2SiS2sqDadwrT8,84
47
- mpflash/versions.py,sha256=SrXVZx6qVWcighHlg8pJ0RPRZ3gcYN7l2DnSicconAk,4098
48
- mpflash-0.9.1.dist-info/LICENSE,sha256=xHwgxGNkI0R2iN4KNfbPbQSzRomWyRz7bJnR1O2mln8,1057
49
- mpflash-0.9.1.dist-info/METADATA,sha256=81r3-DTSaPrLNwLUdQDjgnFT8WJhC-awFTW1FAC6sXU,16058
50
- mpflash-0.9.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
51
- mpflash-0.9.1.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
52
- mpflash-0.9.1.dist-info/RECORD,,
48
+ mpflash/versions.py,sha256=x5VrdVfWhZJfH7tZmwu2vVx-mPrK1iunYSpSce9VUXU,4492
49
+ mpflash-0.9.1.post2.dist-info/LICENSE,sha256=xHwgxGNkI0R2iN4KNfbPbQSzRomWyRz7bJnR1O2mln8,1057
50
+ mpflash-0.9.1.post2.dist-info/METADATA,sha256=SFrk166YQmHI5NcNGZYbOmSx9O2D1r9zvG-DxKs26EM,16064
51
+ mpflash-0.9.1.post2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
52
+ mpflash-0.9.1.post2.dist-info/entry_points.txt,sha256=Jk_visOhYOsZIcSP2Ms9hKqfKy1iorR-6dYltSoWCpY,52
53
+ mpflash-0.9.1.post2.dist-info/RECORD,,