sdk/Sdk/Tasks/ZipDeploy/CreateZipFileTask.cs (117 lines of code) (raw):
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Text.Json;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
// IMPORTANT: Do not modify this file directly with major changes
// This file is a copy from this project (with minor updates) -- https://github.com/Azure/azure-functions-vs-build-sdk/blob/b0e54a832a92119e00a2b1796258fcf88e0d6109/src/Microsoft.NET.Sdk.Functions.MSBuild/Microsoft.NET.Sdk.Functions.MSBuild.csproj
// Please make any changes upstream first.
namespace Microsoft.NET.Sdk.Functions.MSBuild.Tasks
{
#if NET472
[LoadInSeparateAppDomain]
public class CreateZipFileTask : AppDomainIsolatedTask
#else
public class CreateZipFileTask : Task
#endif
{
internal const string WorkerRootReplacement = "{WorkerRoot}";
// Unix file permissions for -rwxrwxrwx
internal static readonly int UnixExecutablePermissions = Convert.ToInt32("100777", 8) << 16;
[Required]
public string? FolderToZip { get; set; }
[Required]
public string? ProjectName { get; set; }
[Required]
public string? PublishIntermediateTempPath { get; set; }
[Output]
public string? CreatedZipPath { get; private set; }
public override bool Execute()
{
if (FolderToZip == null)
{
return false;
}
string zipFileName = ProjectName + " - " + DateTime.Now.ToString("yyyyMMddHHmmssFFF") + ".zip";
CreatedZipPath = Path.Combine(PublishIntermediateTempPath, zipFileName);
CreateZipFileFromDirectory(FolderToZip, CreatedZipPath);
return true;
}
internal static void CreateZipFileFromDirectory(string directoryToZip, string destinationArchiveFileName)
{
System.IO.Compression.ZipFile.CreateFromDirectory(directoryToZip, destinationArchiveFileName);
// We may need to modify permissions for Linux.
string configJson = File.ReadAllText(Path.Combine(directoryToZip, "worker.config.json"));
var configJsonDoc = JsonDocument.Parse(configJson);
if (configJsonDoc.RootElement.TryGetProperty("description", out JsonElement description) &&
description.TryGetProperty("defaultExecutablePath", out JsonElement defaultExecutablePath) &&
defaultExecutablePath.ValueKind == JsonValueKind.String)
{
string? executable = defaultExecutablePath.GetString();
// if the executable path contains "{WorkerRoot}", it means we'll be executing this file directly (as
// opposed to running with 'dotnet ...'). If so, we need to make the file executable for Linux.
if (executable != null && executable.Contains(WorkerRootReplacement))
{
executable = executable.Replace(WorkerRootReplacement, string.Empty);
if (!string.IsNullOrEmpty(executable))
{
ModifyUnixFilePermissions(destinationArchiveFileName, directoryToZip, executable);
}
}
}
}
internal static void ModifyUnixFilePermissions(string zipFilePath, string entryRootPath, string entryName)
{
using (var zipFile = new ZipFile(zipFilePath))
{
zipFile.EntryFactory = new EntryFactory();
zipFile.BeginUpdate();
try
{
string entryFullPath = Path.Combine(entryRootPath, entryName);
// In Windows, we leave off the .exe, so need to adjust the entry name
if (!File.Exists(entryFullPath))
{
entryFullPath += ".exe";
entryName += ".exe";
if (!File.Exists(entryFullPath))
{
return;
}
}
// This will overwrite the existing entry.
zipFile.Add(entryFullPath, entryName);
}
finally
{
zipFile.CommitUpdate();
zipFile.Close();
}
}
}
private class EntryFactory : IEntryFactory
{
private IEntryFactory _internal = new ZipEntryFactory();
public INameTransform NameTransform { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ZipEntryFactory.TimeSetting Setting => throw new NotImplementedException();
public DateTime FixedDateTime => throw new NotImplementedException();
public ZipEntry MakeDirectoryEntry(string directoryName)
{
throw new NotImplementedException();
}
public ZipEntry MakeDirectoryEntry(string directoryName, bool useFileSystem)
{
throw new NotImplementedException();
}
public ZipEntry MakeFileEntry(string fileName)
{
throw new NotImplementedException();
}
public ZipEntry MakeFileEntry(string fileName, bool useFileSystem)
{
throw new NotImplementedException();
}
public ZipEntry MakeFileEntry(string fileName, string entryName, bool useFileSystem)
{
var zipEntry = _internal.MakeFileEntry(fileName, entryName, useFileSystem);
// Unix
zipEntry.HostSystem = 3;
// Unix file permissions for -rwxrwxrwx
zipEntry.ExternalFileAttributes = UnixExecutablePermissions;
return zipEntry;
}
}
}
}