2
2
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
3
from __future__ import annotations
4
4
5
+ import os
5
6
import sys
6
7
# TODO: Remove this import when Python 3.11 is the minimum supported version
7
8
if sys .version_info >= (3 , 11 ):
@@ -48,19 +49,19 @@ def _parse_toml_content(content: str) -> dict:
48
49
return result
49
50
50
51
51
- def _write_toml_content (data : dict ) -> str :
52
+ def _write_base_toml_content (data : dict ) -> str :
52
53
"""
53
54
Write minimal TOML content with project and tool.pyside6-project sections.
54
55
"""
55
56
lines = []
56
57
57
- if 'project' in data and data [ 'project' ] :
58
+ if data . get ( 'project' ) :
58
59
lines .append ('[project]' )
59
60
for key , value in sorted (data ['project' ].items ()):
60
61
if isinstance (value , str ):
61
62
lines .append (f'{ key } = "{ value } "' )
62
63
63
- if ' tool' in data and 'pyside6-project' in data ['tool' ]:
64
+ if data . get ( " tool" ) and data ['tool' ]. get ( 'pyside6-project' ) :
64
65
lines .append ('\n [tool.pyside6-project]' )
65
66
for key , value in sorted (data ['tool' ]['pyside6-project' ].items ()):
66
67
if isinstance (value , list ):
@@ -115,7 +116,7 @@ def parse_pyproject_toml(pyproject_toml_file: Path) -> PyProjectParseResult:
115
116
116
117
def write_pyproject_toml (pyproject_file : Path , project_name : str , project_files : list [str ]):
117
118
"""
118
- Create or update a pyproject.toml file with the specified content.
119
+ Create or overwrite a pyproject.toml file with the specified content.
119
120
"""
120
121
data = {
121
122
"project" : {"name" : project_name },
@@ -124,13 +125,33 @@ def write_pyproject_toml(pyproject_file: Path, project_name: str, project_files:
124
125
}
125
126
}
126
127
128
+ content = _write_base_toml_content (data )
127
129
try :
128
- content = _write_toml_content (data )
129
130
pyproject_file .write_text (content , encoding = 'utf-8' )
130
131
except Exception as e :
131
132
raise ValueError (f"Error writing TOML file: { str (e )} " )
132
133
133
134
135
+ def robust_relative_to_posix (target_path : Path , base_path : Path ) -> str :
136
+ """
137
+ Calculates the relative path from base_path to target_path.
138
+ Uses Path.relative_to first, falls back to os.path.relpath if it fails.
139
+ Returns the result as a POSIX path string.
140
+ """
141
+ # Ensure both paths are absolute for reliable calculation, although in this specific code,
142
+ # project_folder and paths in output_files are expected to be resolved/absolute already.
143
+ abs_target = target_path .resolve () if not target_path .is_absolute () else target_path
144
+ abs_base = base_path .resolve () if not base_path .is_absolute () else base_path
145
+
146
+ try :
147
+ return abs_target .relative_to (abs_base ).as_posix ()
148
+ except ValueError :
149
+ # Fallback to os.path.relpath which is more robust for paths that are not direct subpaths.
150
+ relative_str = os .path .relpath (str (abs_target ), str (abs_base ))
151
+ # Convert back to Path temporarily to get POSIX format
152
+ return Path (relative_str ).as_posix ()
153
+
154
+
134
155
def migrate_pyproject (pyproject_file : Path | str = None ) -> int :
135
156
"""
136
157
Migrate a project *.pyproject JSON file to the new pyproject.toml format.
@@ -170,7 +191,7 @@ def migrate_pyproject(pyproject_file: Path | str = None) -> int:
170
191
project_name = project_files [0 ].stem
171
192
172
193
# The project files that will be written to the pyproject.toml file
173
- output_files = set ()
194
+ output_files : set [ Path ] = set ()
174
195
for project_file in project_files :
175
196
project_data = parse_pyproject_json (project_file )
176
197
if project_data .errors :
@@ -185,39 +206,58 @@ def migrate_pyproject(pyproject_file: Path | str = None) -> int:
185
206
project_name = project_folder .name
186
207
187
208
pyproject_toml_file = project_folder / "pyproject.toml"
188
- if pyproject_toml_file .exists ():
189
- already_existing_file = True
209
+
210
+ relative_files = sorted (
211
+ robust_relative_to_posix (p , project_folder ) for p in output_files
212
+ )
213
+
214
+ if not (already_existing_file := pyproject_toml_file .exists ()):
215
+ # Create new pyproject.toml file
216
+ data = {
217
+ "project" : {"name" : project_name },
218
+ "tool" : {
219
+ "pyside6-project" : {"files" : relative_files }
220
+ }
221
+ }
222
+ updated_content = _write_base_toml_content (data )
223
+ else :
224
+ # For an already existing file, append our tool.pyside6-project section
225
+ # If the project section is missing, add it
190
226
try :
191
227
content = pyproject_toml_file .read_text (encoding = 'utf-8' )
192
- data = _parse_toml_content (content )
193
228
except Exception as e :
194
- raise ValueError (f"Error parsing TOML: { str (e )} " )
195
- else :
196
- already_existing_file = False
197
- data = {"project" : {}, "tool" : {"pyside6-project" : {}}}
229
+ print (f"Error processing existing TOML file: { str (e )} " , file = sys .stderr )
230
+ return 1
198
231
199
- # Update project name if not present
200
- if "name" not in data ["project" ]:
201
- data ["project" ]["name" ] = project_name
232
+ append_content = []
202
233
203
- # Update files list
204
- data ["tool" ]["pyside6-project" ]["files" ] = sorted (
205
- p .relative_to (project_folder ).as_posix () for p in output_files
206
- )
234
+ if '[project]' not in content :
235
+ # Add project section if needed
236
+ append_content .append ('\n [project]' )
237
+ append_content .append (f'name = "{ project_name } "' )
238
+
239
+ if '[tool.pyside6-project]' not in content :
240
+ # Add tool.pyside6-project section
241
+ append_content .append ('\n [tool.pyside6-project]' )
242
+ items = [f'"{ item } "' for item in relative_files ]
243
+ append_content .append (f'files = [{ ", " .join (items )} ]' )
207
244
208
- # Generate TOML content
209
- toml_content = _write_toml_content (data )
245
+ if append_content :
246
+ updated_content = content .rstrip () + '\n ' + '\n ' .join (append_content )
247
+ else :
248
+ # No changes needed
249
+ print ("pyproject.toml already contains [project] and [tool.pyside6-project] sections" )
250
+ return 0
210
251
211
- if already_existing_file :
212
252
print (f"WARNING: A pyproject.toml file already exists at \" { pyproject_toml_file } \" " )
213
253
print ("The file will be updated with the following content:" )
214
- print (toml_content )
254
+ print (updated_content )
215
255
response = input ("Proceed? [Y/n] " )
216
256
if response .lower ().strip () not in {"yes" , "y" }:
217
257
return 0
218
258
219
259
try :
220
- pyproject_toml_file .write_text (toml_content )
260
+ pyproject_toml_file .write_text (updated_content , encoding = 'utf-8' )
221
261
except Exception as e :
222
262
print (f"Error writing to \" { pyproject_toml_file } \" : { str (e )} " , file = sys .stderr )
223
263
return 1
0 commit comments