Skip to content

Add new —remap flag for files-pull#262

Open
WPprodigy wants to merge 13 commits into
trunkfrom
add/files-pull-remap
Open

Add new —remap flag for files-pull#262
WPprodigy wants to merge 13 commits into
trunkfrom
add/files-pull-remap

Conversation

@WPprodigy

@WPprodigy WPprodigy commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Tell the importer where to place certain files during files-pull via a new --remap SOURCE TARGET flag:

It places a source subtree at a chosen path under --fs-root instead of nesting it under the source's full absolute path — so instead of content landing at /srv/htdocs/var/www/html/wp-content/…, it lands at /srv/htdocs/wp-content.

--remap :wp-content: :fs-root:/wp-content
--remap :wp-content: /srv/htdocs/wp-content   # same thing as above

# Most-specific source wins
--remap :wp-content: :fs-root:/wp-content --remap :wp-uploads: :fs-root:/media

The SOURCE and TARGET are template strings, known :token:s are substituted with real paths, and the result must be an absolute path.

  • SOURCE — a remote WP-layout token, or a raw absolute remote path:
    • :wp-content: :wp-plugins: :wp-mu-plugins: :wp-uploads: — the source site's real component locations, discovered during preflight (so they're correct even when relocated, e.g. uploads under /user/site-media-files).
    • :abspath: — the source's WP core root, for things outside wp-content (:abspath:/wp-admin).
    • a raw absolute path (/var/www/…) — pulled verbatim.
  • TARGET — a :fs-root:-anchored path or a raw absolute path:
    • it must resolve within --fs-root (otherwise it's an error). :fs-root: expands to the --fs-root you passed.

Testing

You'll need a source site with the reprint exporter installed.

  DOCROOT=/tmp/remap-test  STATE=/tmp/remap-state
  URL="https://YOUR-SITE.com/?reprint-api"  SECRET="<migration secret>"

  rm -rf "$DOCROOT" "$STATE"; mkdir -p "$DOCROOT" "$STATE"

  php importer/import.php preflight  "$URL" --state-dir="$STATE" --fs-root="$DOCROOT" --secret="$SECRET"

  # re-run until it prints "complete" (resumable; exits non-zero while partial)
  php importer/import.php files-pull "$URL" --state-dir="$STATE" --fs-root="$DOCROOT" --secret="$SECRET" \
    --remap :wp-content: :fs-root:/custom/wp-content --no-follow-symlinks

Then confirm placement:

  • ls "$DOCROOT/custom/wp-content" — plugins/ themes/ uploads/ … (landed here via --remap)
  • ls "$DOCROOT"custom/ and var/ (core falls through, nested under var/www/html)

Tell the importer where to place certain files via a new flag:

```
—remap SRC TARGET

—remap wp-content /srv/htdocs/wp-content
```

The SRC is a generic path that references where the traditional WP component would live. It’s automatically converted the to real path on the source site.

The TARGET is either a relative path based on the docroot, or a full path.
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Pull pipeline performance — large-directory

Site: large-directory · 2,000+ plus targeted file-transfer scenarios files · 10,000 posts · 25,000 postmeta · PHP 8.5.7

Stage PR trunk Δ Status Details
playground-sqlite-db-pull 9.74 s 9.36 s ⚪ +374 ms (+4.0%) condition=db-pull in PHP.wasm
runtime=php.wasm 8.3
wp_mysql_parser=enabled
mode=lexer
native_lexer=verified
native_token_stream=WP_MySQL_Native_Token_Stream
native_token_count=18
native_parser=selected
trunk: condition=db-pull in PHP.wasm
runtime=php.wasm 8.3
wp_mysql_parser=enabled
mode=lexer
native_lexer=verified
native_token_stream=WP_MySQL_Native_Token_Stream
native_token_count=18
native_parser=selected
playground-sqlite-db-apply 3.61 s 3.56 s ⚪ +52 ms (+1.5%) condition=db-apply to SQLite in PHP.wasm
runtime=php.wasm 8.3
wp_mysql_parser=enabled
mode=parser
native_lexer=verified
native_token_stream=WP_MySQL_Native_Token_Stream
native_token_count=18
native_parser=verified
native_ast=WP_MySQL_Native_Parser_Node
sqlite_driver_parser=verified
trunk: condition=db-apply to SQLite in PHP.wasm
runtime=php.wasm 8.3
wp_mysql_parser=enabled
mode=parser
native_lexer=verified
native_token_stream=WP_MySQL_Native_Token_Stream
native_token_count=18
native_parser=verified
native_ast=WP_MySQL_Native_Parser_Node
sqlite_driver_parser=verified
Total 13.35 s 12.92 s ⚪ +426 ms (+3.3%)

Numbers carry runner noise; treat single-run deltas as directional, not authoritative.

📈 Trunk performance history — commit-by-commit timeline.

@atanas-dev atanas-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. I haven't tested this; I just gave it a once-over.

Comment thread packages/reprint-importer/src/import.php Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new --remap SRC TGT flag to the files-pull command, allowing users to control where source files are placed locally instead of nesting them under their full remote absolute path. The feature resolves source paths using preflight WordPress component data and supports automatic expansion for detached components (e.g., relocated uploads directories).

Changes:

  • New resolve_remap() method that converts user-provided WP-layout source paths into absolute source→target rules using preflight data, including automatic expansion for detached wp-content sub-components
  • New remap_source_path_to_target() routing method integrated into remote_path_to_local_path_within_import_root() with longest-match-wins specificity
  • CLI option registration as a repeatable pair type (consistent with existing --rewrite-url), plus integration with get_export_directories() to ensure the remote exporter traverses remapped source paths

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
packages/reprint-importer/src/import.php Core implementation: remap_rules property, resolve_remap(), wp_component_source_paths(), resolve_source_path(), remap_source_path_to_target(), path_remainder_under(), integration into remote_path_to_local_path_within_import_root() and get_export_directories(), CLI option definition
tests/Import/RemapSeamTest.php Tests for the path-routing seam: in-scope paths map to target, deeper source wins, docroot-root target, out-of-scope fallback, and no-rules legacy behavior
tests/Import/RemapResolveTest.php Tests for rule resolution: wp-content mapping, absolute target normalization, slash trimming, detached component expansion, component source resolution, manual override of expansion, non-wp-content paths, and docroot target

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
// Pass 2: Do a whole tree remap for wp-content's components if needed.
if ($wp_content_target !== null) {
foreach (["plugins", "mu-plugins", "uploads"] as $name) {
$source = $source_paths[$name];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any chance either of these directories is missing on the source site?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is possible I suppose, but we can only give it best effort. We consult the preflight for information on where they exist. If they don't exist, then there's just not going to be any files being transferred under these paths, so the remapping won't be doing anything anyway.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That works! I mostly want to make sure it won't derail the whole procedure. 👍

Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
return [
"abspath" => $abspath,
"content" => $content_dir,
"plugins" => $this->flatten_clean_path($paths["plugins_dir"] ?? null) ?? $content_dir . "/plugins",

@adamziel adamziel Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$content_dir . "/plugins" assumes that directory exists on the remote site. Can we confirm that in the index? Ditto for the other lines below.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if the preflight hasn't run yet and found a wp-content dir, it'll error out earlier on in wp_component_source_paths(): Cannot resolve --remap: preflight has no content_dir. Run preflight first.

With preflight present, a component path that doesn't exist on the source is basically a no-op anyway. The exporter enumerates nothing under it, so the rule never matches a file.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, cool! That would make a great inline comment for when we read this code in the future.

Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php
- Use full words for variable names
- Utilize wp_join_unix_paths()
-  Use a single key => value array for $remap_rules
@WPprodigy

Copy link
Copy Markdown
Collaborator Author

Pushed some updates addressing the feedback, and updated the PR description with the new grammar/setup.

The main change is having --remap SOURCE TARGET now uses template-string tokens. The source is an explicit :token: (:wp-uploads:, :abspath:, …) or a raw absolute path, and the target is :fs-root:-anchored or absolute. That removes the "is this a literal path or a logical location?" ambiguity.

Also addressed:

  • Spelled-out variable names; single source => target rules array;
  • Used wp_join_unix_paths() throughout.
  • A leading slash now means "absolute path" instead of being silently trimmed; trailing slashes trimmed when needed; decided to just hard reject relative paths for now.
  • The target paths are validated to stay within --fs-root.

Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Comment thread packages/reprint-importer/src/import.php Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants