Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Single-file publishing #3074

Closed
wants to merge 8 commits into from

Conversation

swaroop-sridhar
Copy link
Contributor

This change implements support for publishing apps to a single file.

  • dotnet publish /p:PublishSingleFile=true causes the contents of the "original" publish directory to a single file in the actual publish directory
  • Files marked with the meta-data <IncludeInSingleFile>false<IncludeInSingleFile> are left in the publish directory unbundled. This includes PDB files by default
  • PDB files can be bundled into the single file by setting /p:IncludePdbInSingleFile=true

Publishing to a single file requires publishing wrt a RID using an apphost, because the generated file is the platform-specific AppHost executable with embedded dependencies.

Test Pass: requires a change to the bundler, which is waiting to be updated in the toolset repo.

@@ -127,7 +192,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<Target Name="_CopyResolvedFilesToPublishPreserveNewest"
DependsOnTargets="_ComputeResolvedFilesToPublishTypes"
Inputs="@(_ResolvedFileToPublishPreserveNewest)"
Outputs="@(_ResolvedFileToPublishPreserveNewest->'$(PublishDir)%(RelativePath)')">
Outputs="@(_ResolvedFileToPublishPreserveNewest->'$(PreBundlePublishDir)%(RelativePath)')">
Copy link
Member

Choose a reason for hiding this comment

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

This is not consistent with copy step below.


<Target Name="BundlePublishDirectory"
Condition="'$(PublishSingleFile)' == 'true'"
Inputs="$(PreBundlePublishDir)\**\*.*"
Copy link
Member

Choose a reason for hiding this comment

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

Per our discussion I don't think wildcard syntax works for includes. You'll need to run a target before and evaulate this into an item.

<BundleArgs>$(BundleArgs) -o $(PublishDir)</BundleArgs>
</PropertyGroup>

<Exec Command="$(DOTNET_HOST_PATH) $(MicrosoftDotnetBundle) $(BundleArgs)" />
Copy link
Member

Choose a reason for hiding this comment

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

SDK folks, is this the right property to use for launching dotnet.exe?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Inputs="$(PreBundlePublishDir)\**\*.*"
Outputs="$(PublishDir)\$(AssemblyName)$(_NativeExecutableExtension)">
<PropertyGroup>
<BundleArgs>--source $(PreBundlePublishDir) </BundleArgs>
Copy link
Member

Choose a reason for hiding this comment

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

Try this with spaces in the path to the project file and spaces in the project file name / assembly file itself.

UseHardlinksIfPossible="$(CreateHardLinksForPublishFilesIfPossible)"
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForPublishFilesIfPossible)">

<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
Copy link
Member

Choose a reason for hiding this comment

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

I don't think appending to FileWrites will help here, since incremental clean doesn't write the file back during publish. Moreover I don't think having an intermediate directory with a copy of all the files is buying you anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ericstj: The bundler currently takes in a publish directory and generates the bundled files. This can be changed to accept a series of files.

However, I'm not clear about one scenario in that case. There was a request to bundle the contents of the publish directory and all of its subdirectories. The bundler currently handles this case: reads files from all sub-directories of the --source directory; writes a manifest of files and sub-directory paths into the bundle.

If there's a PreBundlePublish directory, app developers can write anything to it, and have the contents bundled. If we don't have it, I'm not sure how this can be handled. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In order to support sub-directories, I think the bundler interface needs to support an interface that identifies:

  • The file to be bundled
  • The relative path within the bundle (The value of RelativePath)

@swaroop-sridhar
Copy link
Contributor Author

CC: @nguerrera please review

@swaroop-sridhar
Copy link
Contributor Author

At the time of this PR, the bundler was:

  • Built as an app instead of a library
  • Invoked from the SDK out-of-proc in order to enforce strict API boundaries
    However, since the SDK implementation progressed, we've had to revisit the above decisions.

First, the bundler currently is implemented to take a folder vs a list of files to bundle.

  • This causes unnecessary extra copies to the publish directory.
    • The files to be bundled need not be first copied to the publish directory.
    • Instead they can be written directly to the bundle.
  • Stale items remaining in the publish directory may be written into the bundle unnecessarily.
    Therefore, we decided that the bundler should take tuples of (source file-path, relative-path within bundle) instead of the publish folder as input.

While it is possible to provide this input on the command-line/response file, it is convenient and more efficient to do it in-proc.
Further, the SDK team agrees that the bundler is simple enough to run in-proc with the build system.

Therefore, we agreed to make the following changes:

  • Bundler will be built into a library Microsoft.NET.HostModel in core-setup repo (similar to DependencyModel) (Build the Bundler as a library core-setup#5798)
    • Other apphost related services like stamping the app.dll name into the apphost will be moded into this library
  • A task in the SDK repo will consume this library through package reference (from myget)
    (Publish to Single-File #3132)

Therefore, closing this issue in deference to #3132

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.

2 participants