public BuilderContext(string buildPath, string buildProfile, FileVersionTracker inputHashes, int maxParallelProcess, string slaveBuilderPath) { BuildPath = buildPath; BuildProfile = buildProfile; InputHashes = inputHashes; SlaveBuilderPath = slaveBuilderPath; MaxParallelProcesses = maxParallelProcess; }
/// <summary> /// Loads previous versions stored from the specified file path. /// </summary> /// <param name="filePath">The file path.</param> /// <returns>FileVersionTracker.</returns> public static FileVersionTracker Load(string filePath) { // Try to compact it before using it FileVersionStorage.Compact(filePath); bool isFirstPass = true; while (true) { FileStream fileStream = null; // Try to open the file, if we get an exception, this might be due only because someone is locking the file to // save it while we are trying to open it const int RetryOpenFileStream = 20; var random = new Random(); for (int i = 0; i < RetryOpenFileStream; i++) { try { fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); break; } catch (Exception) { if ((i + 1) == RetryOpenFileStream) { throw; } Thread.Sleep(50 + random.Next(100)); } } var tracker = new FileVersionTracker(fileStream); try { tracker.storage.LoadNewValues(); return(tracker); } catch (Exception) { // If an exception occurred, we are going to try to recover from it by reseting it. // reset file length to 0 fileStream.SetLength(0); tracker.Dispose(); if (!isFirstPass) { throw; } } isFirstPass = false; } }
/// <summary> /// Gets the default file version tracker for this machine. /// </summary> /// <returns>FileVersionTracker.</returns> public static FileVersionTracker GetDefault() { lock (lockDefaultTracker) { if (defaultFileVersionTracker == null) { var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), DefaultFileVersionTrackerFile); var directory = Path.GetDirectoryName(filePath); if (directory != null && !Directory.Exists(directory)) { Directory.CreateDirectory(directory); } // Loads the file version cache defaultFileVersionTracker = Load(filePath); } } return(defaultFileVersionTracker); }
/// <summary> /// Runs this instance. /// </summary> public BuildResultCode Run(Mode mode, bool writeIndexFile = true, bool enableMonitor = true) { // When we setup the database ourself we have to take responsibility to close it after var shouldCloseDatabase = ObjectDatabase == null; OpenObjectDatabase(buildPath, indexName); PreRun(); runMode = mode; if (IsRunning) { throw new InvalidOperationException("An instance of this Builder is already running."); } // reset build cache from previous build run var parameters = new BuildParameterCollection(); cancellationTokenSource = new CancellationTokenSource(); Cancelled = false; IsRunning = true; DisableCompressionIds.Clear(); // Reseting result map var inputHashes = FileVersionTracker.GetDefault(); { var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, MaxParallelProcesses, SlaveBuilderPath); resultMap = ObjectDatabase; scheduler = new Scheduler(); if (enableMonitor) { threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId)); foreach (var monitorPipeName in MonitorPipeNames) { threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId, monitorPipeName)); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Start(); } } // Schedule the build ScheduleBuildStep(builderContext, null, Root, InitialVariables); // Create threads var threads = Enumerable.Range(0, ThreadCount).Select(x => new Thread(SafeAction.Wrap(RunUntilEnd)) { IsBackground = true }).ToArray(); // Start threads int threadId = 0; foreach (var thread in threads) { thread.Name = (BuilderName ?? "Builder") + " worker thread " + (++threadId); thread.Start(); } // Wait for all threads to finish foreach (var thread in threads) { thread.Join(); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Finish(); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Join(); } } threadMonitors.Clear(); BuildResultCode result; if (runMode == Mode.Build) { if (cancellationTokenSource.IsCancellationRequested) { Logger.Error("Build cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Error("Build failed."); result = BuildResultCode.BuildError; } else { Logger.Info("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Info("Build is successful."); result = BuildResultCode.Successful; } } else { string modeName; switch (runMode) { case Mode.Clean: modeName = "Clean"; break; case Mode.CleanAndDelete: modeName = "Clean-and-delete"; break; default: throw new InvalidOperationException("Builder executed in unknown mode."); } if (cancellationTokenSource.IsCancellationRequested) { Logger.Error(modeName + " has been cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error(modeName + " has failed."); result = BuildResultCode.BuildError; } else { Logger.Error(modeName + " has been successfully completed."); result = BuildResultCode.Successful; } } scheduler = null; resultMap = null; IsRunning = false; if (shouldCloseDatabase) { CloseObjectDatabase(); } return(result); }
/// <summary> /// Runs this instance. /// </summary> public BuildResultCode Run(Mode mode, bool writeIndexFile = true, bool enableMonitor = true) { runMode = mode; if (IsRunning) { throw new InvalidOperationException("An instance of this Builder is already running."); } // reset build cache from previous build run var parameters = new BuildParameterCollection(); cancellationTokenSource = new CancellationTokenSource(); Cancelled = false; IsRunning = true; DisableCompressionIds.Clear(); // Reseting result map var inputHashes = FileVersionTracker.GetDefault(); { var builderContext = new BuilderContext(buildPath, buildProfile, inputHashes, parameters, MaxParallelProcesses, SlaveBuilderPath); if (!string.IsNullOrWhiteSpace(MetadataDatabaseDirectory)) { var metadataProvider = new QueryMetadataProvider(); if (metadataProvider.Open(Path.Combine(MetadataDatabaseDirectory, QueryMetadataProvider.DefaultDatabaseFilename), false)) { builderContext.MetadataProvider = metadataProvider; } } resultMap = IndexFileCommand.ObjectDatabase; scheduler = new Scheduler(); if (enableMonitor) { threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId)); foreach (var monitorPipeName in MonitorPipeNames) { threadMonitors.Add(new BuildThreadMonitor(scheduler, BuilderId, monitorPipeName)); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Start(); } } ScheduleBuildStep(builderContext, null, Root, InitialVariables); // Create threads var threads = Enumerable.Range(0, ThreadCount).Select(x => new Thread(SafeAction.Wrap(RunUntilEnd)) { IsBackground = true }).ToArray(); // Start threads int threadId = 0; foreach (var thread in threads) { thread.Name = "Builder thread " + (++threadId); thread.Start(); } // Wait for all threads to finish foreach (var thread in threads) { thread.Join(); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Finish(); } foreach (var threadMonitor in threadMonitors) { threadMonitor.Join(); } } threadMonitors.Clear(); BuildResultCode result; if (runMode == Mode.Build) { Logger.Info(""); if (cancellationTokenSource.IsCancellationRequested) { Logger.Error("Build cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Error("Build failed."); result = BuildResultCode.BuildError; } else { Logger.Info("Build finished in {0} steps. Command results: {1} succeeded, {2} up-to-date, {3} failed, {4} not triggered due to previous failure.", stepCounter.Total, stepCounter.Get(ResultStatus.Successful), stepCounter.Get(ResultStatus.NotTriggeredWasSuccessful), stepCounter.Get(ResultStatus.Failed), stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed)); Logger.Info("Build is successful."); result = BuildResultCode.Successful; } } else { // Clean input hashes file if (VirtualFileSystem.FileExists(InputHashesFileFullPath)) { try { VirtualFileSystem.FileDelete(InputHashesFileFullPath); } catch (IOException) { return(BuildResultCode.BuildError); } } string modeName; switch (runMode) { case Mode.Clean: modeName = "Clean"; break; case Mode.CleanAndDelete: modeName = "Clean-and-delete"; break; default: throw new InvalidOperationException("Builder executed in unknown mode."); } if (cancellationTokenSource.IsCancellationRequested) { Logger.Error(modeName + " has been cancelled."); result = BuildResultCode.Cancelled; } else if (stepCounter.Get(ResultStatus.Failed) > 0 || stepCounter.Get(ResultStatus.NotTriggeredPrerequisiteFailed) > 0) { Logger.Error(modeName + " has failed."); result = BuildResultCode.BuildError; } else { Logger.Error(modeName + " has been successfully completed."); result = BuildResultCode.Successful; } } scheduler = null; resultMap = null; IsRunning = false; return(result); }