// TODO TransactionScope? /// <summary> /// Processes a single Ableton project folder by syncing its metadata /// to our data store. If the state is considered invalid, this is /// marked both in our data store and in our tracking file. /// </summary> /// <remarks> /// This does nothing with project tasks. /// /// If the given <paramref name="directoryInfo"/> is not an Ableton /// project directory, this will throw an exception of type /// <see cref="NotAnAbletonProjectFolderException"/>. /// /// Note: This service does not consider the possibility of a project /// existing in the data store without it having a tracking file. /// </remarks> /// <param name="directoryInfo">The directory to process.</param> /// <param name="token">The cancellation token.</param> /// <returns>See <see cref="Task"/>.</returns> public async Task ProcessAbletonProjectFolderAsync(DirectoryInfo directoryInfo, CancellationToken token) { if (directoryInfo == null) { throw new ArgumentNullException(nameof(directoryInfo)); } if (token == null) { throw new ArgumentNullException(nameof(token)); } try { if (!ProjectFolderHelper.IsAbletonProjectFolder(directoryInfo)) { throw new NotAnAbletonProjectFolderException(); } if (_trackingFileService.HasTrackingFile(directoryInfo)) { // If marked invalid, this service will log and skip. var trackingFile = _trackingFileService.GetTrackingFile(directoryInfo); if (trackingFile.TrackingFileStatus == TrackingFileStatus.InvalidLocal) { _logger.LogWarning($"Project with id {trackingFile.ProjectId} marked as invalid, skipping"); return; } if (!await _projectRepository.ExistsAsync(trackingFile.ProjectId, token)) { // If the project has a tracking file but does not exist in the store, // we have reached an invalid state. This should never happen. _trackingFileService.MarkTrackingFileInvalidLocal(directoryInfo); _logger.LogWarning($"Project with id {trackingFile.ProjectId} has a tracking file" + $"but does not exist in the store - marked as invalid."); return; } else { // The state where there exists a tracking file and where the project // exists in the data store is valid. We can continue to process. // TODO Transaction? var project = await _projectRepository.GetAsync(trackingFile.ProjectId, token); project = await _projectRepository.MarkProjectAsScrapedAsync(trackingFile.ProjectId, token); _trackingFileService.MarkProjectScraped(directoryInfo); _logger.LogTrace($"Project with id {trackingFile.ProjectId} has been scraped"); return; } } else { // If no tracking file exists we can only assume that the project is // not yet being tracked. This will start tracking the project. var extractedProject = ProjectFolderHelper.ExtractProject(directoryInfo); // TODO This should not happen here. var root = _options.RootDirectoryPath.LocalPath; extractedProject.RelativePath = PathHelper.GetRelativePath(directoryInfo.FullName, root); // TODO Transaction? var createdProjectId = await _projectRepository.CreateAsync(extractedProject, token); _trackingFileService.CreateTrackingFile(createdProjectId, directoryInfo); _logger.LogTrace($"A new tracking file has been created for project {createdProjectId} at {directoryInfo.FullName}"); return; } } catch (IOException e) { _logger.LogError(e.Message); throw new FileAccessException("Could not determine if directory was Ableton project", e); } }