pre-commit-localupdate 0.4.1__tar.gz → 0.5.1__tar.gz

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 (20) hide show
  1. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/PKG-INFO +38 -22
  2. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/README.md +36 -20
  3. pre_commit_localupdate-0.5.1/pre_commit_localupdate/__init__.py +1 -0
  4. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/__main__.py +9 -3
  5. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/cli.py +31 -3
  6. pre_commit_localupdate-0.5.1/pre_commit_localupdate/io.py +121 -0
  7. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/golang.py +16 -32
  8. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/julia.py +44 -37
  9. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/node.py +24 -38
  10. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/package.py +18 -8
  11. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/python.py +18 -32
  12. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/rust.py +17 -28
  13. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/pre_commit_config.py +43 -59
  14. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pyproject.toml +2 -2
  15. pre_commit_localupdate-0.4.1/pre_commit_localupdate/__init__.py +0 -1
  16. pre_commit_localupdate-0.4.1/pre_commit_localupdate/io.py +0 -53
  17. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/LICENSE +0 -0
  18. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/error.py +0 -0
  19. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/logs.py +0 -0
  20. {pre_commit_localupdate-0.4.1 → pre_commit_localupdate-0.5.1}/pre_commit_localupdate/packages/__init__.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pre-commit-localupdate
3
- Version: 0.4.1
4
- Summary: A CLI tool to automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in pre-commit config files.
3
+ Version: 0.5.1
4
+ Summary: A CLI tool to automatically update additional dependencies within local hooks in pre-commit config files.
5
5
  Author: M. Farzalipour Tabriz
6
6
  Classifier: Development Status :: 3 - Alpha
7
7
  Classifier: Environment :: Console
@@ -16,7 +16,7 @@ Description-Content-Type: text/markdown
16
16
 
17
17
  # pre-commit-localupdate
18
18
 
19
- A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, Go, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
19
+ A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
20
20
 
21
21
  ## Installation
22
22
 
@@ -34,20 +34,25 @@ pre-commit-localupdate
34
34
 
35
35
  All options:
36
36
 
37
- ```shell
38
- usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c CONFIG] [--timeout TIMEOUT] [--version]
37
+ ```text
38
+ usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c PRE-COMMIT-CONFIG] [--timeout TIMEOUT]
39
+ [--indent-mapping INDENT_MAPPING] [--indent-sequence INDENT_SEQUENCE]
40
+ [--indent-offset INDENT_OFFSET] [--line-width LINE_WIDTH] [--version]
39
41
 
40
- Automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in a pre-commit config
41
- file.
42
+ Automatically update additional dependencies within local hooks in a pre-commit config file.
42
43
 
43
44
  options:
44
- -h, --help show this help message and exit
45
- --debug enable debug logging (default: False)
46
- --dry-run dry run mode. Do not update the file and exit with a non-zero code if the configuration file require an
47
- update. (default: False)
48
- -c, --config CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
49
- --timeout TIMEOUT connection timeout in seconds (default: 10)
50
- --version show program's version number and exit
45
+ -h, --help show this help message and exit
46
+ --debug enable debug logging (default: False)
47
+ --dry-run dry run mode. Do not update the file and exit with a non-zero code if the
48
+ configuration file require an update. (default: False)
49
+ -c, --config PRE-COMMIT-CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
50
+ --timeout TIMEOUT connection timeout in seconds (default: 10)
51
+ --indent-mapping INDENT_MAPPING YAML indentation for mappings (default: 2)
52
+ --indent-sequence INDENT_SEQUENCE YAML indentation for sequences (default: 4)
53
+ --indent-offset INDENT_OFFSET YAML indentation offset (default: 2)
54
+ --line-width LINE_WIDTH maximum line width (default: 80)
55
+ --version show program's version number and exit
51
56
  ```
52
57
 
53
58
  ## Example
@@ -70,7 +75,7 @@ repos:
70
75
  # All comment are preserved
71
76
  - id: black
72
77
  name: black
73
- description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
78
+ description: "Length of strings is automatically adjusted based on the value of --line-width"
74
79
  entry: black
75
80
  language: python
76
81
  minimum_pre_commit_version: 2.9.2
@@ -84,7 +89,7 @@ repos:
84
89
 
85
90
  - id: julia-format
86
91
  name: format julia code
87
- description: Run `JuliaFormatter.jl` against Julia source files
92
+ description: Unicodeテキストは保持されます。
88
93
  language: julia
89
94
  types: [julia]
90
95
  entry: tools/formatter.jl
@@ -120,8 +125,8 @@ repos:
120
125
  # All comment are preserved
121
126
  - id: black
122
127
  name: black
123
- description: "Long strings are automatically folded into multilines by ruamel-yaml
124
- library!"
128
+ description: "Length of strings is automatically adjusted based on the value
129
+ of --line-width"
125
130
  entry: black
126
131
  language: python
127
132
  minimum_pre_commit_version: 2.9.2
@@ -135,7 +140,7 @@ repos:
135
140
 
136
141
  - id: julia-format
137
142
  name: format julia code
138
- description: Run `JuliaFormatter.jl` against Julia source files
143
+ description: Unicodeテキストは保持されます。
139
144
  language: julia
140
145
  types: [julia]
141
146
  entry: tools/formatter.jl
@@ -153,14 +158,25 @@ repos:
153
158
  additional_dependencies: ["cli:mdbook-lint:0.14.2"]
154
159
  ```
155
160
 
161
+ ## Supported Languages
162
+
163
+ Following local hook languages are currently supported:
164
+
165
+ - Go (golang)
166
+ - Julia
167
+ - Node.js (node)
168
+ - Python
169
+ - Rust
170
+
156
171
  ## Formatting
157
172
 
158
- A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
173
+ Significant effort has been made to ensure `pre-commit-localupdate` maintains the original style and preserves comments in pre-commit configuration files. However, since the current version of the underlying library does not perfectly preserve the original YAML file format after processing, `pre-commit-localupdate` automatically folds long string values (like descriptions) and enforces block indentation by default when updating files to enhance readability. Both behaviors can be adjusted using command-line parameters.
159
174
 
160
175
  ## Requirements
161
176
 
162
- - ruamel.yaml
163
- - requests
177
+ - `packaging`
178
+ - `requests`
179
+ - `ruamel.yaml`
164
180
 
165
181
  ## License
166
182
 
@@ -1,6 +1,6 @@
1
1
  # pre-commit-localupdate
2
2
 
3
- A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local Python, Julia, Rust, Go, and Node.js hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
3
+ A CLI tool to automatically update dependencies in `pre-commit-config.yml` files. It specifically targets `additional_dependencies` within local hooks to ensure your tooling stays up-to-date. It also adds version to unversioned packages and pins exact version of loosely defined ones. You can also pin a specific package to an older version by adding a `# freeze` comment.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,20 +18,25 @@ pre-commit-localupdate
18
18
 
19
19
  All options:
20
20
 
21
- ```shell
22
- usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c CONFIG] [--timeout TIMEOUT] [--version]
21
+ ```text
22
+ usage: pre-commit-localupdate [-h] [--debug] [--dry-run] [-c PRE-COMMIT-CONFIG] [--timeout TIMEOUT]
23
+ [--indent-mapping INDENT_MAPPING] [--indent-sequence INDENT_SEQUENCE]
24
+ [--indent-offset INDENT_OFFSET] [--line-width LINE_WIDTH] [--version]
23
25
 
24
- Automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in a pre-commit config
25
- file.
26
+ Automatically update additional dependencies within local hooks in a pre-commit config file.
26
27
 
27
28
  options:
28
- -h, --help show this help message and exit
29
- --debug enable debug logging (default: False)
30
- --dry-run dry run mode. Do not update the file and exit with a non-zero code if the configuration file require an
31
- update. (default: False)
32
- -c, --config CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
33
- --timeout TIMEOUT connection timeout in seconds (default: 10)
34
- --version show program's version number and exit
29
+ -h, --help show this help message and exit
30
+ --debug enable debug logging (default: False)
31
+ --dry-run dry run mode. Do not update the file and exit with a non-zero code if the
32
+ configuration file require an update. (default: False)
33
+ -c, --config PRE-COMMIT-CONFIG pre-commit config file path (default: .pre-commit-config.yaml)
34
+ --timeout TIMEOUT connection timeout in seconds (default: 10)
35
+ --indent-mapping INDENT_MAPPING YAML indentation for mappings (default: 2)
36
+ --indent-sequence INDENT_SEQUENCE YAML indentation for sequences (default: 4)
37
+ --indent-offset INDENT_OFFSET YAML indentation offset (default: 2)
38
+ --line-width LINE_WIDTH maximum line width (default: 80)
39
+ --version show program's version number and exit
35
40
  ```
36
41
 
37
42
  ## Example
@@ -54,7 +59,7 @@ repos:
54
59
  # All comment are preserved
55
60
  - id: black
56
61
  name: black
57
- description: "Long strings are automatically folded into multilines by ruamel-yaml library!"
62
+ description: "Length of strings is automatically adjusted based on the value of --line-width"
58
63
  entry: black
59
64
  language: python
60
65
  minimum_pre_commit_version: 2.9.2
@@ -68,7 +73,7 @@ repos:
68
73
 
69
74
  - id: julia-format
70
75
  name: format julia code
71
- description: Run `JuliaFormatter.jl` against Julia source files
76
+ description: Unicodeテキストは保持されます。
72
77
  language: julia
73
78
  types: [julia]
74
79
  entry: tools/formatter.jl
@@ -104,8 +109,8 @@ repos:
104
109
  # All comment are preserved
105
110
  - id: black
106
111
  name: black
107
- description: "Long strings are automatically folded into multilines by ruamel-yaml
108
- library!"
112
+ description: "Length of strings is automatically adjusted based on the value
113
+ of --line-width"
109
114
  entry: black
110
115
  language: python
111
116
  minimum_pre_commit_version: 2.9.2
@@ -119,7 +124,7 @@ repos:
119
124
 
120
125
  - id: julia-format
121
126
  name: format julia code
122
- description: Run `JuliaFormatter.jl` against Julia source files
127
+ description: Unicodeテキストは保持されます。
123
128
  language: julia
124
129
  types: [julia]
125
130
  entry: tools/formatter.jl
@@ -137,14 +142,25 @@ repos:
137
142
  additional_dependencies: ["cli:mdbook-lint:0.14.2"]
138
143
  ```
139
144
 
145
+ ## Supported Languages
146
+
147
+ Following local hook languages are currently supported:
148
+
149
+ - Go (golang)
150
+ - Julia
151
+ - Node.js (node)
152
+ - Python
153
+ - Rust
154
+
140
155
  ## Formatting
141
156
 
142
- A considerable amount of effort has been put into making `pre-commit-localupdate` respect the original style and preserve the comments in the pre-commit configuration files. Although it is currently folding long strings (for example, in description lines) and enforcing block indentation for better readability.
157
+ Significant effort has been made to ensure `pre-commit-localupdate` maintains the original style and preserves comments in pre-commit configuration files. However, since the current version of the underlying library does not perfectly preserve the original YAML file format after processing, `pre-commit-localupdate` automatically folds long string values (like descriptions) and enforces block indentation by default when updating files to enhance readability. Both behaviors can be adjusted using command-line parameters.
143
158
 
144
159
  ## Requirements
145
160
 
146
- - ruamel.yaml
147
- - requests
161
+ - `packaging`
162
+ - `requests`
163
+ - `ruamel.yaml`
148
164
 
149
165
  ## License
150
166
 
@@ -0,0 +1 @@
1
+ __version__ = '0.5.1'
@@ -11,10 +11,10 @@ to their latest versions.
11
11
 
12
12
  import logging
13
13
  import sys
14
- from pathlib import Path
15
14
 
16
15
  from pre_commit_localupdate.cli import parse_args
17
16
  from pre_commit_localupdate.error import PreCommitLocalUpdateError
17
+ from pre_commit_localupdate.io import YAMLFormat
18
18
  from pre_commit_localupdate.logs import setup_logging
19
19
  from pre_commit_localupdate.pre_commit_config import update_additional_dependencies
20
20
 
@@ -23,12 +23,18 @@ def main() -> None:
23
23
  """Main entry point for the script."""
24
24
  args = parse_args()
25
25
  setup_logging(debug=args.debug)
26
-
26
+ yaml_format = YAMLFormat(
27
+ indent_mapping=args.indent_mapping,
28
+ indent_sequence=args.indent_sequence,
29
+ indent_offset=args.indent_offset,
30
+ line_width=args.line_width,
31
+ )
27
32
  try:
28
33
  if update_additional_dependencies(
29
- Path(args.config), args.timeout, dry_run=args.dry_run
34
+ args.config, args.timeout, yaml_format, dry_run=args.dry_run
30
35
  ):
31
36
  if args.dry_run:
37
+ logging.info("Additional dependencies require updating!")
32
38
  sys.exit(1)
33
39
  logging.info("Done.")
34
40
  else:
@@ -2,6 +2,7 @@
2
2
  # SPDX-License-Identifier: LGPL-3.0-or-later
3
3
 
4
4
  import argparse
5
+ from pathlib import Path
5
6
 
6
7
  from pre_commit_localupdate import __version__
7
8
 
@@ -13,8 +14,10 @@ def parse_args() -> argparse.Namespace:
13
14
  argparse.Namespace: Parsed arguments.
14
15
  """
15
16
  parser = argparse.ArgumentParser(
16
- description="Automatically update additional dependencies within local Python, Julia, Rust, Go, and Node.js hooks in a pre-commit config file.",
17
- formatter_class=argparse.ArgumentDefaultsHelpFormatter,
17
+ description="Automatically update additional dependencies within local hooks in a pre-commit config file.",
18
+ formatter_class=lambda prog: argparse.ArgumentDefaultsHelpFormatter(
19
+ prog, max_help_position=40, width=120
20
+ ),
18
21
  )
19
22
  parser.add_argument(
20
23
  "--debug",
@@ -29,9 +32,10 @@ def parse_args() -> argparse.Namespace:
29
32
  parser.add_argument(
30
33
  "-c",
31
34
  "--config",
32
- type=str,
35
+ type=Path,
33
36
  help="pre-commit config file path",
34
37
  default=".pre-commit-config.yaml",
38
+ metavar="PRE-COMMIT-CONFIG",
35
39
  )
36
40
  parser.add_argument(
37
41
  "--timeout",
@@ -39,6 +43,30 @@ def parse_args() -> argparse.Namespace:
39
43
  help="connection timeout in seconds",
40
44
  default=10,
41
45
  )
46
+ parser.add_argument(
47
+ "--indent-mapping",
48
+ type=int,
49
+ help="YAML indentation for mappings",
50
+ default=2,
51
+ )
52
+ parser.add_argument(
53
+ "--indent-sequence",
54
+ type=int,
55
+ help="YAML indentation for sequences",
56
+ default=4,
57
+ )
58
+ parser.add_argument(
59
+ "--indent-offset",
60
+ type=int,
61
+ help="YAML indentation offset",
62
+ default=2,
63
+ )
64
+ parser.add_argument(
65
+ "--line-width",
66
+ type=int,
67
+ help="maximum line width",
68
+ default=80,
69
+ )
42
70
  parser.add_argument(
43
71
  "--version",
44
72
  action="version",
@@ -0,0 +1,121 @@
1
+ # SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
2
+ # SPDX-License-Identifier: LGPL-3.0-or-later
3
+
4
+ import io
5
+ import logging
6
+ import os
7
+ import tempfile
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+
11
+ from ruamel.yaml import YAML
12
+ from ruamel.yaml.comments import CommentedMap
13
+
14
+ from pre_commit_localupdate.error import PreCommitLocalUpdateError
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class YAMLFormat:
19
+ """Configuration for YAML file formatting parameters.
20
+
21
+ Attributes:
22
+ indent_mapping (int): YAML indentation for mappings
23
+ indent_sequence (int): YAML indentation for sequences
24
+ indent_offset (int): YAML indentation offset
25
+ line_width (int): maximum line width
26
+
27
+ """
28
+
29
+ indent_mapping: int
30
+ indent_sequence: int
31
+ indent_offset: int
32
+ line_width: int
33
+
34
+
35
+ def load_config_file(file_path: Path) -> tuple[list[str], str]:
36
+ """Reads pre-commit configuration file and returns its header lines and content.
37
+
38
+ Args:
39
+ file_path (Path): Path to config file
40
+
41
+ Returns:
42
+ tuple[list[str], str]: Header lines, config file content
43
+
44
+ Raises:
45
+ PreCommitLocalUpdateError: Error in reading config file
46
+ """
47
+ logging.debug("Reading configuration file: %s", file_path)
48
+
49
+ try:
50
+ file_content = file_path.read_text(encoding="utf-8")
51
+ except FileNotFoundError as exc:
52
+ raise PreCommitLocalUpdateError(f"File not found: {file_path}") from exc
53
+ except OSError as exc:
54
+ raise PreCommitLocalUpdateError(
55
+ f"IOError while reading file {file_path}"
56
+ ) from exc
57
+
58
+ raw_lines = file_content.splitlines(keepends=True)
59
+
60
+ content_start_index = 0
61
+ for i, line in enumerate(raw_lines):
62
+ stripped = line.strip()
63
+ if stripped == "---":
64
+ logging.debug("YAML marker found.")
65
+ content_start_index = i + 1
66
+ break
67
+ if stripped and not stripped.startswith("#"):
68
+ content_start_index = i
69
+ break
70
+
71
+ header_lines = raw_lines[:content_start_index]
72
+ content = "".join(raw_lines[content_start_index:])
73
+
74
+ return header_lines, content
75
+
76
+
77
+ def save_config_file(
78
+ file_path: Path,
79
+ config: CommentedMap,
80
+ header_lines: list[str],
81
+ yaml_dumper: YAML,
82
+ ) -> None:
83
+ """Writes pre-commit configuration file.
84
+
85
+ Args:
86
+ file_path (Path): Path to config file
87
+ config (CommentedMap): Config file content
88
+ header_lines (list[str]): File header lines
89
+ yaml_dumper (YAML): YAML dumper
90
+
91
+ Raises:
92
+ PreCommitLocalUpdateError: Error in writing config file
93
+ """
94
+
95
+ logging.debug("Writing modifications to disk...")
96
+ stream = io.StringIO()
97
+ yaml_dumper.dump(config, stream)
98
+ modified_body = stream.getvalue()
99
+ final_content = "".join(header_lines) + modified_body
100
+
101
+ temp_file_path = None
102
+ try:
103
+ with tempfile.NamedTemporaryFile(
104
+ mode="w",
105
+ encoding="utf-8",
106
+ dir=file_path.parent,
107
+ delete=False,
108
+ ) as temp_file:
109
+ temp_file_path = temp_file.name
110
+ temp_file.write(final_content)
111
+ os.fsync(temp_file.fileno())
112
+
113
+ os.replace(temp_file_path, file_path)
114
+ logging.info("Successfully updated %s", file_path)
115
+
116
+ except OSError as exc:
117
+ if temp_file_path and os.path.exists(temp_file_path):
118
+ os.unlink(temp_file_path)
119
+ raise PreCommitLocalUpdateError(
120
+ f"IOError while writing to file {file_path}"
121
+ ) from exc
@@ -1,9 +1,10 @@
1
1
  # SPDX-FileCopyrightText: 2026 M. Farzalipour Tabriz, Max Planck Institute for Physics
2
2
  # SPDX-License-Identifier: LGPL-3.0-or-later
3
3
 
4
+ from __future__ import annotations
5
+
4
6
  import logging
5
7
  import re
6
- from dataclasses import dataclass
7
8
 
8
9
  import requests
9
10
 
@@ -13,51 +14,39 @@ from .package import PackageBase
13
14
  GO_PKG_LATEST_VERSION_API_URL = "https://proxy.golang.org/{package_path}/@latest"
14
15
 
15
16
 
16
- @dataclass
17
17
  class GoPackage(PackageBase):
18
18
  """Represents a Go module."""
19
19
 
20
20
  @classmethod
21
- def from_specification(
22
- cls, spec: str, connection_timeout: int
23
- ) -> "GoPackage" | None:
21
+ def from_specification(cls, spec: str) -> "GoPackage" | None:
24
22
  """Parse a Go module specification string into a Package object.
25
23
 
26
- Handles formats like:
27
- - 'mvdan.cc/sh' (Module path only)
28
- - 'mvdan.cc/sh@v1.3.0' (Module path with specific version)
29
- - 'mvdan.cc/sh/v3' (Module path with major version suffix)
30
- - 'mvdan.cc/sh/v3@v3.10.0' (Major suffix with version)
31
- - 'mvdan.cc/sh/v3/cmd/shfmt' (Submodule)
32
- - 'mvdan.cc/sh/v3/cmd/shfmt@v3.10.0' (Submodule with version)
24
+ Supported formats:
25
+ - `mvdan.cc/sh` (Module path only)
26
+ - `mvdan.cc/sh@v1.3.0` (Module path with specific version)
27
+ - `mvdan.cc/sh/v3` (Module path with major version suffix)
28
+ - `mvdan.cc/sh/v3@v3.10.0` (Major suffix with version)
29
+ - `mvdan.cc/sh/v3/cmd/shfmt` (Submodule)
30
+ - `mvdan.cc/sh/v3/cmd/shfmt@v3.10.0` (Submodule with version)
33
31
 
34
32
  Args:
35
- spec (str): The package specification string.
36
- connection_timeout (int): Connection timeout in seconds.
33
+ spec (str): The package specification string (without quotations).
37
34
 
38
35
  Returns:
39
36
  "GoPackage" | None: A Package instance if parsing succeeds, otherwise None.
40
37
  """
41
- clean_spec = spec.strip().strip('"').strip("'")
42
38
 
43
- match = re.match(r"^([a-zA-Z0-9._/-]+)(@.+)?$", clean_spec)
39
+ match = re.match(r"^([a-zA-Z0-9._/-]+)(@.+)?$", spec)
44
40
 
45
41
  if not match:
46
- logging.warning(
47
- "Could not parse the Go package specification: %s", clean_spec
48
- )
49
42
  return None
50
43
 
51
44
  name = match.group(1)
52
45
  raw_spec = match.group(2)
53
46
 
54
- module_path = cls._resolve_module_path(name)
55
- latest_version = cls._get_latest_version(module_path, connection_timeout)
56
-
57
47
  return cls(
58
48
  name=name,
59
49
  raw_spec=raw_spec,
60
- latest_version=latest_version,
61
50
  )
62
51
 
63
52
  @staticmethod
@@ -82,17 +71,13 @@ class GoPackage(PackageBase):
82
71
 
83
72
  return package_path
84
73
 
85
- @staticmethod
86
- def _get_latest_version(package_path: str, connection_timeout: int) -> str | None:
74
+ def fetch_latest_version(self, connection_timeout: int) -> None:
87
75
  """Fetch the latest version of a Go module from proxy.golang.org.
88
76
 
89
77
  Args:
90
- package_path (str): The module path (e.g., mvdan.cc/sh/v3).
91
78
  connection_timeout (int): Connection timeout in seconds.
92
-
93
- Returns:
94
- str | None: The latest version string (e.g., v3.10.0) if found, otherwise None.
95
79
  """
80
+ package_path = self._resolve_module_path(self.name)
96
81
  logging.debug("Fetching latest version for %s", package_path)
97
82
  try:
98
83
  url = GO_PKG_LATEST_VERSION_API_URL.format(package_path=package_path)
@@ -103,16 +88,15 @@ class GoPackage(PackageBase):
103
88
  data = response.json()
104
89
  latest_version = data.get("Version")
105
90
 
106
- return latest_version if isinstance(latest_version, str) else None
91
+ if isinstance(latest_version, str):
92
+ self.latest_version = latest_version
107
93
 
108
94
  except requests.exceptions.RequestException as exc:
109
95
  logging.warning(
110
96
  "Could not fetch latest version for %s: %s", package_path, exc
111
97
  )
112
- return None
113
98
  except (KeyError, ValueError) as exc:
114
99
  logging.warning("Could not parse response for %s: %s", package_path, exc)
115
- return None
116
100
 
117
101
  def latest_version_specification(self) -> str | None:
118
102
  """Version specification of package pinned to the latest version.