Helix Core is now P4. Product user interfaces will be updated soon. Learn more >>

P4 CLI Documentation | 2025.2

# Stream components

A stream component is similar to an import of default paths because both allow the stream client to have access to files outside of the current stream. An advantage of a stream component is that it avoids the maintenance issues associated with keeping default paths up to date.

Stream components allow stream client views to include other stream views. Any stream can become a component by being referenced in another stream view.

Components can be nested to arbitrary levels. For example, stream A references component stream B, which references component stream C, which references component stream D.

A stream component only affects client views. Branch views are not affected by stream components, so integrations between parent and child are unaffected by component definitions.

A stream cannot reference itself as a component, either directly or indirectly through other referenced component streams.

## Enabling stream components

By default, the stream components feature is not enabled. To enable this feature, set the dm.stream.components configurable to `1`.

## Defining readonly stream components

A readonly stream component is defined with this syntax:

`component_type component_folder component_stream[@[change | automatic_label]]`

such as

`readonly dirB //streams/B`

where

component_type | component_folder | component_stream[@[change | automatic_label]]
--- | --- | ---
is `readonly`, so component files can be synced (and even opened for edit), but cannot be submitted | Specifies a directory prefix for each component view file. The specified directory is directly under the workspace root directory. | Specifies the name and path of the component stream, which can be pinned to a change or automatic label. If `@change` or @automatic_label is specified, The version of the component stream specification at or before the change or label is used Any files synced will be at revisions at or before the change or label.

If neither `@change` nor @automatic_label is specified, the view is not pinned to any change number but instead defaults to the current revision at that time.

### StreamAtChange applies to components@change

Do not confuse `@change` with `@head` because a StreamAtChange applies to all streams, including those contributing to the view as Components.

For example, when setting `StreamAtChange=86`, you are asking for the view at change `86`, which includes the streamviews for `//str/comp-devDD` at change `86` (or before). This might be helpful when you want to see what the stream view was at a particular point in time. This might be useful if your stream spec changes frequently, such as changing what you are importing or what you are sharing. However, when you use the StreamAtChange option in a workspace, you cannot submit changes to the files in the stream because your workspace view is not up to date.

Although the spec for the stream might have a component at the head revision when setting `StreamAtChange=86`, the version limit is at `86`, not at `head`. In this scenario, the value of `@change` overrides the value of `@head`.

## Examples of stream components

For example, given three streams, //streams/A, //streams/B, and //streams/C,

and //streams/A has a component definition

    readonly dirB //streams/B

and //streams/B has a component definition

    readonly dirC //streams/C

a client of `//streams/A` therefore has the views

    //streams/A/...  //clientname/...
    //streams/B/...  //clientname/dirB/...
    //streams/C/...  //clientname/dirB/dirC/...

and a client of //streams/B therefore has the views

    //streams/B/...  //clientname/...
    //streams/C/...  //clientname/dirC/...

In this example, the client of /streams/A does not need to maintain default paths for //streams/B and //streams/C. Therefore, if //streams/C upgrades its path for a new library version, all the stream views that consume the //streams/C component automatically have access to that new library version.

For security, the p4 protect protections table remains in force. For example, if a user has `//clientname/dirB/dirC/...` in the component view, but lacks the `read` protection for that directory, that user cannot read those files.

### Source stream and source path type

Suppose that stream A consumes component B, and B consumes component C, and C has a path

`import oRead/... //other/oRead/...`

This causes a client of A to get the view

`//other/oRead/... //clientOfA/dirB/dirC/oRead/...`

where A is the stream, C is the source stream, and `import` is the source path type.

In other words, C is the source stream because C is a component that A consumes.

### inheritance and noinherit

Component views are inherited by descendants of the defining stream, unless a descendant has a `noinherit` ParentView. For example, if a mainline stream consumes two components, the development stream that is a child of that mainline stream also consumes those same two components.

If a descendant stream is converted to have a `noinherit` ParentView, the component definition is copied to the descendant. In this way, a `noinherit` ParentView child stream can continue to consume the same components directly as it did by inheritance from its parent prior to conversion to `noinherit`.

A stream component only affects client views. Branch views are not affected by stream components, so integrations between parent and child are unaffected by component definitions.

### Additional information

See also the `p4 help stream` command-line output.

## Writable components

Starting in 2022.2, a stream consumer can set the `component_type` to `readonly`, `writeimport+`, or `writeall`. Both `writeimport+`, or `writeall` allow stream consumer clients to open for edit and submit changes to files in certain paths in the stream component:

writeimport+ | writeall
--- | ---
Applies solely to `import+` paths in the stream component. | Applies to `share`, `isolate`, or `import+` paths in the stream component.
To learn more, see the path types for the Paths: field of p4 stream.

### Defining writeable stream components

A writeable stream component is defined with this syntax:

`component_type component_folder component_stream`

such as

`writeimport+ dirWI //streams/W1`

or

`writeall dirWA //streams/WA`

where

component_type | component_folder | component_stream
--- | --- | ---
Is `writeimport+` or `writeall` | Specifies a directory prefix for each component view file. The specified directory is directly under the workspace root directory. | Specifies the name and path of the component stream. Writeable stream components do NOT support `@change` or @automatic_label, so the view is not pinned to any change number but instead defaults to the head version.

### Effective component type and the end component

The effective component type in a chain of components of different types is whichever `component_type` is the most restrictive for views originating from the end component in the chain.

The end component is the final component in a chain of components. In the Examples of stream components above where stream A consumes B, and B consumes C, the end component is C.

Consider these two cases:

- If stream A defines a `writeall` component B, and B defines a `readonly` component C, the views that originate from paths in the end component, C, are `readonly.`

  - Because `readonly` is the most restrictive `component_type`, if `readonly` exists at any location in the chain, `readonly` applies throughout the chain when the view originates from the end component.

- If stream A defines a `writeimport+` component B, and B defines a `writeall` component C, the views in A that originate from `share` or `isolate` paths in the end component, C, are `readonly`, while `import+` paths in C are writable.

  - Because `writeimport+` is more restrictive than `writeall`, it is `writeimport+` that applies throughout the chain when the view originates from the end component, and `writeimport+` prevents writing to `share` or `isolate` paths.

## Viewing imported files

The `--streamviews` option of `p4 dirs`, `p4 files`, and `p4 fstat` reports files and directories from stream Paths and Components. Imported files are represented as symbolic links under the stream depot path.

For example, if stream C has the import, and there is one actual file in each of A, B, and C

then

    p4 stream -o //root/C

includes in its output:

    Paths:
        share ...
        import oRead/... //other/oRead/...

and

    p4 sync -f

outputs:

    //root/A/a1#1 - refreshing /home/maria/test/components/client/a1
    //root/B/b1#1 - refreshing /home/maria/test/components/client/dirB/b1
    //root/C/c1#1 - refreshing /home/maria/test/components/client/dirB/dirC/c1
    //other/oRead/or1#1 - refreshing /home/maria/test/components/client/dirB/dirC/oRead/or1

and

    p4 files --streamviews //root/A/...

outputs:

    //root/A/dirB/dirC/oRead/or1#1 (mapped to //other/oRead/or1) - add change 4 (text)
    //root/A/a1#1 - add change 8 (text)
    //root/A/dirB/b1#1 (mapped to //root/B/b1) - add change 9 (text)
    //root/A/dirB/dirC/c1#1 (mapped to //root/C/c1) - add change 10 (text)

The `--streamviews` option is convenient because you can view this report without having to create a new workspace.

## Example of pinned and unpinned readonly components

Before listing the commands to run, let's begin with the orange boxes showing that in this example, m1_devA consumes m2_devB, which consumes m3_devC:

and an overview of how P4V displays the effect of stream components in such a chain:

To set up the example,

1. Enable the Stream Components feature by setting the dm.stream.components configurable on the P4 Server:

       p4 configure set dm.stream.components=1

2. Create three mainline streams, main1, main2, and main3:

       p4 stream -t mainline //streamD1/main1

       p4 stream -t mainline //streamD1/main2

       p4 stream -t mainline //streamD1/main3

3. Create a child stream of type development for main1 with m1_devA as its name.

       p4 stream -t development -P //streamD1/main1 //streamD1/m1_devA

   and in the stream spec, make m2_devB be a component of m1_devA

       Components:
             readonly m2_dirB //streamD1/m2_devB

4. Create a child stream of type development for main2 with m2_devB as its name.

       p4 stream -t development -P //streamD1/main2 //streamD1/m2_devB

   and in the stream spec, make m3_devC be a component of m2_devB with m3_devC pinned at changelist 12193

       Components:
             readonly m2_dirC //streamD1/m3_devC@12193

5. Create a child stream of type development for main3 with m3_devC as its name.

       p4 stream -t development -P //streamD1/main3 //streamD1/m3_devC

6. Verify that stream components are being consumed. For example, the output of

       p4 stream -ov //streamD1/m1_devA

   includes

       View:
             //streamD1/m1_devA/... ...
             //streamD1/m2_devB/... m2_dirB/...
            //streamD1/m3_devC/... m2_dirB/m2_dirC/...
       ChangeView:
           //streamD1/m3_devC/...@12193

7. Verify the limiting changelist pin by running

       p4 stream -o //streamD1/m2_devB

   and the output includes @12193 as the limiting changlist pin.

       Components:
             readonly m2_dirC //streamD1/m3_devC@12193

8. Files from the component streams can be sync’d using workspace associated with the consuming stream, such as

       p4 -c m1_devA_ws sync //streamD1/m2_devB/...

9. Files from a component stream that is not pinned can be edited, which might be useful for testing purposes, but they cannot be submitted to the depot.
   When you run

       p4 -c m1_devA_ws edit //streamD1/m2_devB/main2_f1.txt

   the output includes "opened for edit" but also says "warning: cannot submit from stream //streamD1/m1_devA client".

10. Pinned component stream files cannot be edited, so the output of

        p4 -c m1_devA_ws edit //streamD1/m3_devC/main3_f1.txt

    includes "//m1_devA_ws/m2_dirB/m2_dirC/main3_f1.txt - can't edit file that is restricted by client's ChangeView mapping".

Your search for returned results