fastws-cli 0.0.22__tar.gz → 0.0.23__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.
- {fastws_cli-0.0.22/fastws_cli.egg-info → fastws_cli-0.0.23}/PKG-INFO +5 -3
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/README.md +4 -2
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws/__init__.py +2 -1
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws/cargo.py +3 -3
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws/core.py +36 -34
- {fastws_cli-0.0.22 → fastws_cli-0.0.23/fastws_cli.egg-info}/PKG-INFO +5 -3
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/tests/test_sync.py +3 -3
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/LICENSE +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws/build_backend.py +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws/releases.py +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws_cli.egg-info/SOURCES.txt +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws_cli.egg-info/dependency_links.txt +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws_cli.egg-info/entry_points.txt +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws_cli.egg-info/requires.txt +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/fastws_cli.egg-info/top_level.txt +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/pyproject.toml +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/setup.cfg +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/tests/test_build.py +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/tests/test_releases.py +0 -0
- {fastws_cli-0.0.22 → fastws_cli-0.0.23}/tests/test_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastws-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.23
|
|
4
4
|
Summary: Fast workspace tools for multi-repo management
|
|
5
5
|
Author: Jeremy Howard
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -99,7 +99,7 @@ Keep `repos.txt` tracked in the workspace Git repo. Put personal additions in a
|
|
|
99
99
|
|
|
100
100
|
`--repos-file myrepos.txt` uses `myrepos-local.txt` alongside it. Either list may be absent. Removing a repo from the baseline does not delete its checkout. The next sync discovers an existing root checkout as a personal addition. External checkouts also remain on disk; add them to the local list to keep managing them.
|
|
101
101
|
|
|
102
|
-
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the repo extras
|
|
102
|
+
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the managed repo extras, workspace exclusions, and build-isolation list. The template supplies starting defaults only: later template edits do not overwrite existing configuration. Ignore these files in the workspace repo (not in its member repos):
|
|
103
103
|
|
|
104
104
|
```gitignore
|
|
105
105
|
/repos-local.txt
|
|
@@ -240,7 +240,7 @@ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level dir
|
|
|
240
240
|
|
|
241
241
|
Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
|
|
242
242
|
|
|
243
|
-
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
243
|
+
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members, except a crate marked `publish = false`, which never comes from crates.io. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
244
244
|
|
|
245
245
|
Do not commit a `Cargo.lock` generated under these patches. Its source-less local entries cannot be resolved on another machine.
|
|
246
246
|
|
|
@@ -252,6 +252,8 @@ Each sync updates `workspaces` in the root `package.json`. It creates the file w
|
|
|
252
252
|
|
|
253
253
|
An optional tracked `package.json.shared` is merged into the root `package.json` on every sync. Object-valued fields merge one level deep, shared values win conflicts, and arrays replace rather than concatenate. Unrelated local settings remain; removing a shared key does not delete its local value. Workspace discovery still manages `workspaces`. Use this file for shared policy such as version-pinned npm `allowScripts` approvals.
|
|
254
254
|
|
|
255
|
+
Before `uv sync`, fastws regenerates `tool.uv.no-build-isolation-package` with the sorted package names of projects using `fastws.build_backend`, including external checkouts. These builds use the shared environment's `fastws-cli` and `maturin`. Leave global build isolation enabled for other projects.
|
|
256
|
+
|
|
255
257
|
After `uv sync`, fastws runs `cargo develop` in each mixed Rust/Python project. Cargo skips unchanged compilation inputs. These projects should keep only packaging inputs in `tool.uv.cache-keys`; Rust source changes are handled by Cargo rather than triggering a separate maturin editable build. Maturin packages with `bindings = "bin"` keep their existing uv installation path.
|
|
256
258
|
|
|
257
259
|
Fastws then runs `<tool> install` at the workspace root. It runs `<tool> run build` in each JavaScript package containing both `Cargo.toml` and a `build` script. Cargo handles incremental compilation. Other build steps still run.
|
|
@@ -74,7 +74,7 @@ Keep `repos.txt` tracked in the workspace Git repo. Put personal additions in a
|
|
|
74
74
|
|
|
75
75
|
`--repos-file myrepos.txt` uses `myrepos-local.txt` alongside it. Either list may be absent. Removing a repo from the baseline does not delete its checkout. The next sync discovers an existing root checkout as a personal addition. External checkouts also remain on disk; add them to the local list to keep managing them.
|
|
76
76
|
|
|
77
|
-
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the repo extras
|
|
77
|
+
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the managed repo extras, workspace exclusions, and build-isolation list. The template supplies starting defaults only: later template edits do not overwrite existing configuration. Ignore these files in the workspace repo (not in its member repos):
|
|
78
78
|
|
|
79
79
|
```gitignore
|
|
80
80
|
/repos-local.txt
|
|
@@ -215,7 +215,7 @@ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level dir
|
|
|
215
215
|
|
|
216
216
|
Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
|
|
217
217
|
|
|
218
|
-
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
218
|
+
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members, except a crate marked `publish = false`, which never comes from crates.io. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
219
219
|
|
|
220
220
|
Do not commit a `Cargo.lock` generated under these patches. Its source-less local entries cannot be resolved on another machine.
|
|
221
221
|
|
|
@@ -227,6 +227,8 @@ Each sync updates `workspaces` in the root `package.json`. It creates the file w
|
|
|
227
227
|
|
|
228
228
|
An optional tracked `package.json.shared` is merged into the root `package.json` on every sync. Object-valued fields merge one level deep, shared values win conflicts, and arrays replace rather than concatenate. Unrelated local settings remain; removing a shared key does not delete its local value. Workspace discovery still manages `workspaces`. Use this file for shared policy such as version-pinned npm `allowScripts` approvals.
|
|
229
229
|
|
|
230
|
+
Before `uv sync`, fastws regenerates `tool.uv.no-build-isolation-package` with the sorted package names of projects using `fastws.build_backend`, including external checkouts. These builds use the shared environment's `fastws-cli` and `maturin`. Leave global build isolation enabled for other projects.
|
|
231
|
+
|
|
230
232
|
After `uv sync`, fastws runs `cargo develop` in each mixed Rust/Python project. Cargo skips unchanged compilation inputs. These projects should keep only packaging inputs in `tool.uv.cache-keys`; Rust source changes are handled by Cargo rather than triggering a separate maturin editable build. Maturin packages with `bindings = "bin"` keep their existing uv installation path.
|
|
231
233
|
|
|
232
234
|
Fastws then runs `<tool> install` at the workspace root. It runs `<tool> run build` in each JavaScript package containing both `Cargo.toml` and a `build` script. Cargo handles incremental compilation. Other build steps still run.
|
|
@@ -59,12 +59,12 @@ def develop(root):
|
|
|
59
59
|
lib, = [f for f in artifact['filenames'] if Path(f).suffix in ('.dylib', '.so', '.dll')]
|
|
60
60
|
module = cfg.get('module-name', artifact['target']['name'])
|
|
61
61
|
dest = root/cfg['python-source']/Path(*module.split('.'))
|
|
62
|
-
|
|
62
|
+
replace(lib, dest.with_name(dest.name + sysconfig.get_config_var('EXT_SUFFIX')))
|
|
63
63
|
if binaries:
|
|
64
64
|
env = Path(os.environ.get('VIRTUAL_ENV', sys.prefix))
|
|
65
65
|
scripts = env/('Scripts' if os.name == 'nt' else 'bin')
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
for m in artifacts:
|
|
67
|
+
if m.get('executable'): replace(m['executable'], scripts/Path(m['executable']).name)
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
def stage_binaries(root, profile=None, target=None):
|
|
@@ -172,7 +172,7 @@ def _remove_from_pyproject(pyproject_path: Path, names: list[str]) -> list[str]:
|
|
|
172
172
|
sources = {k:v for k,v in sources.items() if _pkg_key(k) not in targets}
|
|
173
173
|
deps = [d for d in deps if _pkg_key(dep_key(d)) not in targets]
|
|
174
174
|
content = _replace_table(content, "tool.uv.sources", "\n".join(f"{k} = {_fmt_source(v)}" for k,v in sources.items()))
|
|
175
|
-
content =
|
|
175
|
+
content = _replace_array(content, "project", "dependencies", deps)
|
|
176
176
|
pyproject_path.write_text(content)
|
|
177
177
|
return removed
|
|
178
178
|
|
|
@@ -247,17 +247,17 @@ def _sync_ws_excludes(pyproject_path: Path, root: Path, tracked: set[str]) -> tu
|
|
|
247
247
|
survivors = set(kept) | set(auto)
|
|
248
248
|
new = [e for e in cur if e in survivors] + [e for e in kept + auto if e not in cur]
|
|
249
249
|
if new == cur: return [], []
|
|
250
|
-
content =
|
|
250
|
+
content = _replace_array(content, "tool.uv.workspace", "exclude", new)
|
|
251
251
|
tomllib.loads(content) # never write an unparseable pyproject
|
|
252
252
|
pyproject_path.write_text(content)
|
|
253
253
|
return [e for e in new if e not in cur], [e for e in cur if e not in new]
|
|
254
254
|
|
|
255
|
-
def
|
|
256
|
-
block = "
|
|
257
|
-
if not (span := _table_span(content,
|
|
255
|
+
def _replace_array(content: str, table: str, key: str, values: list[str]) -> str:
|
|
256
|
+
block = f"{key} = [\n" + "".join(f' {json.dumps(v)},\n' for v in values) + "]"
|
|
257
|
+
if not (span := _table_span(content, table)): return _replace_table(content, table, block)
|
|
258
258
|
start,end = span
|
|
259
259
|
section = content[start:end]
|
|
260
|
-
if m := re.search(
|
|
260
|
+
if m := re.search(rf"(?m)^{re.escape(key)}\s*=\s*\[", section):
|
|
261
261
|
arr_start = m.end()-1
|
|
262
262
|
arr_end = _find_array_end(section, arr_start)
|
|
263
263
|
section = section[:m.start()] + block + section[arr_end+1:]
|
|
@@ -293,18 +293,6 @@ def _find_array_end(content: str, start: int) -> int:
|
|
|
293
293
|
if depth == 0: return i
|
|
294
294
|
raise ValueError("Unterminated TOML array")
|
|
295
295
|
|
|
296
|
-
def _replace_project_dependencies(content: str, deps: list[str]) -> str:
|
|
297
|
-
if not (span := _table_span(content, "project")): raise SystemExit("Missing [project] table in pyproject.toml")
|
|
298
|
-
start,end = span
|
|
299
|
-
section = content[start:end]
|
|
300
|
-
dep_block = "dependencies = [\n" + "".join(f' {json.dumps(dep)},\n' for dep in deps) + "]"
|
|
301
|
-
if m := re.search(r"(?m)^dependencies\s*=\s*\[", section):
|
|
302
|
-
arr_start = m.end()-1
|
|
303
|
-
arr_end = _find_array_end(section, arr_start)
|
|
304
|
-
section = section[:m.start()] + dep_block + section[arr_end+1:]
|
|
305
|
-
else: section = section.rstrip() + "\n" + dep_block + "\n"
|
|
306
|
-
return content[:start] + section + content[end:]
|
|
307
|
-
|
|
308
296
|
def _init_ws_pyproject(path: Path, python: str = f"{sys.version_info.major}.{sys.version_info.minor}") -> bool:
|
|
309
297
|
if path.exists(): return False
|
|
310
298
|
major,minor = map(int, python.split(".")[:2])
|
|
@@ -348,10 +336,21 @@ def _sync_ws_pyproject(pyproject_path: Path, template_path: Path, projects: list
|
|
|
348
336
|
if missing or ext_missing:
|
|
349
337
|
source_lines = "\n".join(f"{proj} = {_fmt_source(src)}" for proj,src in sources.items())
|
|
350
338
|
content = _replace_table(content, "tool.uv.sources", source_lines)
|
|
351
|
-
if deps != data.get("project", {}).get("dependencies", []): content =
|
|
339
|
+
if deps != data.get("project", {}).get("dependencies", []): content = _replace_array(content, "project", "dependencies", deps)
|
|
352
340
|
if content != original: pyproject_path.write_text(content)
|
|
353
341
|
return missing + [n for n,_ in ext_missing]
|
|
354
342
|
|
|
343
|
+
def _sync_build_isolation(pyproject_path: Path, projects: list[tuple[str, Path]]):
|
|
344
|
+
"Regenerate uv's non-isolated build list from the projects using the fastws backend."
|
|
345
|
+
content = pyproject_path.read_text()
|
|
346
|
+
packages = sorted({name for name,d in projects
|
|
347
|
+
if tomllib.loads((d/'pyproject.toml').read_text()).get('build-system', {}).get('build-backend') == 'fastws.build_backend'})
|
|
348
|
+
current = tomllib.loads(content).get('tool', {}).get('uv', {}).get('no-build-isolation-package', [])
|
|
349
|
+
if packages == current: return
|
|
350
|
+
content = _replace_array(content, 'tool.uv', 'no-build-isolation-package', packages)
|
|
351
|
+
tomllib.loads(content)
|
|
352
|
+
pyproject_path.write_text(content)
|
|
353
|
+
|
|
355
354
|
def _editable_mapping(path: Path) -> dict[str,str]:
|
|
356
355
|
tree = ast.parse(path.read_text(), filename=str(path))
|
|
357
356
|
for node in tree.body:
|
|
@@ -564,7 +563,7 @@ def cargo_develop(
|
|
|
564
563
|
):
|
|
565
564
|
r"Build and install a mixed Rust/Python project's extension and opted-in binaries."
|
|
566
565
|
from .cargo import develop
|
|
567
|
-
|
|
566
|
+
develop(Path(path).resolve())
|
|
568
567
|
|
|
569
568
|
@call_parse(pos=['command'])
|
|
570
569
|
def cargo_stage(
|
|
@@ -645,18 +644,18 @@ def _cargo_patches(root: Path):
|
|
|
645
644
|
return patches, config
|
|
646
645
|
|
|
647
646
|
def _crate_pkgs(d: Path):
|
|
648
|
-
"(package
|
|
647
|
+
"(`[package]` table, dir) for the crate at `d` and its cargo workspace members"
|
|
649
648
|
try: data = tomllib.loads((d/"Cargo.toml").read_text())
|
|
650
649
|
except tomllib.TOMLDecodeError: return
|
|
651
|
-
if name := data.get("package", {})
|
|
650
|
+
if "name" in (pkg := data.get("package", {})): yield pkg, d
|
|
652
651
|
for m in _project_dirs(d, "Cargo.toml", data.get("workspace", {}).get("members", [])):
|
|
653
652
|
try: sub = tomllib.loads((m/"Cargo.toml").read_text())
|
|
654
653
|
except tomllib.TOMLDecodeError: continue
|
|
655
|
-
if name := sub.get("package", {})
|
|
654
|
+
if "name" in (pkg := sub.get("package", {})): yield pkg, m
|
|
656
655
|
|
|
657
|
-
def _local_crates(root: Path) -> dict
|
|
658
|
-
"
|
|
659
|
-
return
|
|
656
|
+
def _local_crates(root: Path) -> list[tuple[dict, Path]]:
|
|
657
|
+
"(`[package]` table, dir) for every crate under `root`, nested cargo workspace members included"
|
|
658
|
+
return [p for crate in _crate_dirs(root) for p in _crate_pkgs(crate)]
|
|
660
659
|
|
|
661
660
|
def _git_dep_tables(root: Path, crates: dict[str, Path]) -> dict[str, dict[str, Path]]:
|
|
662
661
|
"Git URL -> {package: local dir} for members' git deps that name a local crate"
|
|
@@ -688,14 +687,15 @@ def _entry_changes(current, new):
|
|
|
688
687
|
def _sync_cargo_patches(root: Path) -> tuple[list[str], list[str]]:
|
|
689
688
|
"""Regenerate `[patch]` entries in the workspace `.cargo/config.toml` and return (added, removed).
|
|
690
689
|
|
|
691
|
-
Every local crate gets a `[patch.crates-io]` entry,
|
|
692
|
-
an entry under that URL
|
|
693
|
-
editable installs. Only entries whose path is inside `root` are
|
|
694
|
-
elsewhere (and any other config sections) are kept as-is, and a kept entry wins
|
|
695
|
-
one of the same name."""
|
|
690
|
+
Every local crate gets a `[patch.crates-io]` entry, except one marked `publish = false`, which never comes
|
|
691
|
+
from crates.io. A member's git dep on a local crate gets an entry under that URL. Builds anywhere under `root`
|
|
692
|
+
then use the checkouts: the cargo analog of editable installs. Only entries whose path is inside `root` are
|
|
693
|
+
managed; entries pointing elsewhere (and any other config sections) are kept as-is, and a kept entry wins
|
|
694
|
+
over a generated one of the same name."""
|
|
696
695
|
root = root.resolve()
|
|
697
|
-
|
|
698
|
-
|
|
696
|
+
pkgs = _local_crates(root)
|
|
697
|
+
crates = {pkg["name"]: d for pkg, d in pkgs}
|
|
698
|
+
desired = {"crates-io": {pkg["name"]: str(d) for pkg, d in pkgs if pkg.get("publish") is not False}}
|
|
699
699
|
for url, entries in _git_dep_tables(root, crates).items(): desired[url] = {name: str(d) for name, d in entries.items()}
|
|
700
700
|
config = root/".cargo"/"config.toml"
|
|
701
701
|
content = config.read_text() if config.exists() else ""
|
|
@@ -923,6 +923,8 @@ async def ws_sync(
|
|
|
923
923
|
missing_projects = _sync_ws_pyproject(pyproject_path, template_path, _ws_projects(root), _external_projects(root, ext_dirs),
|
|
924
924
|
_repo_extras(root, entries))
|
|
925
925
|
if missing_projects: print(f"Added workspace projects: {', '.join(missing_projects)}")
|
|
926
|
+
projects = _build_projects(root, repos_file)
|
|
927
|
+
_sync_build_isolation(pyproject_path, projects)
|
|
926
928
|
|
|
927
929
|
wrapper_added = _sync_cargo_wrapper(root)
|
|
928
930
|
added_p, removed_p = _sync_cargo_patches(root)
|
|
@@ -943,7 +945,7 @@ async def ws_sync(
|
|
|
943
945
|
if up: _cargo_update(root, workers=workers)
|
|
944
946
|
_sync_cargo_keys(root)
|
|
945
947
|
subprocess.run(["uv", "sync", "-U"] if up else ["uv", "sync"], check=True, cwd=root)
|
|
946
|
-
for _,d in
|
|
948
|
+
for _,d in projects:
|
|
947
949
|
cfg = tomllib.loads((d/'pyproject.toml').read_text()).get('tool', {}).get('maturin', {})
|
|
948
950
|
if 'python-source' in cfg and cfg.get('bindings') != 'bin': cargo_develop(path=str(d))
|
|
949
951
|
if up: _upgrade_stamp(root).touch()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fastws-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.23
|
|
4
4
|
Summary: Fast workspace tools for multi-repo management
|
|
5
5
|
Author: Jeremy Howard
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -99,7 +99,7 @@ Keep `repos.txt` tracked in the workspace Git repo. Put personal additions in a
|
|
|
99
99
|
|
|
100
100
|
`--repos-file myrepos.txt` uses `myrepos-local.txt` alongside it. Either list may be absent. Removing a repo from the baseline does not delete its checkout. The next sync discovers an existing root checkout as a personal addition. External checkouts also remain on disk; add them to the local list to keep managing them.
|
|
101
101
|
|
|
102
|
-
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the repo extras
|
|
102
|
+
The workspace `pyproject.toml` is local generated state. `ws-sync` creates it from the tracked `pyproject.tmpl` when available, or generates a minimal one, then maintains it while preserving personal settings except for the managed repo extras, workspace exclusions, and build-isolation list. The template supplies starting defaults only: later template edits do not overwrite existing configuration. Ignore these files in the workspace repo (not in its member repos):
|
|
103
103
|
|
|
104
104
|
```gitignore
|
|
105
105
|
/repos-local.txt
|
|
@@ -240,7 +240,7 @@ Fastws maintains `tool.uv.workspace.exclude`. It excludes unlisted top-level dir
|
|
|
240
240
|
|
|
241
241
|
Existing globs, entries for missing directories, and entries for checkouts that are still not Python projects are retained. Use `exclude = [...]` under `[tool.fastws]` to specify exclusions the scan cannot infer, such as keeping a valid project out of the workspace. Adding members preserves hand-written `[tool.uv.sources]` entries, including path and Git sources.
|
|
242
242
|
|
|
243
|
-
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
243
|
+
Each sync regenerates Cargo overrides in the workspace's `.cargo/config.toml`. `[patch.crates-io]` gets an entry for each local crate, including nested Cargo workspace members, except a crate marked `publish = false`, which never comes from crates.io. Git dependencies that name local crates get entries under the matching URL. Builds under the workspace root use these local checkouts. Entries pointing outside the root and other configuration sections are preserved.
|
|
244
244
|
|
|
245
245
|
Do not commit a `Cargo.lock` generated under these patches. Its source-less local entries cannot be resolved on another machine.
|
|
246
246
|
|
|
@@ -252,6 +252,8 @@ Each sync updates `workspaces` in the root `package.json`. It creates the file w
|
|
|
252
252
|
|
|
253
253
|
An optional tracked `package.json.shared` is merged into the root `package.json` on every sync. Object-valued fields merge one level deep, shared values win conflicts, and arrays replace rather than concatenate. Unrelated local settings remain; removing a shared key does not delete its local value. Workspace discovery still manages `workspaces`. Use this file for shared policy such as version-pinned npm `allowScripts` approvals.
|
|
254
254
|
|
|
255
|
+
Before `uv sync`, fastws regenerates `tool.uv.no-build-isolation-package` with the sorted package names of projects using `fastws.build_backend`, including external checkouts. These builds use the shared environment's `fastws-cli` and `maturin`. Leave global build isolation enabled for other projects.
|
|
256
|
+
|
|
255
257
|
After `uv sync`, fastws runs `cargo develop` in each mixed Rust/Python project. Cargo skips unchanged compilation inputs. These projects should keep only packaging inputs in `tool.uv.cache-keys`; Rust source changes are handled by Cargo rather than triggering a separate maturin editable build. Maturin packages with `bindings = "bin"` keep their existing uv installation path.
|
|
256
258
|
|
|
257
259
|
Fastws then runs `<tool> install` at the workspace root. It runs `<tool> run build` in each JavaScript package containing both `Cargo.toml` and a `build` script. Cargo handles incremental compilation. Other build steps still run.
|
|
@@ -155,17 +155,17 @@ def test_sync_cargo_patches_generates_and_preserves(tmp_path):
|
|
|
155
155
|
(crate1/'Cargo.toml').write_text('[package]\nname = "crate1"\nversion = "0.1.0"\n\n[dependencies]\nfamily = { git = "https://example.com/family" }\n')
|
|
156
156
|
family = tmp_path/'family'
|
|
157
157
|
(family/'sub').mkdir(parents=True)
|
|
158
|
-
(family/'Cargo.toml').write_text('[package]\nname = "family"\nversion = "0.1.0"\n\n[workspace]\nmembers = ["sub"]\n')
|
|
158
|
+
(family/'Cargo.toml').write_text('[package]\nname = "family"\nversion = "0.1.0"\npublish = false\n\n[workspace]\nmembers = ["sub"]\n')
|
|
159
159
|
(family/'sub'/'Cargo.toml').write_text('[package]\nname = "family-sub"\nversion = "0.1.0"\n')
|
|
160
160
|
|
|
161
161
|
added, removed = core._sync_cargo_patches(tmp_path)
|
|
162
162
|
data = core.tomllib.loads(config.read_text())
|
|
163
163
|
cio = data['patch']['crates-io']
|
|
164
|
-
assert set(cio) == {'foreign', 'crate1', 'family
|
|
164
|
+
assert set(cio) == {'foreign', 'crate1', 'family-sub'} # `publish = false` crates never come from crates.io
|
|
165
165
|
assert cio['foreign']['path'] == '/elsewhere/foreign' # entries pointing outside the root are kept as-is
|
|
166
166
|
assert cio['crate1']['path'] == str(crate1)
|
|
167
167
|
assert cio['family-sub']['path'] == str(family/'sub')
|
|
168
|
-
assert data['patch']['https://example.com/family']['family']['path'] == str(family) # git deps on local crates get their URL table
|
|
168
|
+
assert data['patch']['https://example.com/family']['family']['path'] == str(family) # git deps on local crates get their URL table, published or not
|
|
169
169
|
assert data['term']['quiet'] is True # other sections untouched
|
|
170
170
|
assert set(added) == {'crate1', 'family', 'family-sub'} and removed == ['gone']
|
|
171
171
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|