internal async Task <ChangeSet> Sync(OneDriveInfo info, IRepository repository) { ChangeSet changeSet = null; string cursor = _settings.GetValue(CursorKey); ChangesResult changes = null; // We truncate cursor value in filename but keep it unharmed in the trace content using (_tracer.Step("Getting delta changes with cursor: {0}...", cursor.Truncate(5))) using (_tracer.Step("cursor: {0}", cursor)) { changes = await GetChanges(info.TargetChangeset.Id, info.AccessToken, info.RepositoryUrl, cursor); } if (changes == null || changes.Count == 0) { _tracer.Trace("No changes need to be applied."); LogMessage(Resources.OneDriveNoChangesFound); return(changeSet); } // for simplicity, use file changes as effective total _totals = changes.FileChanges.Count > 0 ? changes.FileChanges.Count : changes.Count; string hoststarthtml = Path.Combine(_environment.WebRootPath, Constants.HostingStartHtml); FileSystemHelpers.DeleteFileSafe(hoststarthtml); using (new Timer(UpdateStatusFile, state: info.TargetChangeset.Id, dueTime: TimeSpan.FromSeconds(5), period: TimeSpan.FromSeconds(5))) using (_tracer.Step("Applying {0} changes ...", _totals)) { LogMessage(Resources.OneDriveApplyingChanges, _totals); // perform action seperately, so that can ensure timestamp on directory // e.g two changes: // (new) file /a/b/c.txt // (new) dir /a/b // if created dir first then create file. file creation will trigger folder timestamp change. // which will result in "/a/b" has timestamp from the monent of file creation instead of the timestamp value from server, where value supposed to be set by code specifically. await ApplyChangesParallel(changes.DeletionChanges, info.AccessToken, maxParallelCount : 1, countSuccess : changes.FileChanges.Count == 0); await ApplyChangesParallel(changes.FileChanges, info.AccessToken, maxParallelCount : MaxConcurrentRequests, countSuccess : true); // apply folder changes at last to maintain same timestamp as in OneDrive await ApplyChangesParallel(changes.DirectoryChanges, info.AccessToken, maxParallelCount : 1, countSuccess : changes.FileChanges.Count == 0); _tracer.Trace("{0} succeeded, {1} failed", _successCount, _failedCount); LogMessage(Resources.OneDriveApplyResult, _successCount, _failedCount); string message = _failedCount > 0 ? string.Format(CultureInfo.CurrentCulture, Resources.OneDrive_SynchronizedWithFailure, _successCount, _totals, _failedCount) : string.Format(CultureInfo.CurrentCulture, Resources.OneDrive_Synchronized, _totals); // Commit anyway even partial change if (repository.Commit(message, info.AuthorName, info.AuthorEmail)) { changeSet = repository.GetChangeSet("HEAD"); } if (_failedCount > 0) { // signal deployment failied throw new Exception(string.Format(CultureInfo.CurrentCulture, Resources.OneDriveApplyResult, _successCount, _failedCount)); } } // finally keep a copy of the new cursor _settings.SetValue(CursorKey, changes.Cursor); return(changeSet); }
public async Task DeployAsync(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate = true) { using (var deploymentAnalytics = new DeploymentAnalytics(_analytics, _settings)) { Exception exception = null; ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; ILogger innerLogger = null; string targetBranch = null; // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it if (changeSet == null) { targetBranch = _settings.GetBranch(); changeSet = repository.GetChangeSet(targetBranch); if (changeSet == null) { throw new InvalidOperationException(String.Format("The current deployment branch is '{0}', but nothing has been pushed to it", targetBranch)); } } string id = changeSet.Id; IDeploymentStatusFile statusFile = null; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer); statusFile.MarkPending(); ILogger logger = GetLogger(changeSet.Id); if (needFileUpdate) { using (tracer.Step("Updating to specific changeset")) { innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id); using (var writer = new ProgressWriter()) { // Update to the specific changeset or branch repository.Update(targetBranch ?? id); } } } if (_settings.ShouldUpdateSubmodules()) { using (tracer.Step("Updating submodules")) { innerLogger = logger.Log(Resources.Log_UpdatingSubmodules); repository.UpdateSubmodules(); } } if (clean) { tracer.Trace("Cleaning {0} repository", repository.RepositoryType); innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType); repository.Clean(); } // set to null as Build() below takes over logging innerLogger = null; // Perform the build deployment of this changeset await Build(changeSet, tracer, deployStep, repository, deploymentAnalytics); } catch (Exception ex) { exception = ex; if (innerLogger != null) { innerLogger.Log(ex); } if (statusFile != null) { MarkStatusComplete(statusFile, success: false); } tracer.TraceError(ex); deploymentAnalytics.Error = ex.ToString(); if (deployStep != null) { deployStep.Dispose(); } } // Reload status file with latest updates statusFile = _status.Open(id); if (statusFile != null) { await _hooksManager.PublishEventAsync(HookEventTypes.PostDeployment, statusFile); } if (exception != null) { throw new DeploymentFailedException(exception); } } }
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 siteSku = _settings.GetWebSiteSku(); if ((MINIDUMP_TYPE)dumpType == MINIDUMP_TYPE.WithFullMemory && siteSku.Equals(Constants.FreeSKU, StringComparison.OrdinalIgnoreCase)) { return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, String.Format(CultureInfo.CurrentCulture, Resources.Error_FullMiniDumpNotSupported, siteSku))); } var process = GetProcessById(id); string dumpFile = Path.Combine(_environment.LogFilesPath, "minidump", "minidump.dmp"); FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(dumpFile)); FileSystemHelpers.DeleteFileSafe(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(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)); 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, _tracer, String.Empty); } finally { FileSystemHelpers.DeleteFileSafe(dumpFile); } foreach (var fileName in new[] { "sos.dll", "mscordacwks.dll" }) { string filePath = Path.Combine(ProcessExtensions.ClrRuntimeDirectory, fileName); if (FileSystemHelpers.FileExists(filePath)) { zip.AddFile(filePath, _tracer, String.Empty); } } }); return(response); } else { return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, String.Format(CultureInfo.CurrentCulture, Resources.Error_DumpFormatNotSupported, dumpFormat))); } } }
public void Delete(int deleteWebRoot = 0, int ignoreErrors = 0) { // Fail if a deployment is in progress bool acquired = _deploymentLock.TryLockOperation(() => { using (_tracer.Step("Deleting repository")) { string repositoryPath = Path.Combine(_environment.SiteRootPath, Constants.RepositoryPath); if (String.Equals(repositoryPath, _environment.RepositoryPath, StringComparison.OrdinalIgnoreCase)) { // Delete the repository FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath, ignoreErrors != 0); } else { // Just delete .git folder FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".git"), ignoreErrors != 0); FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".hg"), ignoreErrors != 0); } } using (_tracer.Step("Deleting ssh key")) { // Delete the ssh key FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath, ignoreErrors != 0); } if (deleteWebRoot != 0) { using (_tracer.Step("Deleting web root")) { // Delete the wwwroot folder FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath, ignoreErrors != 0); } using (_tracer.Step("Deleting diagnostics")) { // Delete the diagnostic log. This is a slight abuse of deleteWebRoot, but the // real semantic is more to reset the site to a fully clean state FileSystemHelpers.DeleteDirectorySafe(_environment.DiagnosticsPath, ignoreErrors != 0); } // Delete first deployment manifest since it is no longer needed FileSystemHelpers.DeleteFileSafe(Path.Combine(_environment.SiteRootPath, Constants.FirstDeploymentManifestFileName)); } else { using (_tracer.Step("Updating initial deployment manifest")) { // The active deployment manifest becomes the baseline initial deployment manifest // When SCM is reconnected, the new deployment will use this manifest to clean the wwwroot SaveInitialDeploymentManifest(); } } using (_tracer.Step("Deleting deployment cache")) { // Delete the deployment cache FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentsPath, ignoreErrors != 0); } }, TimeSpan.Zero); if (!acquired) { HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.Conflict, Resources.Error_DeploymentInProgess); throw new HttpResponseException(response); } }
private void WriteEndTrace() { bool isOutgoingResponse = false; bool zeroInfos = false; try { var info = _infos.Pop(); var elapsed = DateTime.UtcNow - info.StartTime; var strb = new StringBuilder(); if (_isStartElement) { strb.Append("/>"); } else { strb.Append(new String(' ', _infos.Count * 2)); strb.Append("</step>"); } strb.AppendLine(String.Format("<!-- duration: {0:0}ms -->", elapsed.TotalMilliseconds)); FileSystemHelpers.AppendAllTextToFile(_file, strb.ToString()); log.Debug(Regex.Replace(strb.ToString(), @"\t|\n|\r", "")); _isStartElement = false; // adjust filename with statusCode if (info.Title == XmlTracer.OutgoingResponseTrace && _file.EndsWith(PendingXml, StringComparison.OrdinalIgnoreCase)) { if (!Int32.TryParse(info.Attributes["statusCode"], out _statusCode)) { _statusCode = 0; } isOutgoingResponse = true; } if (_infos.Count == 0) { // avoid spamming the traces if (!ShouldTrace(_level, info, _statusCode)) { FileSystemHelpers.DeleteFileSafe(_file); } else { var file = _file; if (_file.EndsWith(PendingXml, StringComparison.OrdinalIgnoreCase)) { file = file.Replace(PendingXml, _statusCode <= 0 ? ".xml" : String.Format("_{0}.xml", _statusCode)); } file = file.Replace(".xml", String.Format("_{0:0}s.xml", elapsed.TotalSeconds)); FileSystemHelpers.MoveFile(_file, file); } _file = null; zeroInfos = true; } } catch (Exception ex) { WriteUnexpectedException(ex); } finally { if (isOutgoingResponse && zeroInfos) { startTagAdded = false; log.Debug("@@@EndTrace@@@\n\n\n"); } } }
private void EnsureMaxXmlFiles() { // _lastCleanup ensures we only check (iterate) the log directory every certain period. // _cleanupPending ensures there is one cleanup thread at a time. lock (_cleanupLock) { if (_cleanupPending) { return; } var now = DateTime.UtcNow; if (_lastCleanup.AddSeconds(CleanUpIntervalSecs) > now) { return; } _lastCleanup = now; _cleanupPending = true; } try { ITracer tracer = this; using (tracer.Step("Cleanup Xml Logs")) { try { var files = FileSystemHelpers.GetFiles(_path, "*.xml"); if (files.Length < MaxXmlFiles) { return; } var toCleanup = files.Length - (MaxXmlFiles * 80) / 100; var attribs = new Dictionary <string, string> { { "totalFiles", files.Length.ToString() }, { "totalCleanup", toCleanup.ToString() } }; using (tracer.Step("Cleanup Infos", attribs)) { foreach (var file in files.OrderBy(n => n).Take(toCleanup)) { if (file.IndexOf("default", StringComparison.OrdinalIgnoreCase) >= 0) { FileSystemHelpers.DeleteFileSafe(file); } } } } catch (Exception ex) { tracer.TraceError(ex); } } } finally { _cleanupPending = false; } }
public static async Task UpdateLocalPackage(this SourceRepository srcRepo, SourceRepository localRepo, PackageIdentity identity, string destinationFolder, string pathToLocalCopyOfNupkg, ITracer tracer) { tracer.Trace("Performing incremental package update for {0}", identity.Id); using (Stream newPackageStream = await srcRepo.GetPackageStream(identity)) { // update file var localPackage = await localRepo.GetLatestPackageByIdFromSrcRepo(identity.Id); if (localPackage == null) { throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Package {0} not found from local repo.", identity.Id)); } using (Stream oldPackageStream = await localRepo.GetPackageStream(localPackage.Identity)) using (ZipFile oldPackageZip = ZipFile.Read(oldPackageStream)) 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 fullPath = Path.Combine(destinationFolder, entry.FileName.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 fullPath = Path.Combine(destinationFolder, entry.FileName.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 foder is meant to be deleted, double check there is no files under it var entryNameInLower = entry.FileName.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 (!identity.Version.Equals(localPackage.Identity.Version)) { using (tracer.Step("New package has difference version {0} from old package {1}. Remove old nupkg file.", identity.Version, localPackage.Identity.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", identity.Id, identity.Version.ToNormalizedString()), string.Format(CultureInfo.InvariantCulture, "{0}.{1}.nupkg", localPackage.Identity.Id, localPackage.Identity.Version.ToNormalizedString())); FileSystemHelpers.DeleteFileSafe(oldNupkg); } } } } }
private void DeleteFunctionArtifacts(string name) { FileSystemHelpers.DeleteFileSafe(GetFunctionTestDataFilePath(name)); FileSystemHelpers.DeleteFileSafe(GetFunctionSecretsFilePath(name)); FileSystemHelpers.DeleteFileSafe(GetFunctionLogPath(name)); }
public void Deploy(string id, string deployer, bool clean) { ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Check to see if we have a deployment with this id already string trackingFilePath = GetStatusFilePath(id, ensureDirectory: false); if (!_fileSystem.File.Exists(trackingFilePath)) { // If we don't then throw throw new FileNotFoundException(String.Format(CultureInfo.CurrentCulture, Resources.Error_DeployNotFound, id)); } // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); ILogger logger = GetLogger(id); using (tracer.Step("Updating to specific changeset")) { // Update to the the specific changeset _serverRepository.Update(id); } if (clean) { tracer.Trace("Cleaning git repository"); logger.Log(Resources.Log_CleaningGitRepository); _serverRepository.Clean(); } if (!String.IsNullOrEmpty(deployer)) { // Update the deployer DeploymentStatusFile statusFile = OpenStatusFile(id); statusFile.Deployer = deployer; statusFile.Save(_fileSystem); } // Perform the build deployment of this changeset Build(id, tracer, deployStep); } catch (Exception ex) { tracer.TraceError(ex); if (deployStep != null) { deployStep.Dispose(); } throw; } }
public void Delete(int deleteWebRoot = 0, int ignoreErrors = 0) { try { // Fail if a deployment is in progress _deploymentLock.LockOperation(() => { using (_tracer.Step("Deleting repository")) { string repositoryPath = Path.Combine(_environment.SiteRootPath, Constants.RepositoryPath); if (String.Equals(repositoryPath, _environment.RepositoryPath, StringComparison.OrdinalIgnoreCase)) { // Delete the repository FileSystemHelpers.DeleteDirectorySafe(_environment.RepositoryPath, ignoreErrors != 0); } else { // Just delete .git folder FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".git"), ignoreErrors != 0); FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.RepositoryPath, ".hg"), ignoreErrors != 0); } } using (_tracer.Step("Delete auto swap lock file")) { FileSystemHelpers.DeleteFileSafe(Path.Combine(_environment.LocksPath, PostDeploymentHelper.AutoSwapLockFile)); } using (_tracer.Step("Deleting ssh key")) { // Delete the ssh key FileSystemHelpers.DeleteDirectorySafe(_environment.SSHKeyPath, ignoreErrors != 0); } if (deleteWebRoot != 0) { // This logic is primarily used to help with site reuse during test. // The flag is not documented for general use. using (_tracer.Step("Deleting web root")) { // Delete the wwwroot folder FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath, ignoreErrors != 0); } using (_tracer.Step("Deleting diagnostics")) { // Delete the diagnostic log. This is a slight abuse of deleteWebRoot, but the // real semantic is more to reset the site to a fully clean state FileSystemHelpers.DeleteDirectorySafe(_environment.DiagnosticsPath, ignoreErrors != 0); } using (_tracer.Step("Deleting ASP.NET 5 approot")) { // Delete the approot folder used by ASP.NET 5 apps FileSystemHelpers.DeleteDirectorySafe(Path.Combine(_environment.SiteRootPath, "approot"), ignoreErrors != 0); } // Delete first deployment manifest since it is no longer needed FileSystemHelpers.DeleteFileSafe(Path.Combine(_environment.SiteRootPath, Constants.FirstDeploymentManifestFileName)); } else { using (_tracer.Step("Updating initial deployment manifest")) { // The active deployment manifest becomes the baseline initial deployment manifest // When SCM is reconnected, the new deployment will use this manifest to clean the wwwroot SaveInitialDeploymentManifest(); } } using (_tracer.Step("Deleting deployment cache")) { // Delete the deployment cache FileSystemHelpers.DeleteDirectorySafe(_environment.DeploymentsPath, ignoreErrors != 0); } }, "Deleting repository", TimeSpan.Zero); } catch (LockOperationException ex) { HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.Conflict, ex.Message); throw new HttpResponseException(response); } }
internal async Task <ChangeSet> Sync(DropboxInfo dropboxInfo, string branch, IRepository repository, ITracer tracer) { DropboxDeployInfo deployInfo = dropboxInfo.DeployInfo; // use incoming tracer since it is background work _tracer = tracer; ResetStats(); // for Dropbox OAuth V2, the delta is collected and applied by SCM // simply set OldCursoras current. if (dropboxInfo.OAuthVersion == 2) { deployInfo.OldCursor = _settings.GetValue(CursorKey); } else if (_settings.GetValue(CursorKey) != deployInfo.OldCursor) { throw new InvalidOperationException(Resources.Error_MismatchDropboxCursor); } // initial sync, remove default content // for simplicity, we do it blindly whether or not in-place // given the end result is the same if (String.IsNullOrEmpty(deployInfo.OldCursor) && DeploymentHelper.IsDefaultWebRootContent(_environment.WebRootPath)) { string hoststarthtml = Path.Combine(_environment.WebRootPath, Constants.HostingStartHtml); FileSystemHelpers.DeleteFileSafe(hoststarthtml); } if (!repository.IsEmpty()) { // git checkout --force <branch> repository.Update(branch); } ChangeSet changeSet = null; string message = null; try { using (_tracer.Step("Sync with Dropbox")) { if (dropboxInfo.OAuthVersion == 2) { // Fetch the deltas await UpdateDropboxDeployInfo(deployInfo); } // Sync dropbox => repository directory await ApplyChanges(dropboxInfo, useOAuth20 : dropboxInfo.OAuthVersion == 2); } message = String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_Synchronized, deployInfo.Deltas.Count); } catch (Exception) { message = String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_SynchronizedWithFailure, _successCount, deployInfo.Deltas.Count, _failedCount); throw; } finally { Logger.Log(message); Logger.Log(String.Format("{0} downloaded files, {1} successful retries.", _fileCount, _retriedCount)); IDeploymentStatusFile statusFile = _status.Open(dropboxInfo.TargetChangeset.Id); statusFile.UpdateMessage(message); statusFile.UpdateProgress(String.Format(CultureInfo.CurrentCulture, Resources.Dropbox_Committing, _successCount)); // Commit anyway even partial change if (repository.Commit(message, deployInfo.UserName, deployInfo.Email ?? deployInfo.UserName)) { changeSet = repository.GetChangeSet("HEAD"); } } // Save new dropboc cursor LogInfo("Update dropbox cursor"); _settings.SetValue(CursorKey, deployInfo.NewCursor); return(changeSet); }
public async Task Deploy(IRepository repository, ChangeSet changeSet, string deployer, bool clean, bool needFileUpdate) { ITracer tracer = _traceFactory.GetTracer(); IDisposable deployStep = null; ILogger innerLogger = null; string targetBranch = null; // If we don't get a changeset, find out what branch we should be deploying and get the commit ID from it if (changeSet == null) { targetBranch = _settings.GetBranch(); changeSet = repository.GetChangeSet(targetBranch); } string id = changeSet.Id; IDeploymentStatusFile statusFile = null; try { deployStep = tracer.Step("DeploymentManager.Deploy(id)"); // Remove the old log file for this deployment id string logPath = GetLogPath(id); FileSystemHelpers.DeleteFileSafe(logPath); statusFile = GetOrCreateStatusFile(changeSet, tracer, deployer); statusFile.MarkPending(); ILogger logger = GetLogger(changeSet.Id); repository.ClearLock(); if (needFileUpdate) { using (tracer.Step("Updating to specific changeset")) { innerLogger = logger.Log(Resources.Log_UpdatingBranch, targetBranch ?? id); using (var writer = new ProgressWriter()) { // Update to the the specific changeset repository.Update(id); } } } using (tracer.Step("Updating submodules")) { innerLogger = logger.Log(Resources.Log_UpdatingSubmodules); repository.UpdateSubmodules(); } if (clean) { tracer.Trace("Cleaning {0} repository", repository.RepositoryType); innerLogger = logger.Log(Resources.Log_CleaningRepository, repository.RepositoryType); repository.Clean(); } // set to null as Build() below takes over logging innerLogger = null; // Perform the build deployment of this changeset await Build(id, tracer, deployStep, repository); } catch (Exception ex) { if (innerLogger != null) { innerLogger.Log(ex); } if (statusFile != null) { statusFile.MarkFailed(); } tracer.TraceError(ex); if (deployStep != null) { deployStep.Dispose(); } throw; } }
private async Task <IActionResult> PushDeployAsync(ArtifactDeploymentInfo deploymentInfo, bool isAsync, HttpContext context) { string artifactTempPath; if (string.IsNullOrWhiteSpace(deploymentInfo.TargetFileName)) { artifactTempPath = Path.Combine(_environment.ZipTempPath, Guid.NewGuid() + ".zip"); } else { artifactTempPath = Path.Combine(_environment.ZipTempPath, deploymentInfo.TargetFileName); } if (_settings.RunFromLocalZip()) { await WriteSitePackageZip(deploymentInfo, _tracer); } else { var oryxManifestFile = Path.Combine(_environment.WebRootPath, "oryx-manifest.toml"); if (FileSystemHelpers.FileExists(oryxManifestFile)) { _tracer.Step("Removing previous build artifact's manifest file"); FileSystemHelpers.DeleteFileSafe(oryxManifestFile); } try { var nodeModulesSymlinkFile = Path.Combine(_environment.WebRootPath, "node_modules"); Mono.Unix.UnixSymbolicLinkInfo i = new Mono.Unix.UnixSymbolicLinkInfo(nodeModulesSymlinkFile); if (i.FileType == Mono.Unix.FileTypes.SymbolicLink) { _tracer.Step("Removing node_modules symlink"); // TODO: Add support to remove Unix Symlink File in DeleteFileSafe // FileSystemHelpers.DeleteFileSafe(nodeModulesSymlinkFile); FileSystemHelpers.RemoveUnixSymlink(nodeModulesSymlinkFile, TimeSpan.FromSeconds(5)); } } catch (Exception) { // best effort } using (_tracer.Step("Writing artifact to {0}", artifactTempPath)) { if (!string.IsNullOrEmpty(context.Request.ContentType) && context.Request.ContentType.Contains("multipart/form-data", StringComparison.OrdinalIgnoreCase)) { FormValueProvider formModel; using (_tracer.Step("Writing zip file to {0}", artifactTempPath)) { using (var file = System.IO.File.Create(artifactTempPath)) { formModel = await Request.StreamFile(file); } } } else if (deploymentInfo.RemoteURL != null) { using (_tracer.Step("Writing zip file from packageUri to {0}", artifactTempPath)) { using (var httpClient = new HttpClient()) using (var fileStream = new FileStream(artifactTempPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true)) { var zipUrlRequest = new HttpRequestMessage(HttpMethod.Get, deploymentInfo.RemoteURL); var zipUrlResponse = await httpClient.SendAsync(zipUrlRequest); try { zipUrlResponse.EnsureSuccessStatusCode(); } catch (HttpRequestException hre) { _tracer.TraceError(hre, "Failed to get file from packageUri {0}", deploymentInfo.RemoteURL); throw; } using (var content = await zipUrlResponse.Content.ReadAsStreamAsync()) { await content.CopyToAsync(fileStream); } } } } else { using (var file = System.IO.File.Create(artifactTempPath)) { await Request.Body.CopyToAsync(file); } } deploymentInfo.RepositoryUrl = artifactTempPath; } } var result = await _deploymentManager.FetchDeploy(deploymentInfo, isAsync, UriHelper.GetRequestUri(Request), "HEAD"); switch (result) { case FetchDeploymentRequestResult.RunningAynschronously: if (isAsync) { // latest deployment keyword reserved to poll till deployment done Response.GetTypedHeaders().Location = new Uri(UriHelper.GetRequestUri(Request), String.Format("/api/deployments/{0}?deployer={1}&time={2}", Constants.LatestDeployment, deploymentInfo.Deployer, DateTime.UtcNow.ToString("yyy-MM-dd_HH-mm-ssZ"))); } return(Accepted()); case FetchDeploymentRequestResult.ForbiddenScmDisabled: // Should never hit this for zip push deploy _tracer.Trace("Scm is not enabled, reject all requests."); return(Forbid()); case FetchDeploymentRequestResult.ConflictAutoSwapOngoing: return(StatusCode(StatusCodes.Status409Conflict, Resources.Error_AutoSwapDeploymentOngoing)); case FetchDeploymentRequestResult.Pending: // Shouldn't happen here, as we disallow deferral for this use case return(Accepted()); case FetchDeploymentRequestResult.RanSynchronously: return(Ok()); case FetchDeploymentRequestResult.ConflictDeploymentInProgress: return(StatusCode(StatusCodes.Status409Conflict, Resources.Error_DeploymentInProgress)); case FetchDeploymentRequestResult.ConflictRunFromRemoteZipConfigured: return(StatusCode(StatusCodes.Status409Conflict, Resources.Error_RunFromRemoteZipConfigured)); default: return(BadRequest()); } }