private void VerifyOrSetDefaultStorageDirectoryPath(string desireStorageDirectoryPath)
        {
            if (string.IsNullOrEmpty(desireStorageDirectoryPath))
            {
                string storageDir = Path.Combine(Utilities.EnsureCoreToolsLocalData(), ".telemetry");
                FileSystemHelpers.EnsureDirectory(storageDir);
                _storageDirectoryPath = Path.GetFullPath(storageDir);
            }
            else
            {
                if (!Path.IsPathRooted(desireStorageDirectoryPath))
                {
                    throw new ArgumentException($"{nameof(desireStorageDirectoryPath)} need to be rooted (full path)");
                }

                _storageDirectoryPath = desireStorageDirectoryPath;
            }
        }
Пример #2
0
 protected void NotifyShutdownJob()
 {
     try
     {
         if (_shutdownNotificationFilePath != null)
         {
             OperationManager.Attempt(() =>
             {
                 FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(_shutdownNotificationFilePath));
                 FileSystemHelpers.WriteAllText(_shutdownNotificationFilePath, DateTime.UtcNow.ToString());
             });
         }
     }
     catch (Exception ex)
     {
         _analytics.UnexpectedException(ex);
     }
 }
Пример #3
0
 protected void AddOryxBuildCommand(StringBuilder args, DeploymentContext context, string source, string destination)
 {
     // If it is express build, we don't directly need to write to /home/site/wwwroot
     // So, we build into a different directory to avoid overlap
     // Additionally, we didn't run kudusync, and can just build directly from repository path
     if (Flags == BuildOptimizationsFlags.UseExpressBuild)
     {
         source      = context.RepositoryPath;
         destination = OryxBuildConstants.FunctionAppBuildSettings.ExpressBuildSetup;
         // It is important to clean and recreate the directory to make sure no overwrite occurs
         if (FileSystemHelpers.DirectoryExists(destination))
         {
             FileSystemHelpers.DeleteDirectorySafe(destination);
         }
         FileSystemHelpers.EnsureDirectory(destination);
     }
     OryxArgumentsHelper.AddOryxBuildCommand(args, source, destination);
 }
        public override async Task RunAsync()
        {
            if (SourceControl != SourceControl.Git)
            {
                throw new Exception("Only Git is supported right now for vsc");
            }

            if (!string.IsNullOrEmpty(FolderName))
            {
                var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName);
                FileSystemHelpers.EnsureDirectory(folderPath);
                Environment.CurrentDirectory = folderPath;
            }

            WorkerRuntime workerRuntime;

            if (string.IsNullOrEmpty(WorkerRuntime))
            {
                ColoredConsole.Write("Select a worker runtime: ");
                workerRuntime = SelectionMenuHelper.DisplaySelectionWizard(WorkerRuntimeLanguageHelper.AvailableWorkersList);
                ColoredConsole.WriteLine(TitleColor(workerRuntime.ToString()));
            }
            else
            {
                workerRuntime = WorkerRuntimeLanguageHelper.NormalizeWorkerRuntime(WorkerRuntime);
            }

            if (workerRuntime == Helpers.WorkerRuntime.dotnet)
            {
                await DotnetHelpers.DeployDotnetProject(Path.GetFileName(Environment.CurrentDirectory), Force);
            }
            else
            {
                await InitLanguageSpecificArtifacts(workerRuntime);
                await WriteFiles();
                await WriteLocalSettingsJson(workerRuntime);
            }

            await WriteExtensionsJson();
            await SetupSourceControl();
            await WriteDockerfile(workerRuntime);

            PostInit();
        }
Пример #5
0
        public void Save(JObject json)
        {
            _lock.LockOperation(() =>
            {
                if (!FileSystemHelpers.FileExists(_path))
                {
                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(_path));
                }

                // opens file for FileAccess.Write but does allow other dirty read (FileShare.Read).
                // it is the most optimal where write is infrequent and dirty read is acceptable.
                using (var writer = new JsonTextWriter(new StreamWriter(FileSystemHelpers.OpenFile(_path, FileMode.Create, FileAccess.Write, FileShare.Read))))
                {
                    // prefer indented-readable format
                    writer.Formatting = Formatting.Indented;
                    json.WriteTo(writer);
                }
            }, "Updating setting", _timeout);
        }
Пример #6
0
        public static void Persist(string siteName, string kind, string requestId, string status, string details)
        {
            var info = new DeploymentCompletedInfo
            {
                TimeStamp = $"{DateTime.UtcNow:s}Z",
                SiteName  = siteName,
                Kind      = kind,
                RequestId = requestId,
                Status    = status,
                Details   = details ?? string.Empty
            };

            try
            {
                var path       = Path.Combine(System.Environment.ExpandEnvironmentVariables(@"%HOME%"), "site", "deployments");
                var file       = Path.Combine(path, $"{Constants.LatestDeployment}.json");
                var serializer = new JavaScriptSerializer();
                var content    = serializer.Serialize(info);
                FileSystemHelpers.EnsureDirectory(path);

                // write deployment info to %home%\site\deployments\LatestDeployment.json
                OperationManager.Attempt(() => FileSystemHelpers.Instance.File.WriteAllText(file, content));

                // write to etw
                KuduEventSource.Log.DeploymentCompleted(
                    info.SiteName,
                    info.Kind,
                    info.RequestId,
                    info.Status,
                    info.Details);
            }
            catch (Exception ex)
            {
                KuduEventSource.Log.KuduException(
                    info.SiteName,
                    string.Empty,
                    string.Empty,
                    string.Empty,
                    string.Empty,
                    $"{ex}");
            }
        }
Пример #7
0
        private void SetupAppServiceArtifacts(DeploymentContext context)
        {
            var    tempArtifactDir = context.BuildTempPath;
            string framework       = System.Environment.GetEnvironmentVariable(OryxBuildConstants.OryxEnvVars.FrameworkSetting);

            if (framework.StartsWith("DOTNETCORE", StringComparison.OrdinalIgnoreCase))
            {
                tempArtifactDir = Path.Combine(context.BuildTempPath, "oryx-out");
            }
            string sitePackages    = "/home/data/SitePackages";
            string deploymentsPath = $"/home/site/deployments/";
            string artifactPath    = $"/home/site/deployments/{context.CommitId}/artifact";
            string packageNameFile = Path.Combine(sitePackages, "packagename.txt");
            string packagePathFile = Path.Combine(sitePackages, "packagepath.txt");

            FileSystemHelpers.EnsureDirectory(sitePackages);
            FileSystemHelpers.EnsureDirectory(artifactPath);

            string zipAppName = $"{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.zip";

            string createdZip = PackageArtifactFromFolder(context, tempArtifactDir,
                                                          tempArtifactDir, zipAppName, BuildArtifactType.Zip, numBuildArtifacts: -1);
            var copyExe    = ExternalCommandFactory.BuildExternalCommandExecutable(tempArtifactDir, artifactPath, context.Logger);
            var copyToPath = Path.Combine(artifactPath, zipAppName);

            try
            {
                copyExe.ExecuteWithProgressWriter(context.Logger, context.Tracer, $"cp {createdZip} {copyToPath}");
            }
            catch (Exception)
            {
                context.GlobalLogger.LogError();
                throw;
            }

            // Gotta remove the old zips
            DeploymentHelper.PurgeOldDeploymentsIfNecessary(deploymentsPath, context.Tracer, totalAllowedDeployments: 10);

            File.WriteAllText(packageNameFile, zipAppName);
            File.WriteAllText(packagePathFile, artifactPath);
        }
Пример #8
0
        /// <summary>
        /// Helper function to download package from given url, and place package (only 'content' folder from package) to given folder
        /// </summary>
        /// <param name="identity">Package identity</param>
        /// <param name="destinationFolder">Folder where we copy the package content (content folder only) to</param>
        /// <param name="pathToLocalCopyOfNupkg">File path where we copy the nudpk to</param>
        /// <returns></returns>
        public static async Task DownloadPackageToFolder(this SourceRepository srcRepo, PackageIdentity identity, string destinationFolder, string pathToLocalCopyOfNupkg)
        {
            var downloadResource = await srcRepo.GetResourceAndValidateAsync <DownloadResource>();

            using (Stream packageStream = await srcRepo.GetPackageStream(identity))
            {
                using (ZipFile zipFile = ZipFile.Read(packageStream))
                {
                    // we only care about stuff under "content" folder
                    int substringStartIndex = @"content/".Length;
                    IEnumerable <ZipEntry> contentEntries = zipFile.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase));
                    foreach (var entry in contentEntries)
                    {
                        string entryFileName = Uri.UnescapeDataString(entry.FileName);
                        string fullPath      = Path.Combine(destinationFolder, entryFileName.Substring(substringStartIndex));

                        if (entry.IsDirectory)
                        {
                            FileSystemHelpers.EnsureDirectory(fullPath.Replace('/', '\\'));
                            continue;
                        }

                        FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(fullPath));
                        using (Stream writeStream = FileSystemHelpers.OpenWrite(fullPath))
                        {
                            // reset length of file stream
                            writeStream.SetLength(0);

                            // let the thread go with itself, so that once file finishes writing, doesn't need to request thread context from main thread
                            await entry.OpenReader().CopyToAsync(writeStream).ConfigureAwait(false);
                        }
                    }
                }

                // set position back to the head of stream
                packageStream.Position = 0;

                // save a copy of the nupkg at last
                WriteStreamToFile(packageStream, pathToLocalCopyOfNupkg);
            }
        }
        public override async Task RunAsync()
        {
            if (!string.IsNullOrEmpty(FolderName))
            {
                var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName);
                FileSystemHelpers.EnsureDirectory(folderPath);
                Environment.CurrentDirectory = folderPath;
            }

            if (!Platforms.Contains(Platform))
            {
                ColoredConsole.Error.WriteLine(ErrorColor($"platform {Platform} is not supported. Valid options are: {String.Join(",", Platforms)}"));
                return;
            }

            var dockerFilePath = Path.Combine(Environment.CurrentDirectory, "Dockerfile");

            if (!FileSystemHelpers.FileExists(dockerFilePath))
            {
                ColoredConsole.Error.WriteLine(ErrorColor($"Dockerfile not found in directory {Environment.CurrentDirectory}"));
                return;
            }

            var image = $"{Registry}/{Name}-azurefunc";

            ColoredConsole.WriteLine("Building Docker image...");
            await DockerHelpers.DockerBuild(image, Environment.CurrentDirectory);

            ColoredConsole.WriteLine("Pushing function image to registry...");
            await DockerHelpers.DockerPush(image);

            var platform = PlatformFactory.CreatePlatform(Platform, ConfigPath);

            if (platform == null)
            {
                ColoredConsole.Error.WriteLine(ErrorColor($"Platform {Platform} is not supported"));
                return;
            }

            await platform.DeployContainerizedFunction(Name, image, MinInstances, MaxInstances);
        }
        private static async Task <string> RestorePythonRequirements(string functionAppRoot)
        {
            var packagesLocation = Path.Combine(functionAppRoot, Constants.ExternalPythonPackages);

            FileSystemHelpers.EnsureDirectory(packagesLocation);

            var requirementsTxt = Path.Combine(functionAppRoot, Constants.RequirementsTxt);

            var packApp = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "tools", "python", "packapp");

            var exe      = new Executable("python", $"{packApp} --platform linux --python-version 36 --packages-dir-name {Constants.ExternalPythonPackages} {functionAppRoot}");
            var sbErrors = new StringBuilder();
            var exitCode = await exe.RunAsync(o => ColoredConsole.WriteLine(o), e => sbErrors.AppendLine(e));

            if (exitCode != 0)
            {
                throw new CliException("There was an error restoring dependencies." + sbErrors.ToString());
            }

            return(packagesLocation);
        }
Пример #11
0
        public void SetPrivateKey(string key)
        {
            ITracer tracer = _traceFactory.GetTracer();

            using (tracer.Step("SSHKeyManager.SetPrivateKey"))
            {
                FileSystemHelpers.EnsureDirectory(_sshPath);

                // Delete existing public key
                if (FileSystemHelpers.FileExists(_id_rsaPub))
                {
                    FileSystemHelpers.DeleteFileSafe(_id_rsaPub);
                }

                // bypass service key checking prompt (StrictHostKeyChecking=no).
                FileSystemHelpers.WriteAllText(_config, ConfigContent);

                // This overrides if file exists
                FileSystemHelpers.WriteAllText(_id_rsa, key);
            }
        }
        public static async Task <string> EnsureExtensionsProjectExistsAsync(ISecretsManager secretsManager, bool csx, string extensionsDir = null)
        {
            if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.dotnet && !csx)
            {
                return(DotnetHelpers.GetCsprojOrFsproj());
            }

            if (String.IsNullOrEmpty(extensionsDir))
            {
                extensionsDir = Environment.CurrentDirectory;
            }

            var extensionsProj = Path.Combine(extensionsDir, Constants.ExtenstionsCsProjFile);

            if (!FileSystemHelpers.FileExists(extensionsProj))
            {
                FileSystemHelpers.EnsureDirectory(extensionsDir);
                await FileSystemHelpers.WriteAllTextToFileAsync(extensionsProj, await StaticResources.ExtensionsProject);
            }
            return(extensionsProj);
        }
        private static async Task <Stream> InternalPreparePythonDeploymentInDocker(IEnumerable <string> files, string functionAppRoot)
        {
            var appContentPath = CopyToTemp(files, functionAppRoot);

            await DockerHelpers.DockerPull(Constants.DockerImages.LinuxPythonImageAmd64);

            var containerId = string.Empty;

            try
            {
                containerId = await DockerHelpers.DockerRun(Constants.DockerImages.LinuxPythonImageAmd64);

                await DockerHelpers.ExecInContainer(containerId, "mkdir -p /home/site/wwwroot/");

                await DockerHelpers.CopyToContainer(containerId, $"{appContentPath}/.", "/home/site/wwwroot");

                var scriptFilePath = Path.GetTempFileName();
                await FileSystemHelpers.WriteAllTextToFileAsync(scriptFilePath, (await StaticResources.PythonDockerBuildScript).Replace("\r\n", "\n"));

                await DockerHelpers.CopyToContainer(containerId, scriptFilePath, Constants.StaticResourcesNames.PythonDockerBuild);

                await DockerHelpers.ExecInContainer(containerId, $"chmod +x /{Constants.StaticResourcesNames.PythonDockerBuild}");

                await DockerHelpers.ExecInContainer(containerId, $"/{Constants.StaticResourcesNames.PythonDockerBuild}");

                var tempDir = Path.Combine(Path.GetTempPath(), Path.GetTempFileName().Replace(".", ""));
                FileSystemHelpers.EnsureDirectory(tempDir);

                await DockerHelpers.CopyFromContainer(containerId, $"/app.zip", tempDir);

                return(FileSystemHelpers.OpenFile(Path.Combine(tempDir, "app.zip"), FileMode.Open));
            }
            finally
            {
                if (!string.IsNullOrEmpty(containerId))
                {
                    await DockerHelpers.KillContainer(containerId, ignoreError : true);
                }
            }
        }
Пример #14
0
        private static async Task <ProfileResultInfo> StopProfileInternalAsync(int processId, int profilingSessionId, bool ignoreProfileFile, ITracer tracer = null)
        {
            tracer = tracer ?? NullTracer.Instance;

            using (tracer.Step("ProfileManager.StopProfileInternalAsync"))
            {
                string profileFileFullPath = GetProfilePath(processId);
                string profileFileName     = Path.GetFileName(profileFileFullPath);
                string arguments           = string.Format("stop {0} /output:{1}", profilingSessionId, profileFileFullPath);

                var profileProcessResponse = await ExecuteProfilingCommandAsync(arguments, tracer);

                ProfileInfo removedId;
                if (profileProcessResponse.StatusCode != HttpStatusCode.OK)
                {
                    _profilingList.TryRemove(processId, out removedId);
                    return(profileProcessResponse);
                }

                FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(profileFileFullPath));
                tracer.Step("profile was saved to {0} successfully.", profileFileFullPath);

                _profilingList.TryRemove(processId, out removedId);

                if (ignoreProfileFile)
                {
                    try
                    {
                        FileSystemHelpers.DeleteFile(profileFileFullPath);
                    }
                    catch
                    {
                    }
                }

                DisposeTimerIfNecessary();

                return(new ProfileResultInfo(HttpStatusCode.OK, string.Empty));
            }
        }
        public override async Task RunAsync()
        {
            if (SourceControl != SourceControl.Git)
            {
                throw new Exception("Only Git is supported right now for vsc");
            }

            if (!string.IsNullOrEmpty(FolderName))
            {
                var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName);
                FileSystemHelpers.EnsureDirectory(folderPath);
                Environment.CurrentDirectory = folderPath;
            }

            await WriteFiles();
            await WriteLaunchJson();
            await SetupSourceControl();
            await WriteDockerfile();
            await WriteSample();

            PostInit();
        }
Пример #16
0
        public override async Task RunAsync()
        {
            if (SourceControl != SourceControl.Git)
            {
                throw new Exception("Only Git is supported right now for vsc");
            }

            if (!string.IsNullOrEmpty(FolderName))
            {
                var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName);
                FileSystemHelpers.EnsureDirectory(folderPath);
                Environment.CurrentDirectory = folderPath;
            }

            if (InitDockerOnly)
            {
                await InitDockerFileOnly();
            }
            else
            {
                await InitFunctionAppProject();
            }
        }
Пример #17
0
        public static async Task <string> EnsureExtensionsProjectExistsAsync(ISecretsManager secretsManager, bool csx, string extensionsDir = null)
        {
            var workerRuntime = WorkerRuntimeLanguageHelper.GetCurrentWorkerRuntimeLanguage(secretsManager);

            if (workerRuntime == WorkerRuntime.dotnet && !csx)
            {
                return(DotnetHelpers.GetCsproj());
            }

            if (String.IsNullOrEmpty(extensionsDir))
            {
                extensionsDir = Environment.CurrentDirectory;
            }

            var extensionsProj = Path.Combine(extensionsDir, "extensions.csproj");

            if (!FileSystemHelpers.FileExists(extensionsProj))
            {
                FileSystemHelpers.EnsureDirectory(extensionsDir);
                await FileSystemHelpers.WriteAllTextToFileAsync(extensionsProj, await StaticResources.ExtensionsProject);
            }
            return(extensionsProj);
        }
Пример #18
0
        private string ParseRequest(HttpContext context)
        {
            _filter = context.Request.QueryString[FilterQueryKey];

            // path route as in logstream/{*path} without query strings
            string routePath = context.Request.RequestContext.RouteData.Values["path"] as string;

            // trim '/'
            routePath = String.IsNullOrEmpty(routePath) ? routePath : routePath.Trim('/');

            // logstream at root
            if (String.IsNullOrEmpty(routePath))
            {
                _enableTrace = true;
                return(_logPath);
            }

            // in case of application or http log, we ensure directory
            string firstPath     = routePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries)[0];
            bool   isApplication = String.Equals(firstPath, "Application", StringComparison.OrdinalIgnoreCase);

            if (isApplication)
            {
                _enableTrace = true;
                FileSystemHelpers.EnsureDirectory(Path.Combine(_logPath, firstPath));
            }
            else
            {
                bool isHttp = String.Equals(firstPath, "http", StringComparison.OrdinalIgnoreCase);
                if (isHttp)
                {
                    FileSystemHelpers.EnsureDirectory(Path.Combine(_logPath, firstPath));
                }
            }

            return(Path.Combine(_logPath, routePath));
        }
Пример #19
0
        public HttpResponseMessage MiniDump(int id, int dumpType = 0)
        {
            using (_tracer.Step("ProcessController.MiniDump"))
            {
                string sitePolicy = _settings.GetWebSitePolicy();
                if ((MINIDUMP_TYPE)dumpType == MINIDUMP_TYPE.WithFullMemory && sitePolicy.Equals(FreeSitePolicy, StringComparison.OrdinalIgnoreCase))
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                                                       String.Format(CultureInfo.CurrentCulture, Resources.Error_FullMiniDumpNotSupported, sitePolicy)));
                }

                var process = GetProcessById(id);

                string dumpFile = Path.Combine(_environment.LogFilesPath, "minidump", "minidump.dmp");
                FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(dumpFile));
                FileSystemHelpers.DeleteFileSafe(_fileSystem, dumpFile);

                try
                {
                    _tracer.Trace("MiniDump pid={0}, name={1}, file={2}", process.Id, process.ProcessName, dumpFile);
                    process.MiniDump(dumpFile, (MINIDUMP_TYPE)dumpType);
                    _tracer.Trace("MiniDump size={0}", new FileInfo(dumpFile).Length);
                }
                catch (Exception ex)
                {
                    FileSystemHelpers.DeleteFileSafe(_fileSystem, dumpFile);
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message));
                }

                HttpResponseMessage response = Request.CreateResponse();
                response.Content = new StreamContent(MiniDumpStream.OpenRead(dumpFile, _fileSystem));
                response.Content.Headers.ContentType                 = new MediaTypeHeaderValue("application/octet-stream");
                response.Content.Headers.ContentDisposition          = new ContentDispositionHeaderValue("attachment");
                response.Content.Headers.ContentDisposition.FileName = String.Format("{0}-{1:MM-dd-H:mm:ss}.dmp", process.ProcessName, DateTime.UtcNow);
                return(response);
            }
        }
        public override async Task RunAsync()
        {
            if (SourceControl != SourceControl.Git)
            {
                throw new Exception("Only Git is supported right now for vsc");
            }

            if (!string.IsNullOrEmpty(FolderName))
            {
                var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName);
                FileSystemHelpers.EnsureDirectory(folderPath);
                Environment.CurrentDirectory = folderPath;
            }

            var language = string.Empty;

            if (string.IsNullOrEmpty(Language))
            {
                ColoredConsole.Write("Select a language: ");
                language = SelectionMenuHelper.DisplaySelectionWizard(availableLanguages.Keys);
                ColoredConsole.WriteLine(TitleColor(language));
            }
            else
            {
                language = Language;
            }

            language = NormalizeLanguage(language);
            await InitLanguageSpecificArtifacts(language);
            await WriteFiles();
            await WriteLocalSettingsJson(language);
            await WriteExtensionsJson();
            await SetupSourceControl();
            await WriteDockerfile(language);

            PostInit();
        }
Пример #21
0
        /// <summary>
        /// <para>Check if there is damanged leftover data</para>
        /// <para>If there is leftover data, will try to cleanup.</para>
        /// <para>If fail to cleanup, will move leftover data to Temp folder</para>
        /// </summary>
        private static void EnsureInstallationEnviroment(string installationDir, ITracer tracer)
        {
            // folder is there but nupkg is gone, means previous uninstallation must encounter some error
            bool isInstalledPackageBroken = FileSystemHelpers.DirectoryExists(installationDir) && FileSystemHelpers.GetFiles(installationDir, "*.nupkg").Length == 0;

            if (!isInstalledPackageBroken)
            {
                return;
            }

            using (tracer.Step("There was leftover data from previous uninstallation. Trying to cleanup now."))
            {
                try
                {
                    OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectorySafe(installationDir, ignoreErrors: false));
                    return;
                }
                catch (Exception ex)
                {
                    tracer.TraceError(ex);
                }

                FileSystemHelpers.EnsureDirectory(_toBeDeletedDirectoryPath);
                DirectoryInfo dirInfo  = new DirectoryInfo(installationDir);
                string        tmpFoder = Path.Combine(
                    _toBeDeletedDirectoryPath,
                    string.Format(CultureInfo.InvariantCulture, "{0}-{1}", dirInfo.Name, Guid.NewGuid().ToString("N").Substring(0, 8)));

                using (tracer.Step("Failed to cleanup. Moving leftover data to {0}", tmpFoder))
                {
                    // if failed, let exception bubble up to trigger bad request
                    OperationManager.Attempt(() => FileSystemHelpers.MoveDirectory(installationDir, tmpFoder));
                }
            }

            FileSystemHelpers.DeleteDirectoryContentsSafe(_toBeDeletedDirectoryPath);
        }
Пример #22
0
        private void SetupAppServiceArtifacts(DeploymentContext context)
        {
            string sitePackages    = "/home/data/SitePackages";
            string deploymentsPath = $"/home/site/deployments/";
            string artifactPath    = $"/home/site/deployments/{context.CommitId}/artifact";
            string packageNameFile = Path.Combine(sitePackages, "packagename.txt");
            string packagePathFile = Path.Combine(sitePackages, "packagepath.txt");

            FileSystemHelpers.EnsureDirectory(sitePackages);
            FileSystemHelpers.EnsureDirectory(artifactPath);

            string zipAppName = $"{DateTime.UtcNow.ToString("yyyyMMddHHmmss")}.zip";

            context.Logger.Log($"Repository path is {repositoryPath}");
            string createdZip = PackageArtifactFromFolder(context, repositoryPath,
                                                          repositoryPath, zipAppName, BuildArtifactType.Zip, numBuildArtifacts: -1);

            context.Logger.Log($"Copying the deployment artifact to {zipAppName} file");
            var copyExe    = ExternalCommandFactory.BuildExternalCommandExecutable(repositoryPath, artifactPath, context.Logger);
            var copyToPath = Path.Combine(artifactPath, zipAppName);

            try
            {
                copyExe.ExecuteWithProgressWriter(context.Logger, context.Tracer, $"cp {createdZip} {copyToPath}");
            }
            catch (Exception)
            {
                context.GlobalLogger.LogError();
                throw;
            }

            // Gotta remove the old zips
            DeploymentHelper.PurgeOldDeploymentsIfNecessary(deploymentsPath, context.Tracer, totalAllowedDeployments: 10);

            File.WriteAllText(packageNameFile, zipAppName);
            File.WriteAllText(packagePathFile, artifactPath);
        }
Пример #23
0
        public static async Task <string> EnsureExtensionsProjectExistsAsync()
        {
            var extensionsDir  = Path.Combine(Environment.CurrentDirectory, "functions-extensions");
            var extensionsProj = Path.Combine(extensionsDir, "extensions.csproj");

            if (!FileSystemHelpers.FileExists(extensionsProj))
            {
                FileSystemHelpers.EnsureDirectory(extensionsDir);
                var assembly           = typeof(ExtensionsHelper).Assembly;
                var extensionsProjText = string.Empty;
                using (Stream resource = assembly.GetManifestResourceStream(assembly.GetName().Name + ".ExtensionsProj.txt"))
                    using (var reader = new StreamReader(resource))
                    {
                        while (!reader.EndOfStream)
                        {
                            var line = await reader.ReadLineAsync();

                            extensionsProjText += $"{line}{Environment.NewLine}";
                        }
                    }
                await FileSystemHelpers.WriteAllTextToFileAsync(extensionsProj, extensionsProjText);
            }
            return(extensionsProj);
        }
Пример #24
0
        /// <summary>
        /// Builds and deploys a particular changeset. Puts all build artifacts in a deployments/{id}
        /// </summary>
        private async Task Build(
            ChangeSet changeSet,
            ITracer tracer,
            IDisposable deployStep,
            IRepository repository,
            DeploymentInfoBase deploymentInfo,
            DeploymentAnalytics deploymentAnalytics,
            bool fullBuildByDefault)
        {
            if (changeSet == null || String.IsNullOrEmpty(changeSet.Id))
            {
                throw new ArgumentException("The changeSet.Id parameter is null or empty", "changeSet.Id");
            }

            ILogger logger = null;
            IDeploymentStatusFile currentStatus = null;
            string buildTempPath = null;
            string id            = changeSet.Id;

            try
            {
                logger = GetLogger(id);
                ILogger innerLogger = logger.Log(Resources.Log_PreparingDeployment, TrimId(id));

                currentStatus            = _status.Open(id);
                currentStatus.Complete   = false;
                currentStatus.StartTime  = DateTime.UtcNow;
                currentStatus.Status     = DeployStatus.Building;
                currentStatus.StatusText = String.Format(CultureInfo.CurrentCulture, Resources.Status_BuildingAndDeploying, id);
                currentStatus.Save();

                ISiteBuilder builder = null;

                // Add in per-deploy default settings values based on the details of this deployment
                var perDeploymentDefaults = new Dictionary <string, string> {
                    { SettingsKeys.DoBuildDuringDeployment, fullBuildByDefault.ToString() }
                };
                var settingsProviders = _settings.SettingsProviders.Concat(
                    new[] { new BasicSettingsProvider(perDeploymentDefaults, SettingsProvidersPriority.PerDeploymentDefault) });

                var perDeploymentSettings = DeploymentSettingsManager.BuildPerDeploymentSettingsManager(repository.RepositoryPath, settingsProviders);

                string delayMaxInStr = perDeploymentSettings.GetValue(SettingsKeys.MaxRandomDelayInSec);
                if (!String.IsNullOrEmpty(delayMaxInStr))
                {
                    int maxDelay;
                    if (!Int32.TryParse(delayMaxInStr, out maxDelay) || maxDelay < 0)
                    {
                        tracer.Trace("Invalid {0} value, expect a positive integer, received {1}", SettingsKeys.MaxRandomDelayInSec, delayMaxInStr);
                    }
                    else
                    {
                        tracer.Trace("{0} is set to {1}s", SettingsKeys.MaxRandomDelayInSec, maxDelay);
                        int gap = _random.Next(maxDelay);
                        using (tracer.Step("Randomization applied to {0}, Start sleeping for {1}s", maxDelay, gap))
                        {
                            logger.Log(Resources.Log_DelayingBeforeDeployment, gap);
                            await Task.Delay(TimeSpan.FromSeconds(gap));
                        }
                    }
                }

                try
                {
                    using (tracer.Step("Determining deployment builder"))
                    {
                        builder = _builderFactory.CreateBuilder(tracer, innerLogger, perDeploymentSettings, repository, deploymentInfo);
                        deploymentAnalytics.ProjectType = builder.ProjectType;
                        tracer.Trace("Builder is {0}", builder.GetType().Name);
                    }
                }
                catch (Exception ex)
                {
                    // If we get a TargetInvocationException, use the inner exception instead to avoid
                    // useless 'Exception has been thrown by the target of an invocation' messages
                    var targetInvocationException = ex as System.Reflection.TargetInvocationException;
                    if (targetInvocationException != null)
                    {
                        ex = targetInvocationException.InnerException;
                    }

                    _globalLogger.Log(ex);

                    innerLogger.Log(ex);

                    MarkStatusComplete(currentStatus, success: false);

                    FailDeployment(tracer, deployStep, deploymentAnalytics, ex);

                    return;
                }

                // Create a directory for the script output temporary artifacts
                // Use tick count (in hex) instead of guid to keep the path for getting to long
                buildTempPath = Path.Combine(_environment.TempPath, DateTime.UtcNow.Ticks.ToString("x"));
                FileSystemHelpers.EnsureDirectory(buildTempPath);

                var context = new DeploymentContext
                {
                    NextManifestFilePath     = GetDeploymentManifestPath(id),
                    PreviousManifestFilePath = GetActiveDeploymentManifestPath(),
                    IgnoreManifest           = deploymentInfo != null && deploymentInfo.CleanupTargetDirectory,
                    // Ignoring the manifest will cause kudusync to delete sub-directories / files
                    // in the destination directory that are not present in the source directory,
                    // without checking the manifest to see if the file was copied over to the destination
                    // during a previous kudusync operation. This effectively performs a clean deployment
                    // from the source to the destination directory.
                    Tracer        = tracer,
                    Logger        = logger,
                    GlobalLogger  = _globalLogger,
                    OutputPath    = GetOutputPath(deploymentInfo, _environment, perDeploymentSettings),
                    BuildTempPath = buildTempPath,
                    CommitId      = id,
                    Message       = changeSet.Message
                };

                if (context.PreviousManifestFilePath == null)
                {
                    // this file (/site/firstDeploymentManifest) capture the last active deployment when disconnecting SCM
                    context.PreviousManifestFilePath = Path.Combine(_environment.SiteRootPath, Constants.FirstDeploymentManifestFileName);
                    if (!FileSystemHelpers.FileExists(context.PreviousManifestFilePath))
                    {
                        // In the first deployment we want the wwwroot directory to be cleaned, we do that using a manifest file
                        // That has the expected content of a clean deployment (only one file: hostingstart.html)
                        // This will result in KuduSync cleaning this file.
                        context.PreviousManifestFilePath = Path.Combine(_environment.ScriptPath, Constants.FirstDeploymentManifestFileName);
                    }
                }

                PreDeployment(tracer);

                using (tracer.Step("Building"))
                {
                    try
                    {
                        await builder.Build(context);

                        builder.PostBuild(context);
                        await RestartMainSiteIfNeeded(tracer, logger, deploymentInfo);

                        await PostDeploymentHelper.SyncFunctionsTriggers(_environment.RequestId, new PostDeploymentTraceListener(tracer, logger), deploymentInfo?.SyncFunctionsTriggersPath);

                        TouchWatchedFileIfNeeded(_settings, deploymentInfo, context);

                        FinishDeployment(id, deployStep);

                        deploymentAnalytics.VsProjectId = TryGetVsProjectId(context);
                        deploymentAnalytics.Result      = DeployStatus.Success.ToString();
                    }
                    catch (Exception ex)
                    {
                        MarkStatusComplete(currentStatus, success: false);

                        FailDeployment(tracer, deployStep, deploymentAnalytics, ex);

                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                FailDeployment(tracer, deployStep, deploymentAnalytics, ex);
            }
            finally
            {
                // Clean the temp folder up
                CleanBuild(tracer, buildTempPath);
            }
        }
Пример #25
0
        public void Initialize()
        {
            var tracer = _tracerFactory.GetTracer();

            using (tracer.Step("LibGit2SharpRepository Initialize"))
            {
                var dotGitPath = LibGit2Sharp.Repository.Init(RepositoryPath);
                using (var repo = new LibGit2Sharp.Repository(dotGitPath))
                {
                    repo.Config.Set("core.autocrlf", true);

                    // This speeds up git operations like 'git checkout', especially on slow drives like in Azure
                    repo.Config.Set("core.preloadindex", true);

                    repo.Config.Set("user.name", _settings.GetGitUsername());
                    repo.Config.Set("user.email", _settings.GetGitEmail());

                    // This is needed to make lfs work
                    repo.Config.Set("filter.lfs.clean", "git-lfs clean %f");
                    repo.Config.Set("filter.lfs.smudge", "git-lfs smudge %f");
                    repo.Config.Set("filter.lfs.required", true);

                    using (tracer.Step("Configure git server"))
                    {
                        // Allow getting pushes even though we're not bare
                        repo.Config.Set("receive.denyCurrentBranch", "ignore");
                    }

                    // to disallow browsing to this folder in case of in-place repo
                    using (tracer.Step("Create deny users for .git folder"))
                    {
                        string content = "<?xml version=\"1.0\"" + @"?>
<configuration>
  <system.web>
    <authorization>
      <deny users=" + "\"*\"" + @"/>
    </authorization>
  </system.web>
<configuration>";

                        File.WriteAllText(Path.Combine(dotGitPath, "web.config"), content);
                    }

                    // Server env does not support interactive cred prompt; hence, we intercept any credential provision
                    // for git fetch/clone with http/https scheme and return random invalid u/p forcing 'fatal: Authentication failed.'
                    using (tracer.Step("Configure git-credential"))
                    {
                        FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(GitCredentialHookPath));

                        string content = @"#!/bin/sh
if [ " + "\"$1\" = \"get\"" + @" ]; then
      echo username=dummyUser
      echo password=dummyPassword
fi" + "\n";

                        File.WriteAllText(GitCredentialHookPath, content);

                        repo.Config.Set("credential.helper", string.Format("!'{0}'", GitCredentialHookPath));
                    }
                }
                using (tracer.Step("Setup post receive hook"))
                {
                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(PostReceiveHookPath));

                    string content = @"#!/bin/sh
read i
echo $i > pushinfo
" + KnownEnvironment.KUDUCOMMAND + "\n";

                    File.WriteAllText(PostReceiveHookPath, content);
                }

                // NOTE: don't add any new init steps after creating the post receive hook,
                // as it's also used to mark that Init was fully executed
            }
        }
Пример #26
0
        public HttpResponseMessage MiniDump(int id, int dumpType = 0, string format = null)
        {
            using (_tracer.Step("ProcessController.MiniDump"))
            {
                DumpFormat dumpFormat = ParseDumpFormat(format, DumpFormat.Raw);
                if (dumpFormat != DumpFormat.Raw && dumpFormat != DumpFormat.Zip)
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.BadRequest,
                                                       String.Format(CultureInfo.CurrentCulture, Resources.Error_DumpFormatNotSupported, dumpFormat)));
                }

                string sitePolicy = _settings.GetWebSitePolicy();
                if ((MINIDUMP_TYPE)dumpType == MINIDUMP_TYPE.WithFullMemory && sitePolicy.Equals(FreeSitePolicy, StringComparison.OrdinalIgnoreCase))
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError,
                                                       String.Format(CultureInfo.CurrentCulture, Resources.Error_FullMiniDumpNotSupported, sitePolicy)));
                }

                var process = GetProcessById(id);

                string dumpFile = Path.Combine(_environment.LogFilesPath, "minidump", "minidump.dmp");
                FileSystemHelpers.EnsureDirectory(_fileSystem, Path.GetDirectoryName(dumpFile));
                FileSystemHelpers.DeleteFileSafe(_fileSystem, dumpFile);

                try
                {
                    using (_tracer.Step(String.Format("MiniDump pid={0}, name={1}, file={2}", process.Id, process.ProcessName, dumpFile)))
                    {
                        process.MiniDump(dumpFile, (MINIDUMP_TYPE)dumpType);
                        _tracer.Trace("MiniDump size={0}", new FileInfo(dumpFile).Length);
                    }
                }
                catch (Exception ex)
                {
                    _tracer.TraceError(ex);
                    FileSystemHelpers.DeleteFileSafe(_fileSystem, dumpFile);
                    return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message));
                }

                if (dumpFormat == DumpFormat.Raw)
                {
                    string responseFileName = GetResponseFileName(process.ProcessName, "dmp");

                    HttpResponseMessage response = Request.CreateResponse();
                    response.Content = new StreamContent(FileStreamWrapper.OpenRead(dumpFile, _fileSystem));
                    response.Content.Headers.ContentType                 = new MediaTypeHeaderValue("application/octet-stream");
                    response.Content.Headers.ContentDisposition          = new ContentDispositionHeaderValue("attachment");
                    response.Content.Headers.ContentDisposition.FileName = responseFileName;
                    return(response);
                }
                else if (dumpFormat == DumpFormat.Zip)
                {
                    string responseFileName = GetResponseFileName(process.ProcessName, "zip");

                    HttpResponseMessage response = Request.CreateResponse();
                    response.Content = ZipStreamContent.Create(responseFileName, _tracer, zip =>
                    {
                        try
                        {
                            zip.AddFile(dumpFile, String.Empty);
                        }
                        finally
                        {
                            FileSystemHelpers.DeleteFileSafe(_fileSystem, dumpFile);
                        }

                        foreach (var fileName in new[] { "sos.dll", "mscordacwks.dll" })
                        {
                            string filePath = Path.Combine(ProcessExtensions.ClrRuntimeDirectory, fileName);
                            if (_fileSystem.File.Exists(filePath))
                            {
                                zip.AddFile(filePath, String.Empty);
                            }
                        }
                    });
                    return(response);
                }
                else
                {
                    return(Request.CreateErrorResponse(HttpStatusCode.BadRequest,
                                                       String.Format(CultureInfo.CurrentCulture, Resources.Error_DumpFormatNotSupported, dumpFormat)));
                }
            }
        }
Пример #27
0
        public async Task <Site> CreateSiteAsync(string applicationName)
        {
            using (ServerManager iis = GetServerManager())
            {
                try
                {
                    var siteBindingCongfigs    = new List <IBindingConfiguration>();
                    var svcSiteBindingCongfigs = new List <IBindingConfiguration>();
                    if (_context.Configuration != null && _context.Configuration.Bindings != null)
                    {
                        siteBindingCongfigs    = _context.Configuration.Bindings.Where(b => b.SiteType == SiteType.Live).ToList();
                        svcSiteBindingCongfigs = _context.Configuration.Bindings.Where(b => b.SiteType == SiteType.Service).ToList();
                    }

                    // Determine the host header values
                    List <BindingInformation> siteBindings        = BuildDefaultBindings(applicationName, siteBindingCongfigs).ToList();
                    List <BindingInformation> serviceSiteBindings = BuildDefaultBindings(applicationName, svcSiteBindingCongfigs).ToList();

                    // Create the service site for this site
                    var serviceSite = CreateSiteAsync(iis, applicationName, GetServiceSite(applicationName), _context.Configuration.ServiceSitePath, serviceSiteBindings);

                    // Create the main site
                    string siteName = GetLiveSite(applicationName);
                    string root     = _context.Paths.GetApplicationPath(applicationName);
                    string siteRoot = _context.Paths.GetLiveSitePath(applicationName);
                    string webRoot  = Path.Combine(siteRoot, Constants.WebRoot);

                    FileSystemHelpers.EnsureDirectory(webRoot);
                    File.WriteAllText(Path.Combine(webRoot, HostingStartHtml), HostingStartHtmlContents);

                    var site = CreateSiteAsync(iis, applicationName, siteName, webRoot, siteBindings);

                    // Map a path called _app to the site root under the service site
                    MapServiceSitePath(iis, applicationName, Constants.MappedSite, root);

                    // Commit the changes to iis
                    iis.CommitChanges();

                    var serviceUrls = serviceSite.Bindings
                                      .Select(url => String.Format("{0}://{1}:{2}/", url.Protocol, String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, url.EndPoint.Port))
                                      .ToList();

                    // Wait for the site to start
                    await OperationManager.AttemptAsync(() => WaitForSiteAsync(serviceUrls.First()));

                    // Set initial ScmType state to LocalGit
                    var settings = new RemoteDeploymentSettingsManager(serviceUrls.First() + "api/settings");
                    await settings.SetValue(SettingsKeys.ScmType, ScmType.LocalGit);

                    var siteUrls = site.Bindings
                                   .Select(url => String.Format("{0}://{1}:{2}/", url.Protocol, String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, url.EndPoint.Port))
                                   .ToList();

                    return(new Site
                    {
                        ServiceUrls = serviceUrls,
                        SiteUrls = siteUrls
                    });
                }
                catch
                {
                    try
                    {
                        DeleteSiteAsync(applicationName).Wait();
                    }
                    catch
                    {
                        // Don't let it throw if we're unable to delete a failed creation.
                    }
                    throw;
                }
            }
        }
Пример #28
0
        public async Task ResetSiteContent(string applicationName)
        {
            const int MaxWaitSeconds = 300;

            using (ServerManager iis = GetServerManager())
            {
                var appPool = iis.ApplicationPools.FirstOrDefault(ap => ap.Name == applicationName);
                if (appPool == null)
                {
                    throw new InvalidOperationException($"Failed to recycle {applicationName} app pool.  It does not exist!");
                }

                // the app pool is running or starting, so stop it first.
                if (appPool.State == ObjectState.Started || appPool.State == ObjectState.Starting)
                {
                    // wait for the app to finish before trying to stop
                    for (int i = 0; i > MaxWaitSeconds && appPool.State == ObjectState.Starting; ++i)
                    {
                        await Task.Delay(1000);
                    }

                    // stop the app if it isn't already stopped
                    if (appPool.State != ObjectState.Stopped)
                    {
                        appPool.Stop();
                    }
                }

                // wait for the app to stop
                for (int i = 0; appPool.State != ObjectState.Stopped; ++i)
                {
                    await Task.Delay(1000);

                    if (i > MaxWaitSeconds)
                    {
                        throw new InvalidOperationException($"Failed to recycle {applicationName} app pool.  Its state '{appPool.State}' is not stopped!");
                    }
                }

                string root     = _context.Paths.GetApplicationPath(applicationName);
                string siteRoot = _context.Paths.GetLiveSitePath(applicationName);
                foreach (var dir in Directory.GetDirectories(root).Concat(new[] { Path.Combine(Path.GetTempPath(), applicationName) }))
                {
                    if (!Directory.Exists(dir))
                    {
                        continue;
                    }

                    // use rmdir command since it handles both hidden and read-only files
                    OperationManager.SafeExecute(() => Process.Start(new ProcessStartInfo
                    {
                        Arguments      = $"/C rmdir /s /q \"{dir}\"",
                        WindowStyle    = ProcessWindowStyle.Hidden,
                        CreateNoWindow = true,
                        FileName       = "cmd.exe"
                    })?.WaitForExit());

                    if (Directory.Exists(dir) && !dir.Contains(".deleted."))
                    {
                        var dirName = Path.GetFileName(dir);
                        OperationManager.Attempt(() => Process.Start(new ProcessStartInfo
                        {
                            Arguments      = $"/C ren \"{dir}\" \"{dirName}.deleted.{Guid.NewGuid():N}\"",
                            WindowStyle    = ProcessWindowStyle.Hidden,
                            CreateNoWindow = true,
                            FileName       = "cmd.exe"
                        })?.WaitForExit());
                    }
                }

                var webRoot = Path.Combine(siteRoot, Constants.WebRoot);
                FileSystemHelpers.EnsureDirectory(siteRoot);
                FileSystemHelpers.EnsureDirectory(webRoot);
                File.WriteAllText(Path.Combine(webRoot, HostingStartHtml), HostingStartHtmlContents);

                // start the app
                appPool.Start();

                // wait for the app to stop
                for (int i = 0; appPool.State != ObjectState.Started; ++i)
                {
                    await Task.Delay(1000);

                    if (i > MaxWaitSeconds)
                    {
                        throw new InvalidOperationException($"Failed to recycle {applicationName} app pool.  Its state '{appPool.State}' is not started!");
                    }
                }
            }
        }
Пример #29
0
        public void Initialize()
        {
            var tracer = _tracerFactory.GetTracer();

            using (tracer.Step("GitExeRepository.Initialize"))
            {
                Execute(tracer, "init");

                Execute(tracer, "config core.autocrlf {0}", OSDetector.IsOnWindows() ? "true" : "false");

                // This speeds up git operations like 'git checkout', especially on slow drives like in Azure
                Execute(tracer, "config core.preloadindex true");

                Execute(tracer, @"config user.name ""{0}""", _settings.GetGitUsername());
                Execute(tracer, @"config user.email ""{0}""", _settings.GetGitEmail());

                // This is needed to make lfs work
                Execute(tracer, @"config filter.lfs.clean ""git-lfs clean %f""");
                Execute(tracer, @"config filter.lfs.smudge ""git-lfs smudge %f""");
                Execute(tracer, @"config filter.lfs.required true");

                using (tracer.Step("Configure git server"))
                {
                    // Allow getting pushes even though we're not bare
                    Execute(tracer, "config receive.denyCurrentBranch ignore");
                }

                // to disallow browsing to this folder in case of in-place repo
                using (tracer.Step("Create deny users for .git folder"))
                {
                    string content = "<?xml version=\"1.0\"" + @"?>
<configuration>
  <system.web>
    <authorization>
      <deny users=" + "\"*\"" + @"/>
    </authorization>
  </system.web>
<configuration>";

                    File.WriteAllText(Path.Combine(_gitExe.WorkingDirectory, ".git", "web.config"), content);
                }

                // Server env does not support interactive cred prompt; hence, we intercept any credential provision
                // for git fetch/clone with http/https scheme and return random invalid u/p forcing 'fatal: Authentication failed.'
                using (tracer.Step("Configure git-credential"))
                {
                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(GitCredentialHookPath));

                    string content = @"#!/bin/sh
if [ " + "\"$1\" = \"get\"" + @" ]; then
      echo username=dummyUser
      echo password=dummyPassword
fi" + "\n";

                    File.WriteAllText(GitCredentialHookPath, content);

                    Execute(tracer, "config credential.helper \"!'{0}'\"", GitCredentialHookPath);
                }

                using (tracer.Step("Setup post receive hook"))
                {
                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(PostReceiveHookPath));

                    //#!/bin/sh
                    //read i
                    //echo $i > pushinfo
                    //KnownEnvironment.KUDUCOMMAND
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("#!/bin/sh");
                    sb.AppendLine("read i");
                    sb.AppendLine("echo $i > pushinfo");
                    sb.AppendLine(KnownEnvironment.KUDUCOMMAND);
                    if (OSDetector.IsOnWindows())
                    {
                        FileSystemHelpers.WriteAllText(PostReceiveHookPath, sb.ToString());
                    }
                    else
                    {
                        FileSystemHelpers.WriteAllText(PostReceiveHookPath, sb.ToString().Replace("\r\n", "\n"));
                        using (tracer.Step("Non-Windows enviroment, granting 755 permission to post-receive hook file"))
                        {
                            PermissionHelper.Chmod("755", PostReceiveHookPath, _environment, _settings, NullLogger.Instance);
                        }
                    }
                }

                // NOTE: don't add any new init steps after creating the post receive hook,
                // as it's also used to mark that Init was fully executed
            }
        }
Пример #30
0
        public static async Task UpdateLocalPackage(string siteExntentionsRootPath, string packageId, string packageVersion, string destinationFolder, string pathToLocalCopyOfNupkg, ITracer tracer)
        {
            tracer.Trace("Performing incremental package update for {0}", packageId);
            using (var client = new HttpClient())
            {
                var uri      = new Uri(String.Format("https://www.nuget.org/api/v2/package/{0}/{1}", packageId, packageVersion));
                var response = await client.GetAsync(uri);

                using (Stream newPackageStream = await response.Content.ReadAsStreamAsync())
                {
                    // update file
                    var localPackage = (await FeedExtensionsV2.SearchLocalRepo(siteExntentionsRootPath, packageId)).FirstOrDefault();
                    if (localPackage == null)
                    {
                        throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Package {0} not found from local repo.", packageId));
                    }

                    string nupkgFile = Directory.GetFiles(Path.Combine(siteExntentionsRootPath, packageId), "*.nupkg", SearchOption.TopDirectoryOnly).FirstOrDefault();

                    using (ZipFile oldPackageZip = ZipFile.Read(nupkgFile))
                        using (ZipFile newPackageZip = ZipFile.Read(newPackageStream))
                        {
                            // we only care about stuff under "content" folder
                            IEnumerable <ZipEntry>        oldContentEntries = oldPackageZip.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase));
                            IEnumerable <ZipEntry>        newContentEntries = newPackageZip.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase));
                            List <ZipEntry>               filesNeedToUpdate = new List <ZipEntry>();
                            Dictionary <string, ZipEntry> indexedOldFiles   = new Dictionary <string, ZipEntry>();
                            foreach (var item in oldContentEntries)
                            {
                                indexedOldFiles.Add(item.FileName.ToLowerInvariant(), item);
                            }

                            foreach (var newEntry in newContentEntries)
                            {
                                var fileName = newEntry.FileName.ToLowerInvariant();
                                if (indexedOldFiles.ContainsKey(fileName))
                                {
                                    // file name existed, only update if file has been touched
                                    ZipEntry oldEntry = indexedOldFiles[fileName];
                                    if (oldEntry.LastModified != newEntry.LastModified)
                                    {
                                        filesNeedToUpdate.Add(newEntry);
                                    }

                                    // remove from old index files buffer, the rest will be files that need to be deleted
                                    indexedOldFiles.Remove(fileName);
                                }
                                else
                                {
                                    // new files
                                    filesNeedToUpdate.Add(newEntry);
                                }
                            }

                            int substringStartIndex = @"content/".Length;

                            foreach (var entry in filesNeedToUpdate)
                            {
                                string entryFileName = Uri.UnescapeDataString(entry.FileName);
                                string fullPath      = Path.Combine(destinationFolder, entryFileName.Substring(substringStartIndex));

                                if (entry.IsDirectory)
                                {
                                    using (tracer.Step("Ensure directory: {0}", fullPath))
                                    {
                                        FileSystemHelpers.EnsureDirectory(fullPath.Replace('/', '\\'));
                                    }

                                    continue;
                                }

                                using (tracer.Step("Adding/Updating file: {0}", fullPath))
                                {
                                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(fullPath));
                                    using (Stream writeStream = FileSystemHelpers.OpenWrite(fullPath))
                                    {
                                        // reset length of file stream
                                        writeStream.SetLength(0);

                                        // let the thread go with itself, so that once file finishes writing, doesn't need to request thread context from main thread
                                        await entry.OpenReader().CopyToAsync(writeStream).ConfigureAwait(false);
                                    }
                                }
                            }

                            foreach (var entry in indexedOldFiles.Values)
                            {
                                string entryFileName = Uri.UnescapeDataString(entry.FileName);
                                string fullPath      = Path.Combine(destinationFolder, entryFileName.Substring(substringStartIndex));

                                if (entry.IsDirectory)
                                {
                                    // in case the two zip file was created from different tool. some tool will include folder as seperate entry, some don`t.
                                    // to be sure that folder is meant to be deleted, double check there is no files under it
                                    var entryNameInLower = entryFileName.ToLower();
                                    if (!string.Equals(destinationFolder, fullPath, StringComparison.OrdinalIgnoreCase) &&
                                        newContentEntries.FirstOrDefault(e => e.FileName.ToLowerInvariant().StartsWith(entryNameInLower)) == null)
                                    {
                                        using (tracer.Step("Deleting directory: {0}", fullPath))
                                        {
                                            FileSystemHelpers.DeleteDirectorySafe(fullPath);
                                        }
                                    }
                                    continue;
                                }

                                using (tracer.Step("Deleting file: {0}", fullPath))
                                {
                                    FileSystemHelpers.DeleteFileSafe(fullPath);
                                }
                            }
                        }

                    // update nupkg
                    newPackageStream.Position = 0;
                    using (tracer.Step("Updating nupkg file."))
                    {
                        WriteStreamToFile(newPackageStream, pathToLocalCopyOfNupkg);
                        if (!packageVersion.Equals(localPackage.Version))
                        {
                            using (tracer.Step("New package has difference version {0} from old package {1}. Remove old nupkg file.", packageVersion, localPackage.Version))
                            {
                                // if version is difference, nupkg file name will be difference. will need to clean up the old one.
                                var oldNupkg = pathToLocalCopyOfNupkg.Replace(
                                    string.Format(CultureInfo.InvariantCulture, "{0}.{1}.nupkg", packageId, packageVersion),
                                    string.Format(CultureInfo.InvariantCulture, "{0}.{1}.nupkg", localPackage.Id, localPackage.Version));

                                FileSystemHelpers.DeleteFileSafe(oldNupkg);
                            }
                        }
                    }
                }
            }
        }