private void Process(
            FunctionItem function,
            bool noCompile,
            bool noAssemblyValidation,
            string gitSha,
            string gitBranch,
            string buildConfiguration
            )
        {
            switch (Path.GetExtension(function.Project).ToLowerInvariant())
            {
            case "":

                // inline project; nothing to do
                break;

            case ".csproj":
                ProcessDotNet(
                    function,
                    noCompile,
                    noAssemblyValidation,
                    gitSha,
                    gitBranch,
                    buildConfiguration
                    );
                break;

            case ".js":
                ProcessJavascript(
                    function,
                    noCompile,
                    noAssemblyValidation,
                    gitSha,
                    gitBranch,
                    buildConfiguration
                    );
                break;

            case ".sbt":
                ScalaPackager.ProcessScala(
                    function,
                    noCompile,
                    noAssemblyValidation,
                    gitSha,
                    gitBranch,
                    buildConfiguration,
                    Settings.OutputDirectory,
                    _existingPackages,
                    GIT_INFO_FILE,
                    _builder
                    );
                break;

            default:
                LogError("could not determine the function language");
                return;
            }
        }
        public static void ProcessScala(
            FunctionItem function,
            bool skipCompile,
            bool noAssemblyValidation,
            string gitSha,
            string gitBranch,
            string buildConfiguration,
            string outputDirectory,
            HashSet <string> existingPackages,
            string gitInfoFilename,
            ModuleBuilder builder
            )
        {
            var showOutput     = Settings.VerboseLevel >= VerboseLevel.Detailed;
            var scalaOutputJar = ScalaPackager.Process(function, skipCompile, noAssemblyValidation, gitSha, gitBranch, buildConfiguration, showOutput);

            // compute hash for zip contents
            string hash;

            using (var zipArchive = ZipFile.OpenRead(scalaOutputJar)) {
                using (var md5 = MD5.Create())
                    using (var hashStream = new CryptoStream(Stream.Null, md5, CryptoStreamMode.Write)) {
                        foreach (var entry in zipArchive.Entries.OrderBy(e => e.FullName))
                        {
                            // hash file path
                            var filePathBytes = Encoding.UTF8.GetBytes(entry.FullName.Replace('\\', '/'));
                            hashStream.Write(filePathBytes, 0, filePathBytes.Length);

                            // hash file contents
                            using (var stream = entry.Open()) {
                                stream.CopyTo(hashStream);
                            }
                        }
                        hashStream.FlushFinalBlock();
                        hash = md5.Hash.ToHexString();
                    }
            }

            // rename function package with hash
            var package = Path.Combine(outputDirectory, $"function_{function.Name}_{hash}.jar");

            if (!existingPackages.Remove(package))
            {
                File.Move(scalaOutputJar, package);

                // add git-info.json file
                using (var zipArchive = ZipFile.Open(package, ZipArchiveMode.Update)) {
                    var entry = zipArchive.CreateEntry(gitInfoFilename);

                    // Set RW-R--R-- permissions attributes on non-Windows operating system
                    if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                    {
                        entry.ExternalAttributes = 0b1_000_000_110_100_100 << 16;
                    }
                    using (var stream = entry.Open()) {
                        stream.Write(Encoding.UTF8.GetBytes(JObject.FromObject(new ModuleManifestGitInfo {
                            SHA    = gitSha,
                            Branch = gitBranch
                        }).ToString(Formatting.None)));
                    }
                }
            }
            else
            {
                File.Delete(scalaOutputJar);
            }

            // decompress project zip into temporary folder so we can add the 'GITSHAFILE' files
            builder.AddAsset($"{function.FullName}::PackageName", package);
        }