Port of RPM package building changes from PR dotnet/core-setup#2462 (dotnet/core...
authorVivek Mishra <vivmish@microsoft.com>
Thu, 25 May 2017 00:17:48 +0000 (17:17 -0700)
committerGitHub <noreply@github.com>
Thu, 25 May 2017 00:17:48 +0000 (17:17 -0700)
* Port of RPM packaging changes from PR dotnet/core-setup#2462

* Port of RPM packaging changes from PR dotnet/core-setup#2462

* Removed the publish RID for Centos

* Updated the Changelog template as pre review comments

* Update the description and summary for SF to comply with char limits

* Update the description and summary for SF to comply with char limits

* Format installer and archive file name per new guidelines (dotnet/core-setup#2461)

* format installer and archive file name per new guidelines

* Updated the installer and compressed files per feedback. Also, taking care of extra space in Brand name.

* Port of fix dotnet/core-setup#2517-Core-Setup-Linux-BT definition to have PortableBuild=false

Commit migrated from https://github.com/dotnet/core-setup/commit/f3abf93e9546f56cafe16acd00e64f1482a868b6

13 files changed:
src/installer/pkg/packaging/deb/dotnet-sharedhost-debian_config.json
src/installer/pkg/packaging/dir.proj
src/installer/pkg/packaging/rpm/dotnet-hostfxr-rpm_config.json [new file with mode: 0644]
src/installer/pkg/packaging/rpm/dotnet-sharedframework-rpm_config.json [new file with mode: 0644]
src/installer/pkg/packaging/rpm/dotnet-sharedhost-rpm_config.json [new file with mode: 0644]
src/installer/pkg/packaging/rpm/package.props [new file with mode: 0644]
src/installer/pkg/packaging/rpm/package.targets [new file with mode: 0644]
src/installer/pkg/packaging/rpm/scripts/after_install_host.sh [new file with mode: 0644]
src/installer/pkg/packaging/rpm/scripts/after_remove_host.sh [new file with mode: 0644]
src/installer/pkg/packaging/rpm/templates/changelog [new file with mode: 0644]
src/installer/pkg/packaging/rpm/templates/copyright [new file with mode: 0644]
src/installer/publish/dir.props
tools-local/tasks/BuildFPMToolPreReqs .cs [new file with mode: 0644]

index e144623..9b14a61 100644 (file)
@@ -13,7 +13,7 @@
         "package_version":"1.0.0.0",
         "package_revision":"1",
         "urgency" : "low",
-        "changelog_message" : "Inital shared host."
+        "changelog_message" : "Initial shared host."
     },
 
     "control": {
index c78e413..d009bd5 100644 (file)
   <Import Project="windows\package.targets" />
   <Import Project="osx\package.targets" />
   <Import Project="deb\package.targets" />
+  <Import Project="rpm\package.targets" />
 
   <PropertyGroup>
    <InstallerDependsOn>
      GenerateBundles;
      GeneratePkgs;
      GenerateDebs;
+     GenerateRpms;
    </InstallerDependsOn>
   </PropertyGroup>
   <Target Name="GenerateInstallers" DependsOnTargets="InitPackage;$(InstallerDependsOn)" />
diff --git a/src/installer/pkg/packaging/rpm/dotnet-hostfxr-rpm_config.json b/src/installer/pkg/packaging/rpm/dotnet-hostfxr-rpm_config.json
new file mode 100644 (file)
index 0000000..a3caeff
--- /dev/null
@@ -0,0 +1,42 @@
+{
+  "maintainer_name": "Microsoft",
+  "maintainer_email": "dotnetcore@microsoft.com",
+  
+  "package_name": "%HOSTFXR_RPM_PACKAGE_NAME%",
+  "install_root": "/usr/share/dotnet",
+  "install_doc": "/usr/share/doc/%HOSTFXR_RPM_PACKAGE_NAME%/",
+  
+  "short_description": "%HOSTFXR_BRAND_NAME% %HOSTFXR_NUGET_VERSION%",
+  "long_description": ".NET Core is a development platform that you can use to build command-line\napplications, microservices and modern websites. It is open source,\ncross-platform and is supported by Microsoft. We hope you enjoy using it!\nIf you do, please consider joining the active community of developers that are\ncontributing to the project on GitHub (https://github.com/dotnet/core).\nWe happily accept issues and PRs.",
+  "homepage": "https://github.com/dotnet/core",
+  
+  "release":{
+        "package_version":"1.0.0.0",
+        "package_revision":"1",
+        "urgency" : "low",
+        "changelog_message" : "Versioned Hostfxr"
+  },
+  
+  "control": {
+        "priority":"standard",
+        "section":"libs",
+        "architecture":"amd64"
+  },
+  
+  "copyright": "2015 Microsoft",
+  
+  "license": {
+    "type": "MIT",
+    "full_text": "Copyright (c) 2015 Microsoft\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
+  },
+  
+  "rpm_dependencies": [{
+      "package_name": "dotnet-host",
+      "package_version": "%SHARED_HOST_RPM_VERSION%"
+    }],
+
+  "directories" : [
+        "/usr/share/dotnet/host",
+        "/usr/share/doc/%HOSTFXR_RPM_PACKAGE_NAME%"
+    ]
+}
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/dotnet-sharedframework-rpm_config.json b/src/installer/pkg/packaging/rpm/dotnet-sharedframework-rpm_config.json
new file mode 100644 (file)
index 0000000..0a7ef7b
--- /dev/null
@@ -0,0 +1,49 @@
+{
+    "maintainer_name":"Microsoft",
+    "maintainer_email": "dotnetcore@microsoft.com",
+
+    "package_name": "%SHARED_FRAMEWORK_RPM_PACKAGE_NAME%",
+    "install_root": "/usr/share/dotnet",
+    "install_doc": "/usr/share/doc/%SHARED_FRAMEWORK_RPM_PACKAGE_NAME%/",
+
+    "short_description": "%SHARED_FRAMEWORK_BRAND_NAME% %SHARED_FRAMEWORK_NUGET_NAME%",
+    "long_description": ".NET Core is a development platform that you can use to build command-line\napplications, microservices and modern websites. It is open source,\ncross-platform and is supported by Microsoft. We hope you enjoy using it!\nIf you do, please consider joining the active community of developers that are\ncontributing to the project on GitHub (https://github.com/dotnet/core).\nWe happily accept issues and PRs.",
+    "homepage": "https://github.com/dotnet/core",
+
+    "release":{
+        "package_version":"1.0.0.0",
+        "package_revision":"1",
+        "urgency" : "low",
+        "changelog_message" : "Initial shared framework."
+    },
+   
+    "control": {
+        "priority":"standard",
+        "section":"libs",
+        "architecture":"amd64"
+    },
+
+    "copyright": "2015 Microsoft",
+    "license": {
+        "type": "MIT",
+        "full_text": "Copyright (c) 2015 Microsoft\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
+    },
+    
+  "rpm_dependencies": [{
+      "package_name": "%HOSTFXR_RPM_PACKAGE_NAME%",
+      "package_version": ""
+    },
+    {
+      "package_name": "openssl-libs",
+      "package_version": ""
+    },   
+    {
+      "package_name": "libcurl",
+      "package_version": ""
+    }],
+   
+    "directories" : [
+        "/usr/share/dotnet/shared",
+        "/usr/share/doc/%SHARED_FRAMEWORK_RPM_PACKAGE_NAME%"
+    ]
+}
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/dotnet-sharedhost-rpm_config.json b/src/installer/pkg/packaging/rpm/dotnet-sharedhost-rpm_config.json
new file mode 100644 (file)
index 0000000..fc2ce89
--- /dev/null
@@ -0,0 +1,45 @@
+{
+    "maintainer_name":"Microsoft",
+    "maintainer_email": "dotnetcore@microsoft.com",
+
+    "package_name": "dotnet-host",
+    "install_root": "/usr/share/dotnet",
+    "install_doc": "/usr/share/doc/dotnet-host/",
+    "install_man": "/usr/share/man/man1",
+
+    "short_description": "%SHARED_HOST_BRAND_NAME%",
+    "long_description": ".NET Core is a development platform that you can use to build command-line\napplications, microservices and modern websites. It is open source,\ncross-platform and is supported by Microsoft. We hope you enjoy using it!\nIf you do, please consider joining the active community of developers that are\ncontributing to the project on GitHub (https://github.com/dotnet/core).\nWe happily accept issues and PRs.",
+    "homepage": "https://github.com/dotnet/core",
+
+    "release":{
+        "package_version":"1.0.0.0",
+        "package_revision":"1",
+        "urgency" : "low",
+        "changelog_message" : "Initial shared host."
+    },
+    
+    "control": {
+        "priority":"standard",
+        "section":"libs",
+        "architecture":"amd64"
+    },
+
+    "copyright": "2015 Microsoft",
+    "license": {
+        "type": "MIT",
+        "full_text": "Copyright (c) 2015 Microsoft\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
+    },
+
+    "package_conflicts" : [
+        "dotnet",
+        "dotnet-nightly"
+    ],
+
+    "directories" : [
+        "/usr/share/dotnet",
+        "/usr/share/doc/dotnet-host"
+    ],
+
+    "after_install_source": "scripts/after_install_host.sh",
+    "after_remove_source": "scripts/after_remove_host.sh"
+}
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/package.props b/src/installer/pkg/packaging/rpm/package.props
new file mode 100644 (file)
index 0000000..3bef4e4
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <rpmConfigJsonName>rpm_config.json</rpmConfigJsonName>
+    <rpmPackagingConfigPath>$(PackagingRoot)rpm/</rpmPackagingConfigPath>
+    <SharedHostRpmPkgName>dotnet-host</SharedHostRpmPkgName>
+    <SharedHostRpmPkgName>$(SharedHostRpmPkgName.ToLower())</SharedHostRpmPkgName>
+    <HostFxrRpmPkgName>dotnet-hostfxr-$(HostResolverVersion)</HostFxrRpmPkgName>
+    <HostFxrRpmPkgName>$(HostFxrRpmPkgName.ToLower())</HostFxrRpmPkgName>
+    <SharedFxRpmPkgName>dotnet-sharedframework-$(SharedFrameworkName)-$(SharedFrameworkNugetVersion)</SharedFxRpmPkgName>
+    <SharedFxRpmPkgName>$(SharedFxRpmPkgName.ToLower())</SharedFxRpmPkgName>
+    <TemplatesDir>$(MSBuildThisFileDirectory)/templates</TemplatesDir>
+    <ScriptsDir>$(MSBuildThisFileDirectory)/scripts</ScriptsDir>
+  </PropertyGroup>
+</Project>
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/package.targets b/src/installer/pkg/packaging/rpm/package.targets
new file mode 100644 (file)
index 0000000..347d5c1
--- /dev/null
@@ -0,0 +1,293 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Import Project='package.props' />
+
+  <UsingTask TaskName="ReplaceFileContents" AssemblyFile="$(LocalBuildToolsTaskDir)core-setup.tasks.dll"/>
+  <UsingTask TaskName="BuildFPMToolPreReqs" AssemblyFile="$(LocalBuildToolsTaskDir)core-setup.tasks.dll"/>
+
+  <PropertyGroup>
+    <IsRPMBasedDistro Condition="$(PackageTargetRid.StartsWith('rhel')) or
+                                    $(PackageTargetRid.StartsWith('centos'))">true</IsRPMBasedDistro>
+    <BuildRpmPackage Condition="'$(IsRPMBasedDistro)' == true and '$(TargetArchitecture)' == 'x64'">true</BuildRpmPackage>
+  </PropertyGroup>
+
+  <Target Name="GenerateRpms"
+          DependsOnTargets="TestFPMTool;BuildRpms;"
+          Condition="'$(BuildRpmPackage)'=='true'" />
+
+  <Target Name="BuildRpms"
+          DependsOnTargets="GenerateSharedHostRpm;GenerateHostFxrRpm;GenerateSharedFrameworkRpm"
+          Condition="'$(BuildRpmPackage)'=='true' and '$(FPMPresent)'=='true'" />
+
+  <Target Name="GenerateSharedHostRpm">
+    <PropertyGroup>
+      <RpmPackageName>$(SharedHostRpmPkgName)</RpmPackageName>
+      <RpmPackageVersion>$(HostVersion)</RpmPackageVersion>
+      <InputRoot>$(SharedHostPublishRoot)</InputRoot>
+      <RpmFile>$(SharedHostInstallerFile)</RpmFile>
+      <ManPagesDir>$(ProjectDir)Documentation/manpages</ManPagesDir>
+      <ConfigJsonName>dotnet-sharedhost-rpm_config.json</ConfigJsonName>
+      <ConfigJsonFile>$(rpmPackagingConfigPath)$(ConfigJsonName)</ConfigJsonFile>
+      <RpmIntermediatesDir>$(PackagesIntermediateDir)$(RpmPackageName)/$(RpmPackageVersion)</RpmIntermediatesDir>
+    </PropertyGroup>
+
+    <PropertyGroup>
+      <rpmLayoutDirectory>$(RpmIntermediatesDir)/rpmLayoutDirectory/</rpmLayoutDirectory>
+      <rpmLayoutPackageRoot>$(rpmLayoutDirectory)package_root</rpmLayoutPackageRoot>
+      <rpmLayoutDocs>$(rpmLayoutDirectory)docs</rpmLayoutDocs>                <!-- Man Pages -->
+      <rpmLayoutTemplates>$(rpmLayoutDirectory)templates</rpmLayoutTemplates> <!-- Copyright, Changelog -->
+      <rpmLayoutScripts>$(rpmLayoutDirectory)scripts</rpmLayoutScripts>
+    </PropertyGroup>
+
+    <RemoveDir Condition="Exists('$(RpmIntermediatesDir)')" Directories="$(RpmIntermediatesDir)" />
+    <MakeDir Directories="$(RpmIntermediatesDir)" />
+    
+    <!-- Create empty rpm layout -->
+    <RemoveDir Condition="Exists('$(rpmLayoutDirectory)')" Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutPackageRoot)" />
+    <MakeDir Directories="$(rpmLayoutDocs)" />
+    <MakeDir Directories="$(rpmLayoutTemplates)" />
+    <MakeDir Directories="$(rpmLayoutScripts)" />
+
+    <!-- Copy files to rpm layout -->
+    <ItemGroup>
+        <SHFiles Include="$(InputRoot)/**/*" />
+        <SHManpages Include="$(ManPagesDir)/**/*" />
+        <SHTemplatesFiles Include="$(TemplatesDir)/**/*" />
+        <SHScriptsFiles Include="$(ScriptsDir)/**/*" />
+    </ItemGroup>
+
+    <Copy SourceFiles="@(SHFiles)" DestinationFiles="@(SHFiles->'$(rpmLayoutPackageRoot)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    <Copy SourceFiles="@(SHManpages)" DestinationFiles="@(SHManpages->'$(rpmLayoutDocs)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    <Copy SourceFiles="@(SHTemplatesFiles)" DestinationFiles="@(SHTemplatesFiles->'$(rpmLayoutTemplates)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    <Copy SourceFiles="@(SHScriptsFiles)" DestinationFiles="@(SHScriptsFiles->'$(rpmLayoutScripts)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    
+    <!-- Replace config json variables -->
+    <ItemGroup>
+      <SharedHostTokenValue Include="%SHARED_HOST_BRAND_NAME%">
+        <ReplacementString>$(SharedHostBrandName)</ReplacementString>
+      </SharedHostTokenValue>
+    </ItemGroup>
+
+    <ReplaceFileContents InputFile="$(ConfigJsonFile)"
+                         DestinationFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)"
+                         ReplacementItems="@(SharedHostTokenValue)" />
+    
+    <!-- Call the task to build the pre-reqs (parameters, copyright, changelog) for calling the FPM tool -->
+    <BuildFPMToolPreReqs  InputDir="$(rpmLayoutDirectory)"
+                          OutputDir="$(RpmIntermediatesDir)"
+                          PackageVersion="$(RpmPackageVersion)"
+                          ConfigJsonFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)">
+                          <Output TaskParameter="FPMParameters" PropertyName="FPMCmdParameters" />
+    </BuildFPMToolPreReqs>
+
+    <!-- Build the RPM package by calling the FPM tool and passing the parameter list -->
+    <Exec Command="fpm $(FPMCmdParameters)" WorkingDirectory="$(RpmIntermediatesDir)" />
+
+   <!-- Copy package to output -->   
+    <ItemGroup>
+      <GeneratedRpmFiles Remove="@(GeneratedRpmFiles)" />
+      <GeneratedRpmFiles Include="$(RpmIntermediatesDir)/*.rpm" />
+    </ItemGroup>
+
+    <Error Text="@(GeneratedRpmFiles->Count()) .rpm files generated." Condition="'@(GeneratedRpmFiles->Count())' != 1" />
+
+    <Copy SourceFiles="@(GeneratedRpmFiles)"
+          DestinationFiles="$(RpmFile)"
+          OverwriteReadOnlyFiles="True"
+          SkipUnchangedFiles="False"
+          UseHardlinksIfPossible="False" />
+
+  </Target>
+
+  <Target Name="GenerateHostFxrRpm">
+    <PropertyGroup>
+      <RpmPackageName>$(HostFxrRpmPkgName)</RpmPackageName>
+      <RpmPackageVersion>$(HostResolverVersion)</RpmPackageVersion>
+      <InputRoot>$(HostFxrPublishRoot)</InputRoot>
+      <RpmFile>$(HostFxrInstallerFile)</RpmFile>
+      <ConfigJsonName>dotnet-hostfxr-rpm_config.json</ConfigJsonName>
+      <ConfigJsonFile>$(rpmPackagingConfigPath)$(ConfigJsonName)</ConfigJsonFile>
+      <RpmIntermediatesDir>$(PackagesIntermediateDir)$(RpmPackageName)/$(RpmPackageVersion)</RpmIntermediatesDir>
+    </PropertyGroup>
+
+    <PropertyGroup>
+      <rpmLayoutDirectory>$(RpmIntermediatesDir)/rpmLayoutDirectory/</rpmLayoutDirectory>
+      <rpmLayoutPackageRoot>$(rpmLayoutDirectory)package_root</rpmLayoutPackageRoot>
+      <rpmLayoutDocs>$(rpmLayoutDirectory)docs</rpmLayoutDocs>
+      <rpmLayoutTemplates>$(rpmLayoutDirectory)templates</rpmLayoutTemplates> <!-- Copyright, Changelog -->
+    </PropertyGroup>
+
+    <RemoveDir Condition="Exists('$(RpmIntermediatesDir)')" Directories="$(RpmIntermediatesDir)" />
+    <MakeDir Directories="$(RpmIntermediatesDir)" />
+
+    <!-- Create empty rpm layout -->
+    <RemoveDir Condition="Exists('$(rpmLayoutDirectory)')" Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutPackageRoot)" />
+    <MakeDir Directories="$(rpmLayoutDocs)" />
+    <MakeDir Directories="$(rpmLayoutTemplates)" />
+
+    <!-- Copy files to rpm layout -->
+    <ItemGroup>
+        <HFFiles Include="$(InputRoot)/**/*" />
+        <HFTemplatesFiles Include="$(TemplatesDir)/**/*" />
+    </ItemGroup>
+
+    <Copy SourceFiles="@(HFFiles)" DestinationFiles="@(HFFiles->'$(rpmLayoutPackageRoot)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    <Copy SourceFiles="@(HFTemplatesFiles)" DestinationFiles="@(HFTemplatesFiles->'$(rpmLayoutTemplates)/%(RecursiveDir)%(Filename)%(Extension)')" />
+
+    <!-- Replace config json variables -->
+    <ItemGroup>
+      <HostFxrTokenValue Include="%HOSTFXR_BRAND_NAME%">
+        <ReplacementString>$(HostFxrBrandName)</ReplacementString>
+      </HostFxrTokenValue>
+      <HostFxrTokenValue Include="%SHARED_HOST_RPM_VERSION%">
+        <ReplacementString>$(HostVersion)</ReplacementString>
+      </HostFxrTokenValue>
+      <HostFxrTokenValue Include="%HOSTFXR_NUGET_VERSION%">
+        <ReplacementString>$(HostResolverVersion)</ReplacementString>
+      </HostFxrTokenValue>
+      <HostFxrTokenValue Include="%HOSTFXR_RPM_PACKAGE_NAME%">
+        <ReplacementString>$(RpmPackageName)</ReplacementString>
+      </HostFxrTokenValue>
+    </ItemGroup>
+
+    <ReplaceFileContents InputFile="$(ConfigJsonFile)"
+                         DestinationFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)"
+                         ReplacementItems="@(HostFxrTokenValue)" />
+
+    <!-- Call the task to build the pre-reqs (parameters, copyright, changelog) for calling the FPM tool -->
+    <BuildFPMToolPreReqs  InputDir="$(rpmLayoutDirectory)"
+                          OutputDir="$(RpmIntermediatesDir)"
+                          PackageVersion="$(RpmPackageVersion)"
+                          ConfigJsonFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)">
+                          <Output TaskParameter="FPMParameters" PropertyName="FPMCmdParameters" />
+    </BuildFPMToolPreReqs>
+
+    <!-- Build the RPM package by calling the FPM tool and passing the parameter list -->
+    <Exec Command="fpm $(FPMCmdParameters)"  WorkingDirectory="$(RpmIntermediatesDir)" />
+    
+    <!-- Copy package to output -->
+    <ItemGroup>
+      <GeneratedRpmFiles Remove="@(GeneratedRpmFiles)" />
+      <GeneratedRpmFiles Include="$(RpmIntermediatesDir)/*.rpm" />
+    </ItemGroup>
+
+    <Error Text="@(GeneratedRpmFiles->Count()) .rpm files generated." Condition="'@(GeneratedRpmFiles->Count())' != 1" />
+
+    <Copy SourceFiles="@(GeneratedRpmFiles)"
+          DestinationFiles="$(RpmFile)"
+          OverwriteReadOnlyFiles="True"
+          SkipUnchangedFiles="False"
+          UseHardlinksIfPossible="False" />
+
+  </Target>
+
+  <Target Name="GenerateSharedFrameworkRpm">
+    <PropertyGroup>
+      <RpmPackageName>$(SharedFxRpmPkgName)</RpmPackageName>
+      <RpmPackageVersion>$(SharedFrameworkNugetVersion)</RpmPackageVersion>
+      <InputRoot>$(SharedFrameworkPublishRoot)</InputRoot>
+      <RpmFile>$(SharedFrameworkInstallerFile)</RpmFile>
+      <ConfigJsonName>dotnet-sharedframework-rpm_config.json</ConfigJsonName>
+      <ConfigJsonFile>$(rpmPackagingConfigPath)$(ConfigJsonName)</ConfigJsonFile>
+      <RpmIntermediatesDir>$(PackagesIntermediateDir)$(RpmPackageName)/$(RpmPackageVersion)</RpmIntermediatesDir>
+    </PropertyGroup>
+
+    <PropertyGroup>
+      <rpmLayoutDirectory>$(RpmIntermediatesDir)/rpmLayoutDirectory/</rpmLayoutDirectory>
+      <rpmLayoutPackageRoot>$(rpmLayoutDirectory)package_root</rpmLayoutPackageRoot>
+      <rpmLayoutDocs>$(rpmLayoutDirectory)docs</rpmLayoutDocs>
+      <rpmLayoutTemplates>$(rpmLayoutDirectory)templates</rpmLayoutTemplates> <!-- Copyright, Changelog -->
+    </PropertyGroup>
+
+    <RemoveDir Condition="Exists('$(RpmIntermediatesDir)')" Directories="$(RpmIntermediatesDir)" />
+    <MakeDir Directories="$(RpmIntermediatesDir)" />
+
+    <!-- Create empty rpm layout -->
+    <RemoveDir Condition="Exists('$(rpmLayoutDirectory)')" Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutDirectory)" />
+    <MakeDir Directories="$(rpmLayoutPackageRoot)" />
+    <MakeDir Directories="$(rpmLayoutDocs)" />
+    <MakeDir Directories="$(rpmLayoutTemplates)" />
+
+    <!-- Copy files to rpm layout -->
+    <ItemGroup>
+        <SFFiles Include="$(InputRoot)/**/*" />
+        <SFTemplatesFiles Include="$(TemplatesDir)/**/*" />
+    </ItemGroup>
+
+    <Copy SourceFiles="@(SFFiles)" DestinationFiles="@(SFFiles->'$(rpmLayoutPackageRoot)/%(RecursiveDir)%(Filename)%(Extension)')" />
+    <Copy SourceFiles="@(SFTemplatesFiles)" DestinationFiles="@(SFTemplatesFiles->'$(rpmLayoutTemplates)/%(RecursiveDir)%(Filename)%(Extension)')" />
+
+    <!-- Replace config json variables -->
+    <ItemGroup>
+      <SharedFrameworkTokenValue Include="%HOSTFXR_RPM_PACKAGE_NAME%">
+        <ReplacementString>$(HostFxrRpmPkgName)</ReplacementString>
+      </SharedFrameworkTokenValue>
+      <SharedFrameworkTokenValue Include="%SHARED_FRAMEWORK_RPM_PACKAGE_NAME%">
+        <ReplacementString>$(SharedFxRpmPkgName)</ReplacementString>
+      </SharedFrameworkTokenValue>
+      <SharedFrameworkTokenValue Include="%SHARED_FRAMEWORK_NUGET_NAME%">
+        <ReplacementString>$(SharedFrameworkName)</ReplacementString>
+      </SharedFrameworkTokenValue>
+      <SharedFrameworkTokenValue Include="%SHARED_FRAMEWORK_NUGET_VERSION%">
+        <ReplacementString>$(SharedFrameworkNugetVersion)</ReplacementString>
+      </SharedFrameworkTokenValue>
+      <SharedFrameworkTokenValue Include="%SHARED_FRAMEWORK_BRAND_NAME%">
+        <ReplacementString>$(SharedFrameworkBrandName)</ReplacementString>
+      </SharedFrameworkTokenValue>
+    </ItemGroup>
+
+    <ReplaceFileContents InputFile="$(ConfigJsonFile)"
+                         DestinationFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)"
+                         ReplacementItems="@(SharedFrameworkTokenValue)" />
+
+    <!-- Call the task to build the pre-reqs (parameters, copyright, changelog) for calling the FPM tool -->
+    <BuildFPMToolPreReqs  InputDir="$(rpmLayoutDirectory)"
+                          OutputDir="$(RpmIntermediatesDir)"
+                          PackageVersion="$(RpmPackageVersion)"
+                          ConfigJsonFile="$(rpmLayoutDirectory)$(rpmConfigJsonName)">
+                          <Output TaskParameter="FPMParameters" PropertyName="FPMCmdParameters" />
+    </BuildFPMToolPreReqs>
+
+    <!-- Build the RPM package by calling the FPM tool and passing the parameter list -->
+    <Exec Command="fpm $(FPMCmdParameters)"  WorkingDirectory="$(RpmIntermediatesDir)" />
+    
+    <!-- Copy package to output -->
+    <ItemGroup>
+      <GeneratedRpmFiles Remove="@(GeneratedRpmFiles)" />
+      <GeneratedRpmFiles Include="$(RpmIntermediatesDir)/*.rpm" />
+    </ItemGroup>
+
+    <Error Text="@(GeneratedRpmFiles->Count()) .rpm files generated." Condition="'@(GeneratedRpmFiles->Count())' != 1" />
+
+    <Copy SourceFiles="@(GeneratedRpmFiles)"
+          DestinationFiles="$(RpmFile)"
+          OverwriteReadOnlyFiles="True"
+          SkipUnchangedFiles="False"
+          UseHardlinksIfPossible="False" />
+
+  </Target>
+
+  <Target Name="TestFPMTool">
+
+    <!-- run FPM  -->
+    <Exec Command="/usr/bin/env fpm -h" ContinueOnError="true">
+      <Output TaskParameter="ExitCode" PropertyName="FPMExitCode" />
+    </Exec>
+
+    <!-- Check if it returned 0 -->
+    <PropertyGroup>
+      <FPMPresent>false</FPMPresent>
+      <FPMPresent Condition=" '$(FPMExitCode)' == '0' ">true</FPMPresent>
+    </PropertyGroup>
+
+    <!-- Workaround for Jenkins machines that don't have the necessary packages https://github.com/dotnet/core-setup/issues/2260 -->
+    <Message Condition=" '$(FPMPresent)'  != 'true' "
+             Text="FPM tool Not found, RPM packages will not be built."
+             Importance="High" />
+  </Target>
+</Project>
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/scripts/after_install_host.sh b/src/installer/pkg/packaging/rpm/scripts/after_install_host.sh
new file mode 100644 (file)
index 0000000..9943b1b
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+echo "Creating dotnet host symbolic link: /usr/bin/dotnet"
+ln -sf "/usr/share/dotnet/dotnet" "/usr/bin/dotnet"
\ No newline at end of file
diff --git a/src/installer/pkg/packaging/rpm/scripts/after_remove_host.sh b/src/installer/pkg/packaging/rpm/scripts/after_remove_host.sh
new file mode 100644 (file)
index 0000000..e0bb6b5
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# Copyright (c) .NET Foundation and contributors. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+#
+echo "Removing dotnet host symbolic link"
+unlink /usr/bin/dotnet
diff --git a/src/installer/pkg/packaging/rpm/templates/changelog b/src/installer/pkg/packaging/rpm/templates/changelog
new file mode 100644 (file)
index 0000000..e61dbc6
--- /dev/null
@@ -0,0 +1,2 @@
+* {DATE} {MAINTAINER_NAME} <{MAINTAINER_EMAIL}> - {PACKAGE_VERSION}-{PACKAGE_REVISION}
+- {CHANGELOG_MESSAGE}
diff --git a/src/installer/pkg/packaging/rpm/templates/copyright b/src/installer/pkg/packaging/rpm/templates/copyright
new file mode 100644 (file)
index 0000000..a336435
--- /dev/null
@@ -0,0 +1,8 @@
+Comment: Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+Files: *
+Copyright: {COPYRIGHT_TEXT}
+License: {LICENSE_NAME}
+
+License: {LICENSE_NAME}
+ {LICENSE_TEXT}
\ No newline at end of file
index 8f739f8..cc777ea 100644 (file)
@@ -48,5 +48,6 @@
     <PublishRid Include="win-arm" />
     <PublishRid Include="win-arm64" />
     <PublishRid Include="linux-arm" />
+    <PublishRid Include="rhel.7-x64" />
   </ItemGroup>
 </Project>
diff --git a/tools-local/tasks/BuildFPMToolPreReqs .cs b/tools-local/tasks/BuildFPMToolPreReqs .cs
new file mode 100644 (file)
index 0000000..031b4f4
--- /dev/null
@@ -0,0 +1,318 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.Framework;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Newtonsoft.Json;
+
+namespace Microsoft.DotNet.Build.Tasks
+{
+    /// <summary>
+    /// This task prepares the command line parameters for running a RPM build using FPM tool and also updates the copyright and changelog file tokens.
+    /// If parses various values from the config json by first reading it into a model and then builds the required string for parameters and passes it back.
+    /// 
+    /// </summary>
+    public class BuildFPMToolPreReqs : BuildTask
+    {
+        [Required]
+        public string InputDir { get; set; }
+        [Required]
+        public string OutputDir { get; set; }
+        [Required]
+        public string PackageVersion { get; set; }
+        [Required]
+        public string ConfigJsonFile { get; set; }
+        [Output]
+        public string FPMParameters { get; set; }
+
+        public override bool Execute()
+        {
+            try
+            {
+                if (!File.Exists(ConfigJsonFile))
+                {
+                    throw new FileNotFoundException($"Expected file {ConfigJsonFile} was not found.");
+                }
+
+                // Open the Config Json and read the values into the model
+                TextReader projectFileReader = File.OpenText(ConfigJsonFile);
+                if (projectFileReader != null)
+                {
+                    string jsonFileText = projectFileReader.ReadToEnd();
+                    ConfigJson configJson = JsonConvert.DeserializeObject<ConfigJson>(jsonFileText);
+
+                    // Update the Changelog and Copyright files by replacing tokens with values from config json
+                    UpdateChangelog(configJson, PackageVersion);
+                    UpdateCopyRight(configJson);
+
+                    // Build the full list of parameters 
+                    FPMParameters = BuildCmdParameters(configJson, PackageVersion);
+                    Log.LogMessage(MessageImportance.Normal, "Generated RPM paramters:  " + FPMParameters);
+                }
+                else
+                {
+                    throw new IOException($"Could not open the file {ConfigJsonFile} for reading.");
+                }
+            }
+            catch (Exception e)
+            {
+                Log.LogError("Exception while processing RPM paramters: " + e.Message);
+            }
+
+            return !Log.HasLoggedErrors;
+        }
+
+        // Update the tokens in the changelog file from the config Json 
+        private void UpdateChangelog(ConfigJson configJson, string package_version)
+        {
+            try
+            {
+                string changelogFile = Path.Combine(InputDir, "templates", "changelog");
+                if (!File.Exists(changelogFile))
+                {
+                    throw new FileNotFoundException($"Expected file {changelogFile} was not found.");
+                }
+                string str = File.ReadAllText(changelogFile);
+                str = str.Replace("{PACKAGE_NAME}", configJson.Package_Name);
+                str = str.Replace("{PACKAGE_VERSION}", package_version);
+                str = str.Replace("{PACKAGE_REVISION}", configJson.Release.Package_Revision);
+                str = str.Replace("{URGENCY}", configJson.Release.Urgency);
+                str = str.Replace("{CHANGELOG_MESSAGE}", configJson.Release.Changelog_Message);
+                str = str.Replace("{MAINTAINER_NAME}", configJson.Maintainer_Name);
+                str = str.Replace("{MAINTAINER_EMAIL}", configJson.Maintainer_Email);
+                // The date format needs to be like Wed May 17 2017
+                str = str.Replace("{DATE}", DateTime.UtcNow.ToString("ddd MMM dd yyyy")); 
+                File.WriteAllText(changelogFile, str);
+            }
+            catch (Exception e)
+            {
+                Log.LogError("Exception while updating the changelog file: " + e.Message);
+            }
+        }
+
+        public void UpdateCopyRight(ConfigJson configJson)
+        {
+            try
+            {
+                // Update the tokens in the copyright file from the config Json 
+                string copyrightFile = Path.Combine(InputDir, "templates", "copyright");
+                if (!File.Exists(copyrightFile))
+                {
+                    throw new FileNotFoundException($"Expected file {copyrightFile} was not found.");
+                }
+                string str = File.ReadAllText(copyrightFile);
+                str = str.Replace("{COPYRIGHT_TEXT}", configJson.CopyRight);
+                str = str.Replace("{LICENSE_NAME}", configJson.License.Type);
+                str = str.Replace("{LICENSE_NAME}", configJson.License.Type);
+                str = str.Replace("{LICENSE_TEXT}", configJson.License.Full_Text);
+                File.WriteAllText(copyrightFile, str);
+            }
+            catch (Exception e)
+            {
+                Log.LogError("Exception while updating the copyright file: " + e.Message);
+            }
+        }
+
+        private string BuildCmdParameters(ConfigJson configJson, string package_version)
+        {
+            // Parameter list that needs to be passed to FPM tool:
+            //      -s : is the input source type(dir)  --Static  
+            //      -t : is the type of package(rpm)    --Static
+            //      -n : is for the name of the package --JSON
+            //      -v : is the version to give to the package --ARG
+            //      -a : architecture  --JSON
+            //      -d : is for all dependent packages. This can be used multiple times to specify the dependencies of the package.   --JSON
+            //      --rpm-os : the operating system to target this rpm  --Static
+            //      --rpm-changelog : the changelog from FILEPATH contents  --ARG
+            //      --rpm-summary : it is the RPM summary that shows in the Title   --JSON
+            //      --description : it is the description for the package   --JSON
+            //      -p : The actual package name (with path) for your package. --ARG+JSON
+            //      --conflicts : Other packages/versions this package conflicts with provided as CSV   --JSON
+            //      --directories : Recursively add directories as being owned by the package.    --JSON
+            //      --after-install : FILEPATH to the script to be run after install of the package     --JSON
+            //      --after-remove : FILEPATH to the script to be run after package removal     --JSON
+            //      --license : the licensing name for the package. This will include the license type in the meta-data for the package, but will not include the associated license file within the package itself.    --JSON
+            //      --iteration : the iteration to give to the package. This comes from the package_revision    --JSON
+            //      --url : url for this package.   --JSON
+            //      --verbose : Set verbose output for FPM tool     --Static  
+            //      <All folder mappings> : Add all the folder mappings for packge_root, docs, man pages   --Static
+
+            var parameters = new List<string>();
+            parameters.Add("-s dir");
+            parameters.Add("-t rpm");
+            parameters.Add(string.Concat("-n ", configJson.Package_Name));
+            parameters.Add(string.Concat("-v ", package_version));
+            parameters.Add(string.Concat("-a ", configJson.Control.Architecture));
+
+            // Build the list of dependencies as -d <dep1> -d <dep2>
+            if (configJson.Rpm_Dependencies != null)
+            {
+                foreach (RpmDependency rpmdep in configJson.Rpm_Dependencies)
+                {
+                    string dependency = "";
+                    if (rpmdep.Package_Name != "")
+                    {
+                        // If no version is specified then the dependency is just the package without >= check
+                        if (rpmdep.Package_Version == "")
+                        {
+                            dependency = rpmdep.Package_Name;
+                        }
+                        else
+                        {
+                            dependency = string.Concat(rpmdep.Package_Name, " >= ", rpmdep.Package_Version);
+                        }
+                    }
+                    if (dependency != "") parameters.Add(string.Concat("-d ", EscapeArg(dependency)));
+                }
+            }
+
+            // Build the list of owned directories
+            if (configJson.Directories != null)
+            {
+                foreach (string dir in configJson.Directories)
+                {
+                    if (dir != "")
+                    {
+                        parameters.Add(string.Concat("--directories ", EscapeArg(dir)));
+                    }
+                }
+            }
+            
+            parameters.Add("--rpm-os linux");
+            parameters.Add(string.Concat("--rpm-changelog ", EscapeArg(Path.Combine(InputDir, "templates", "changelog")))); // Changelog File
+            parameters.Add(string.Concat("--rpm-summary ", EscapeArg(configJson.Short_Description)));
+            parameters.Add(string.Concat("--description ", EscapeArg(configJson.Long_Description)));
+            parameters.Add(string.Concat("--maintainer ", configJson.Maintainer_Name));
+            parameters.Add(string.Concat("-p ", Path.Combine(OutputDir, configJson.Package_Name + ".rpm")));
+            if (configJson.Package_Conflicts != null) parameters.Add(string.Concat("--conflicts ", EscapeArg(string.Join(",", configJson.Package_Conflicts))));
+            if (configJson.After_Install_Source != null) parameters.Add(string.Concat("--after-install ", Path.Combine(InputDir, EscapeArg(configJson.After_Install_Source))));
+            if (configJson.After_Remove_Source != null) parameters.Add(string.Concat("--after-remove ", Path.Combine(InputDir, EscapeArg(configJson.After_Remove_Source))));
+            parameters.Add(string.Concat("--license ", EscapeArg(configJson.License.Type)));
+            parameters.Add(string.Concat("--iteration ", configJson.Release.Package_Revision));
+            parameters.Add(string.Concat("--url ", "\"", EscapeArg(configJson.Homepage), "\""));
+            parameters.Add("--verbose");
+
+            // Map all the payload directories as they need to install on the system 
+            if (configJson.Install_Root != null) parameters.Add(string.Concat(Path.Combine(InputDir, "package_root/="), configJson.Install_Root)); // Package Files
+            if (configJson.Install_Man != null) parameters.Add(string.Concat(Path.Combine(InputDir, "docs", "host/="), configJson.Install_Man)); // Man Pages
+            if (configJson.Install_Doc != null) parameters.Add(string.Concat(Path.Combine(InputDir, "templates", "copyright="), configJson.Install_Doc)); // CopyRight File
+
+            return string.Join(" ", parameters);
+        }
+
+        private string EscapeArg(string arg)
+        {
+            var sb = new StringBuilder();
+
+            bool quoted = ShouldSurroundWithQuotes(arg);
+            if (quoted) sb.Append("\"");
+
+            for (int i = 0; i < arg.Length; ++i)
+            {
+                var backslashCount = 0;
+
+                // Consume All Backslashes
+                while (i < arg.Length && arg[i] == '\\')
+                {
+                    backslashCount++;
+                    i++;
+                }
+
+                // Escape any backslashes at the end of the arg
+                // This ensures the outside quote is interpreted as
+                // an argument delimiter
+                if (i == arg.Length)
+                {
+                    sb.Append('\\', 2 * backslashCount);
+                }
+
+                // Escape any preceding backslashes and the quote
+                else if (arg[i] == '"')
+                {
+                    sb.Append('\\', (2 * backslashCount) + 1);
+                    sb.Append('"');
+                }
+
+                // Output any consumed backslashes and the character
+                else
+                {
+                    sb.Append('\\', backslashCount);
+                    sb.Append(arg[i]);
+                }
+            }
+
+            if (quoted) sb.Append("\"");
+
+            return sb.ToString();
+        }
+        private bool ShouldSurroundWithQuotes(string argument)
+        {
+            // Don't quote already quoted strings
+            if (argument.StartsWith("\"", StringComparison.Ordinal) &&
+                    argument.EndsWith("\"", StringComparison.Ordinal))
+            {
+                return false;
+            }
+
+            // Only quote if whitespace exists in the string
+            if (argument.Contains(" ") || argument.Contains("\t") || argument.Contains("\n"))
+            {
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /// <summary>
+    /// Model classes for reading and storing the JSON. 
+    /// </summary>
+    public class ConfigJson
+    {
+        public string Maintainer_Name { get; set; }
+        public string Maintainer_Email { get; set; }
+        public string Package_Name { get; set; }
+        public string Install_Root { get; set; }
+        public string Install_Doc { get; set; }
+        public string Install_Man { get; set; }
+        public string Short_Description { get; set; }
+        public string Long_Description { get; set; }
+        public string Homepage { get; set; }
+        public string CopyRight { get; set; }
+        public Release Release { get; set; }
+        public Control Control { get; set; }
+        public License License { get; set; }
+        public List<RpmDependency> Rpm_Dependencies { get; set; }
+        public List<string> Package_Conflicts { get; set; }
+        public List<string> Directories { get; set; }
+        public string After_Install_Source { get; set; }
+        public string After_Remove_Source { get; set; }
+    }
+    public class Release
+    {
+        public string Package_Version { get; set; }
+        public string Package_Revision { get; set; }
+        public string Urgency { get; set; }
+        public string Changelog_Message { get; set; }
+    }
+    public class Control
+    {
+        public string Priority { get; set; }
+        public string Section { get; set; }
+        public string Architecture { get; set; }
+    }
+    public class License
+    {
+        public string Type { get; set; }
+        public string Full_Text { get; set; }
+    }
+    public class RpmDependency
+    {
+        public string Package_Name { get; set; }
+        public string Package_Version { get; set; }
+    }
+}