organize with `app: app/app` is not working correctly
Metadata
Current evaluation
No evaluation has been recorded for this issue yet.
Issue body
### Bug Description
I have followed the [fastapi tutorial](https://documentation.ubuntu.com/rockcraft/en/latest/tutorial/fastapi/), but instead of creating the file `app.py` in the base directory, I have created the file `main.py` inside the directory `app`.
That is, the tree of the files is:
```
ubuntu@paas-charm:~/delete/fastapi-hello-world$ tree
.
├── app
│ ├── __init__.py
│ └── main.py
├── requirements.txt
└── rockcraft.yaml
```
Running `ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true rockcraft pack` I get the error:
```
*EXPERIMENTAL* extension 'fastapi-framework' enabled
/root/parts/fastapi-framework/install-app/install/app: No such file or directory
Detailed information: FileNotFoundError: filename: '/root/parts/fastapi-framework/install-app/install/app'
Failed to run rockcraft in instance
Full execution log: '/home/ubuntu/.local/state/rockcraft/log/rockcraft-20250530-174607.442030.log'
```
The reason looks related to the part `fastapi-framework/install-app`. Running `rockcraft expand-extensions`, that part shows:
```
fastapi-framework/install-app:
plugin: dump
source: .
organize:
app: app/app
stage:
- app/app
```
However, the directory app/app is not in the install directory in the lxd machine to build the rock.
```
rockcraft-fastapi-hello-world-amd64-7078398 # ls parts/fastapi-framework/install-app/
build export install layer run src state
```
### To Reproduce
Inside a directory named `fastapi-hello-world`
File requirements.txt
```
fastapi[standard]>=0.109.1
```
File rockcraft.yaml:
```
name: fastapi-hello-world
base: ubuntu@24.04 # the base environment for this FastAPI application
version: '0.1' # just for humans. Semantic versioning is recommended
summary: A summary of your FastAPI application # 79 char long summary
description: |
This is fastapi project's description. You have a paragraph or two to tell the
most important story about it. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the
container registries out there.
platforms:
amd64:
extensions:
- fastapi-framework
```
File `app/main.py`
```
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
```
Also create an empty file named `app/__init__.py`
`ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true rockcraft expand-extensions` fails with error:
```
ubuntu@paas-charm:~/delete/fastapi-hello-world$ ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true rockcraft pack
*EXPERIMENTAL* extension 'fastapi-framework' enabled
Launching managed ubuntu 24.04 instance... :: Starting instance
*EXPERIMENTAL* extension 'fastapi-framework' enabled
/root/parts/fastapi-framework/install-app/install/app: No such file or directory
Detailed information: FileNotFoundError: filename: '/root/parts/fastapi-framework/install-app/install/app'
Failed to run rockcraft in instance
Full execution log: '/home/ubuntu/.local/state/rockcraft/log/rockcraft-20250530-175109.115787.log'
```
### Environment
```
ubuntu@paas-charm:~/delete/fastapi-hello-world$ sudo snap list rockcraft
Name Version Rev Tracking Publisher Notes
rockcraft 1.11.0 3313 latest/stable canonical✓ classic
```
It also fails with rockcraft `latest/edge` as of today
### rockcraft.yaml
```yaml
# This is the expanded rockcraft:
name: fastapi-hello-world
title: fastapi-hello-world
version: '0.1'
summary: A summary of your FastAPI application
description: |
This is fastapi project's description. You have a paragraph or two to tell the
most important story about it. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the
container registries out there.
base: ubuntu@24.04
platforms:
amd64:
build-on:
- amd64
build-for:
- amd64
parts:
fastapi-framework/dependencies:
plugin: python
stage-packages:
- python3-venv
source: .
python-packages:
- uvicorn
python-requirements:
- requirements.txt
fastapi-framework/install-app:
plugin: dump
source: .
organize:
app: app/app
stage:
- app/app
fastapi-framework/runtime:
plugin: nil
stage-packages:
- ca-certificates_data
run-user: _daemon_
services:
fastapi:
override: replace
command: /bin/python3 -m uvicorn app.main:app
startup: enabled
environment:
UVICORN_HOST: 0.0.0.0
user: _daemon_
working-dir: /app
```
### Relevant log output
```shell
:: 2025-05-30 17:51:38.801 execute action fastapi-framework/install-app:Action(part_name='fastapi-framework/install-app', step=Step.STAGE, action_type=ActionType.RUN, reason=None, project_vars=None, properties=ActionProperties(changed_files=None, changed_dirs=None))
:: 2025-05-30 17:51:39.328 /root/parts/fastapi-framework/install-app/install/app: No such file or directory
:: 2025-05-30 17:51:39.328 Detailed information: FileNotFoundError: filename: '/root/parts/fastapi-framework/install-app/install/app'
:: 2025-05-30 17:51:39.332 Traceback (most recent call last):
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/services/lifecycle.py", line 302, in run
:: 2025-05-30 17:51:39.332 aex.execute(action, stdout=stream, stderr=stream)
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 326, in execute
:: 2025-05-30 17:51:39.332 self._executor.execute(actions, stdout=stdout, stderr=stderr)
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 136, in execute
:: 2025-05-30 17:51:39.332 self._run_action(act, stdout=stdout, stderr=stderr)
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/executor.py", line 213, in _run_action
:: 2025-05-30 17:51:39.332 handler.run_action(action, stdout=stdout, stderr=stderr)
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 203, in run_action
:: 2025-05-30 17:51:39.332 state = handler(step_info, stdout=stdout, stderr=stderr)
:: 2025-05-30 17:51:39.332 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 408, in _run_stage
:: 2025-05-30 17:51:39.332 self._run_step(
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/part_handler.py", line 537, in _run_step
:: 2025-05-30 17:51:39.332 return step_handler.run_builtin()
:: 2025-05-30 17:51:39.332 ^^^^^^^^^^^^^^^^^^^^^^^^^^
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/step_handler.py", line 115, in run_builtin
:: 2025-05-30 17:51:39.332 return handler()
:: 2025-05-30 17:51:39.332 ^^^^^^^^^
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/step_handler.py", line 214, in _builtin_stage
:: 2025-05-30 17:51:39.332 files, dirs = migrate_files(
:: 2025-05-30 17:51:39.332 ^^^^^^^^^^^^^^
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/executor/migration.py", line 78, in migrate_files
:: 2025-05-30 17:51:39.332 file_utils.create_similar_directory(
:: 2025-05-30 17:51:39.332 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_parts/utils/file_utils.py", line 270, in create_similar_directory
:: 2025-05-30 17:51:39.332 stat = os.stat(source, follow_symlinks=False)
:: 2025-05-30 17:51:39.332 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:: 2025-05-30 17:51:39.332 FileNotFoundError: [Errno 2] No such file or directory: '/root/parts/fastapi-framework/install-app/install/app'
2025-05-30 17:51:39.795 Executing in container: lxc --project rockcraft exec local:rockcraft-fastapi-hello-world-amd64-7078398 -- env CRAFT_MANAGED_MODE=1 ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_PRIORITY=critical test -f /tmp/rockcraft-pack.yaml
2025-05-30 17:51:40.063 Could not find state file /tmp/rockcraft-pack.yaml in instance.
2025-05-30 17:51:40.064 Executing on host: lxc --project rockcraft config device show local:rockcraft-fastapi-hello-world-amd64-7078398
2025-05-30 17:51:40.126 Executing on host: lxc --project rockcraft config device remove local:rockcraft-fastapi-hello-world-amd64-7078398 disk-/root/project
2025-05-30 17:51:40.217 Executing on host: lxc --project rockcraft stop local:rockcraft-fastapi-hello-world-amd64-7078398
2025-05-30 17:51:44.200 Executing on host: lxc --project rockcraft list local: --format=yaml
2025-05-30 17:51:44.336 Executing on host: lxc --project rockcraft list local: --format=yaml
2025-05-30 17:51:44.494 Failed to run rockcraft in instance
2025-05-30 17:51:44.495 Traceback (most recent call last):
2025-05-30 17:51:44.495 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/services/provider.py", line 448, in run_managed
2025-05-30 17:51:44.495 instance.execute_run( # pyright: ignore[reportUnknownMemberType,reportUnknownVariableType]
2025-05-30 17:51:44.495 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_providers/lxd/lxd_instance.py", line 254, in execute_run
2025-05-30 17:51:44.495 return self.lxc.exec(
2025-05-30 17:51:44.495 ^^^^^^^^^^^^^^
2025-05-30 17:51:44.495 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_providers/lxd/lxc.py", line 390, in exec
2025-05-30 17:51:44.495 return runner(final_cmd, timeout=timeout, check=check, **kwargs)
2025-05-30 17:51:44.495 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.495 File "/snap/rockcraft/current/usr/lib/python3.12/subprocess.py", line 571, in run
2025-05-30 17:51:44.495 raise CalledProcessError(retcode, process.args,
2025-05-30 17:51:44.495 subprocess.CalledProcessError: Command '['lxc', '--project', 'rockcraft', 'exec', 'local:rockcraft-fastapi-hello-world-amd64-7078398', '--cwd', '/root/project', '--', 'env', 'CRAFT_MANAGED_MODE=1', 'ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS=true', 'DEBIAN_FRONTEND=noninteractive', 'DEBCONF_NONINTERACTIVE_SEEN=true', 'DEBIAN_PRIORITY=critical', 'CRAFT_PLATFORM=amd64', 'CRAFT_VERBOSITY_LEVEL=BRIEF', 'rockcraft', 'pack']' returned non-zero exit status 1.
2025-05-30 17:51:44.495
2025-05-30 17:51:44.495 The above exception was the direct cause of the following exception:
2025-05-30 17:51:44.495 Traceback (most recent call last):
2025-05-30 17:51:44.495 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/application.py", line 615, in run
2025-05-30 17:51:44.495 return_code = self._run_inner()
2025-05-30 17:51:44.496 ^^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/application.py", line 594, in _run_inner
2025-05-30 17:51:44.496 return_code = dispatcher.run() or os.EX_OK
2025-05-30 17:51:44.496 ^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_cli/dispatcher.py", line 528, in run
2025-05-30 17:51:44.496 return self._loaded_command.run(self._parsed_command_args)
2025-05-30 17:51:44.496 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/commands/base.py", line 199, in run
2025-05-30 17:51:44.496 result = self._run(parsed_args, **kwargs) or result
2025-05-30 17:51:44.496 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 433, in _run
2025-05-30 17:51:44.496 return super()._run(parsed_args=parsed_args, step_name=step_name)
2025-05-30 17:51:44.496 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 181, in _run
2025-05-30 17:51:44.496 self._run_manager_for_build_plan(fetch_service_policy)
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/commands/lifecycle.py", line 90, in _run_manager_for_build_plan
2025-05-30 17:51:44.496 provider.run_managed(build, bool(fetch_service_policy))
2025-05-30 17:51:44.496 File "/snap/rockcraft/3313/lib/python3.12/site-packages/craft_application/services/provider.py", line 455, in run_managed
2025-05-30 17:51:44.496 raise craft_providers.ProviderError(
2025-05-30 17:51:44.496 craft_providers.errors.ProviderError: Failed to run rockcraft in instance
2025-05-30 17:51:44.496 Full execution log: '/home/ubuntu/.local/state/rockcraft/log/rockcraft-20250530-175109.115787.log'
```
Evaluation history
No evaluation history available.