private async Task <Unit> ScanSeasons( LibraryPath libraryPath, string ffprobePath, Show show, string showFolder) { foreach (string seasonFolder in _localFileSystem.ListSubdirectories(showFolder).Filter(ShouldIncludeFolder) .OrderBy(identity)) { Option <int> maybeSeasonNumber = SeasonNumberForFolder(seasonFolder); await maybeSeasonNumber.IfSomeAsync( async seasonNumber => { Either <BaseError, Season> maybeSeason = await _televisionRepository .GetOrAddSeason(show, libraryPath.Id, seasonNumber) .BindT(season => UpdatePoster(season, seasonFolder)); await maybeSeason.Match( season => ScanEpisodes(libraryPath, ffprobePath, season, seasonFolder), _ => Task.FromResult(Unit.Default)); }); } return(Unit.Default); }
public override bool Compile(string file) { var file_name = file.Split('.')[0]; // Compile string cl_args = ""; Options.ForEach((str) => cl_args += $" {str}"); IncludePath.ForEach((str) => cl_args += $" /I\"{str}\""); cl_args += $" /c {file} /Fo{file_name}.obj"; var cl = MakeProcess(ToolchainPath[0] + "\\cl.exe", cl_args); ReadCompileResult(cl); if (ExitCode != 0) { return(false); } // Link string link_args = " " + Options[0]; LibraryPath.ForEach((str) => link_args += $" /LIBPATH:\"{str}\""); link_args += $" /out:{file_name}.exe {file_name}.obj"; var link = MakeProcess(ToolchainPath[0] + "\\link.exe", link_args); ReadCompileResult(link); if (ExitCode != 0) { return(false); } return(true); }
public async Task DeletedMovieAndFolder_Should_Delete_Old_Movie() { string movieFolder = Path.Combine(FakeRoot, "Movie (2020)"); string oldMoviePath = Path.Combine(movieFolder, "Movie (2020).avi"); _movieRepository.Setup(x => x.FindMoviePaths(It.IsAny <LibraryPath>())) .Returns(new List <string> { oldMoviePath }.AsEnumerable().AsTask()); string moviePath = Path.Combine(movieFolder, "Movie (2020).mkv"); MovieFolderScanner service = GetService( new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now } ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot }; Either <BaseError, Unit> result = await service.ScanFolder(libraryPath, FFprobePath); result.IsRight.Should().BeTrue(); _movieRepository.Verify(x => x.DeleteByPath(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _movieRepository.Verify(x => x.DeleteByPath(libraryPath, oldMoviePath), Times.Once); }
public async Task <Either <BaseError, Episode> > GetOrAddEpisode( Season season, LibraryPath libraryPath, string path) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); Option <Episode> maybeExisting = await dbContext.Episodes .Include(i => i.EpisodeMetadata) .ThenInclude(em => em.Artwork) .Include(i => i.MediaVersions) .ThenInclude(mv => mv.MediaFiles) .OrderBy(i => i.MediaVersions.First().MediaFiles.First().Path) .SingleOrDefaultAsync(i => i.MediaVersions.First().MediaFiles.First().Path == path); return(await maybeExisting.Match <Task <Either <BaseError, Episode> > >( async episode => { // move the file to the new season if needed // this can happen when adding NFO metadata to existing content if (episode.SeasonId != season.Id) { episode.SeasonId = season.Id; episode.Season = season; await _dbConnection.ExecuteAsync( @"UPDATE Episode SET SeasonId = @SeasonId WHERE Id = @EpisodeId", new { SeasonId = season.Id, EpisodeId = episode.Id }); } return episode; }, async() => await AddEpisode(dbContext, season, libraryPath.Id, path))); }
public async Task DeletedMovieAndFolder_Should_Flag_File_Not_Found() { string movieFolder = Path.Combine(FakeRoot, "Movie (2020)"); string oldMoviePath = Path.Combine(movieFolder, "Movie (2020).avi"); _movieRepository.Setup(x => x.FindMoviePaths(It.IsAny <LibraryPath>())) .Returns(new List <string> { oldMoviePath }.AsEnumerable().AsTask()); MovieFolderScanner service = GetService( new FakeFolderEntry(FakeRoot) ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot, LibraryFolders = new List <LibraryFolder>() }; Either <BaseError, Unit> result = await service.ScanFolder( libraryPath, FFmpegPath, FFprobePath, 0, 1, CancellationToken.None); result.IsRight.Should().BeTrue(); _mediaItemRepository.Verify( x => x.FlagFileNotFound(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _mediaItemRepository.Verify(x => x.FlagFileNotFound(libraryPath, oldMoviePath), Times.Once); }
private async Task <Unit> MovePath(TvContext dbContext, Parameters parameters) { LibraryPath path = parameters.LibraryPath; LocalLibrary newLibrary = parameters.Library; path.LibraryId = newLibrary.Id; if (await dbContext.SaveChangesAsync() > 0) { List <int> ids = await dbContext.Connection.QueryAsync <int>( @"SELECT MediaItem.Id FROM MediaItem WHERE LibraryPathId = @LibraryPathId", new { LibraryPathId = path.Id }) .Map(result => result.ToList()); foreach (int id in ids) { Option <MediaItem> maybeMediaItem = await _searchRepository.GetItemToIndex(id); foreach (MediaItem mediaItem in maybeMediaItem) { _logger.LogInformation("Moving item at {Path}", await GetPath(dbContext, mediaItem)); await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> { mediaItem }); } } } return(Unit.Default); }
public async Task DeleteLocalPath(int libraryPathId) { await using TvContext context = _dbContextFactory.CreateDbContext(); LibraryPath libraryPath = await context.LibraryPaths.FindAsync(libraryPathId); context.LibraryPaths.Remove(libraryPath); await context.SaveChangesAsync(); }
public async Task <Unit> UpdateLastScan(LibraryPath libraryPath) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); return(await dbContext.Connection.ExecuteAsync( "UPDATE LibraryPath SET LastScan = @LastScan WHERE Id = @Id", new { libraryPath.LastScan, libraryPath.Id }).ToUnit()); }
public async Task <Either <BaseError, Unit> > ScanFolder(LibraryPath libraryPath, string ffprobePath) { if (!_localFileSystem.IsLibraryPathAccessible(libraryPath)) { return(new MediaSourceInaccessible()); } var allShowFolders = _localFileSystem.ListSubdirectories(libraryPath.Path) .Filter(ShouldIncludeFolder) .OrderBy(identity) .ToList(); foreach (string showFolder in allShowFolders) { Either <BaseError, MediaItemScanResult <Show> > maybeShow = await FindOrCreateShow(libraryPath.Id, showFolder) .BindT(show => UpdateMetadataForShow(show, showFolder)) .BindT(show => UpdateArtworkForShow(show, showFolder, ArtworkKind.Poster)) .BindT(show => UpdateArtworkForShow(show, showFolder, ArtworkKind.FanArt)); await maybeShow.Match( async result => { if (result.IsAdded) { await _searchIndex.AddItems(new List <MediaItem> { result.Item }); } else if (result.IsUpdated) { await _searchIndex.UpdateItems(new List <MediaItem> { result.Item }); } await ScanSeasons(libraryPath, ffprobePath, result.Item, showFolder); }, _ => Task.FromResult(Unit.Default)); } foreach (string path in await _televisionRepository.FindEpisodePaths(libraryPath)) { if (!_localFileSystem.FileExists(path)) { _logger.LogInformation("Removing missing episode at {Path}", path); await _televisionRepository.DeleteByPath(libraryPath, path); } } await _televisionRepository.DeleteEmptySeasons(libraryPath); List <int> ids = await _televisionRepository.DeleteEmptyShows(libraryPath); await _searchIndex.RemoveItems(ids); return(Unit.Default); }
public async Task NewMovie_Statistics_And_FallbackMetadata_And_MovieNamePoster( [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] string videoExtension, [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.ImageFileExtensions))] string imageExtension) { string moviePath = Path.Combine( FakeRoot, Path.Combine("Movie (2020)", $"Movie (2020){videoExtension}")); string posterPath = Path.Combine( Path.GetDirectoryName(moviePath) ?? string.Empty, $"Movie (2020)-poster.{imageExtension}"); MovieFolderScanner service = GetService( new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now }, new FakeFileEntry(posterPath) { LastWriteTime = DateTime.Now } ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot, LibraryFolders = new List <LibraryFolder>() }; Either <BaseError, Unit> result = await service.ScanFolder( libraryPath, FFmpegPath, FFprobePath, 0, 1, CancellationToken.None); result.IsRight.Should().BeTrue(); _movieRepository.Verify(x => x.GetOrAdd(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _movieRepository.Verify(x => x.GetOrAdd(libraryPath, moviePath), Times.Once); _localStatisticsProvider.Verify( x => x.RefreshStatistics( FFmpegPath, FFprobePath, It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), Times.Once); _localMetadataProvider.Verify( x => x.RefreshFallbackMetadata( It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), Times.Once); _imageCache.Verify( x => x.CopyArtworkToCache(posterPath, ArtworkKind.Poster), Times.Once); }
public Task <IEnumerable <string> > FindEpisodePaths(LibraryPath libraryPath) => _dbConnection.QueryAsync <string>( @"SELECT MF.Path FROM MediaFile MF INNER JOIN MediaVersion MV on MF.MediaVersionId = MV.Id INNER JOIN Episode E on MV.EpisodeId = E.Id INNER JOIN MediaItem MI on E.Id = MI.Id WHERE MI.LibraryPathId = @LibraryPathId", new { LibraryPathId = libraryPath.Id });
public async Task <LibraryPath> Add(LibraryPath libraryPath) { await using TvContext context = _dbContextFactory.CreateDbContext(); await context.LibraryPaths.AddAsync(libraryPath); await context.SaveChangesAsync(); return(libraryPath); }
private async Task <Unit> DoDeletion(LibraryPath libraryPath) { List <int> ids = await _libraryRepository.GetMediaIdsByLocalPath(libraryPath.Id); await _searchIndex.RemoveItems(ids); await _libraryRepository.DeleteLocalPath(libraryPath.Id); return(Unit.Default); }
public override int GetHashCode() { unchecked // Overflow is fine, just wrap { int hash = 17; hash = hash * 23 + ModuleName.GetHashCode(); hash = hash * 23 + LibraryPath.GetHashCode(); hash = hash * 23 + LibraryPath.GetHashCode(); return(hash); } }
/// <summary> /// See if valid Spotfire link /// </summary> /// <returns></returns> private bool IsValidSpotfireLink() { if (Lex.IsUndefined(LibraryPath.Text)) { LibraryPath.Focus(); MessageBoxMx.Show("You must define the Library Path for the linked analysis"); return(false); } return(true); }
public async Task <Unit> DeleteEmptySeasons(LibraryPath libraryPath) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); List <Season> seasons = await dbContext.Seasons .Filter(s => s.LibraryPathId == libraryPath.Id) .Filter(s => s.Episodes.Count == 0) .ToListAsync(); dbContext.Seasons.RemoveRange(seasons); await dbContext.SaveChangesAsync(); return(Unit.Default); }
public async Task Missing_Folder() { MovieFolderScanner service = GetService( new FakeFileEntry(Path.Combine(FakeRoot, Path.Combine("Movie (2020)", "Movie (2020).mkv"))) ); var libraryPath = new LibraryPath { Path = BadFakeRoot }; Either <BaseError, Unit> result = await service.ScanFolder(libraryPath, FFprobePath); result.IsLeft.Should().BeTrue(); result.IfLeft(error => error.Should().BeOfType <MediaSourceInaccessible>()); }
public async Task <List <int> > DeleteEmptyShows(LibraryPath libraryPath) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); List <Show> shows = await dbContext.Shows .Filter(s => s.LibraryPathId == libraryPath.Id) .Filter(s => s.Seasons.Count == 0) .ToListAsync(); var ids = shows.Map(s => s.Id).ToList(); dbContext.Shows.RemoveRange(shows); await dbContext.SaveChangesAsync(); return(ids); }
private async Task <Either <BaseError, Unit> > ScanEpisodes( LibraryPath libraryPath, string ffmpegPath, string ffprobePath, Season season, string seasonPath, CancellationToken cancellationToken) { var allSeasonFiles = _localFileSystem.ListSubdirectories(seasonPath) .Map(_localFileSystem.ListFiles) .Flatten() .Append(_localFileSystem.ListFiles(seasonPath)) .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))) .Filter(f => !Path.GetFileName(f).StartsWith("._")) .OrderBy(identity) .ToList(); foreach (string file in allSeasonFiles) { // TODO: figure out how to rebuild playlists Either <BaseError, Episode> maybeEpisode = await _televisionRepository .GetOrAddEpisode(season, libraryPath, file) .BindT( episode => UpdateStatistics(new MediaItemScanResult <Episode>(episode), ffmpegPath, ffprobePath) .MapT(_ => episode)) .BindT(UpdateMetadata) .BindT(e => UpdateThumbnail(e, cancellationToken)) .BindT(UpdateSubtitles) .BindT(e => FlagNormal(new MediaItemScanResult <Episode>(e))) .MapT(r => r.Item); foreach (BaseError error in maybeEpisode.LeftToSeq()) { _logger.LogWarning("Error processing episode at {Path}: {Error}", file, error.Value); } foreach (Episode episode in maybeEpisode.RightToSeq()) { await _searchIndex.UpdateItems(_searchRepository, new List <MediaItem> { episode }); } } // TODO: remove missing episodes? return(Unit.Default); }
public async Task NewMovie_Statistics_And_SidecarMetadata_MovieNameNfo( [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] string videoExtension) { string moviePath = Path.Combine( FakeRoot, Path.Combine("Movie (2020)", $"Movie (2020){videoExtension}")); string metadataPath = Path.ChangeExtension(moviePath, "nfo"); MovieFolderScanner service = GetService( new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now }, new FakeFileEntry(metadataPath) ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot, LibraryFolders = new List <LibraryFolder>() }; Either <BaseError, Unit> result = await service.ScanFolder( libraryPath, FFmpegPath, FFprobePath, 0, 1, CancellationToken.None); result.IsRight.Should().BeTrue(); _movieRepository.Verify(x => x.GetOrAdd(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _movieRepository.Verify(x => x.GetOrAdd(libraryPath, moviePath), Times.Once); _localStatisticsProvider.Verify( x => x.RefreshStatistics( FFmpegPath, FFprobePath, It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), Times.Once); _localMetadataProvider.Verify( x => x.RefreshSidecarMetadata( It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath), metadataPath), Times.Once); }
private async Task <Either <BaseError, MediaItemScanResult <Song> > > UpdateThumbnail( MediaItemScanResult <Song> result, string ffmpegPath, CancellationToken cancellationToken) { try { // reload the song from the database at this point if (result.IsAdded) { LibraryPath libraryPath = result.Item.LibraryPath; string path = result.Item.GetHeadVersion().MediaFiles.Head().Path; foreach (MediaItemScanResult <Song> s in (await _songRepository.GetOrAdd(libraryPath, path)) .RightToSeq()) { result.Item = s.Item; } } Song song = result.Item; Option <string> maybeThumbnail = LocateThumbnail(song); if (maybeThumbnail.IsNone) { await ExtractEmbeddedArtwork(song, ffmpegPath, cancellationToken); } foreach (string thumbnailFile in maybeThumbnail) { SongMetadata metadata = song.SongMetadata.Head(); await RefreshArtwork( thumbnailFile, metadata, ArtworkKind.Thumbnail, ffmpegPath, None, cancellationToken); } return(result); } catch (Exception ex) { _client.Notify(ex); return(BaseError.New(ex.ToString())); } }
public void GetFallbackMetadata_ShouldHandleVariousFormats(string path, int season, int episode) { List <EpisodeMetadata> metadata = _fallbackMetadataProvider.GetFallbackMetadata( new Episode { LibraryPath = new LibraryPath(), MediaVersions = new List <MediaVersion> { new() { MediaFiles = new List <MediaFile> { new() { Path = path } } } } });
public async Task Should_Ignore_Extra_Folders( [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.VideoFileExtensions))] string videoExtension, [ValueSource(typeof(LocalFolderScanner), nameof(LocalFolderScanner.ExtraDirectories))] string extraFolder) { string moviePath = Path.Combine( FakeRoot, Path.Combine("Movie (2020)", $"Movie (2020){videoExtension}")); MovieFolderScanner service = GetService( new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now }, new FakeFileEntry( Path.Combine( Path.GetDirectoryName(moviePath) ?? string.Empty, Path.Combine(extraFolder, $"Movie (2020){videoExtension}"))) ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot }; Either <BaseError, Unit> result = await service.ScanFolder(libraryPath, FFprobePath); result.IsRight.Should().BeTrue(); _movieRepository.Verify(x => x.GetOrAdd(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _movieRepository.Verify(x => x.GetOrAdd(libraryPath, moviePath), Times.Once); _localStatisticsProvider.Verify( x => x.RefreshStatistics( FFprobePath, It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), Times.Once); _localMetadataProvider.Verify( x => x.RefreshFallbackMetadata( It.Is <Movie>(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath)), Times.Once); }
public override bool Execute() { Log.LogMessage("Start to generate documentation"); if (LibraryPath.IsEmpty()) { Log.LogWarning("Library not choosed"); return(true); } LibraryPath = Path.GetFullPath(LibraryPath); if (OutputPath.IsEmpty()) { OutputPath = Path.Combine(Path.GetDirectoryName(LibraryPath), "doc"); } Directory.CreateDirectory(OutputPath); throw new NotImplementedException(); }
public async Task RenamedMovie_Should_Delete_Old_Movie() { // TODO: handle this case more elegantly // ideally, detect that the movie was renamed and still delete the old one (or update the path?) string movieFolder = Path.Combine(FakeRoot, "Movie (2020)"); string oldMoviePath = Path.Combine(movieFolder, "Movie (2020).avi"); _movieRepository.Setup(x => x.FindMoviePaths(It.IsAny <LibraryPath>())) .Returns(new List <string> { oldMoviePath }.AsEnumerable().AsTask()); string moviePath = Path.Combine(movieFolder, "Movie (2020).mkv"); MovieFolderScanner service = GetService( new FakeFileEntry(moviePath) { LastWriteTime = DateTime.Now } ); var libraryPath = new LibraryPath { Id = 1, Path = FakeRoot, LibraryFolders = new List <LibraryFolder>() }; Either <BaseError, Unit> result = await service.ScanFolder( libraryPath, FFmpegPath, FFprobePath, 0, 1, CancellationToken.None); result.IsRight.Should().BeTrue(); _mediaItemRepository.Verify( x => x.FlagFileNotFound(It.IsAny <LibraryPath>(), It.IsAny <string>()), Times.Once); _mediaItemRepository.Verify(x => x.FlagFileNotFound(libraryPath, oldMoviePath), Times.Once); }
/// <summary> /// To be used with Razor class libraries loaded dynamically /// </summary> void LoadDynamicLibraries(ApplicationPartManager PartManager) { // get the output folder of this application string moduleSource = Configuration["ModulesPath"]; moduleSource = Path.GetDirectoryName(moduleSource); // get the full filepath of any dll starting with the rcl_ prefix string Prefix = "Mod_"; string SearchPattern = $"{Prefix}*.dll"; string[] LibraryPaths = Directory.GetFiles(moduleSource, SearchPattern); if (LibraryPaths != null && LibraryPaths.Length > 0) { // create the load context LibraryLoadContext LoadContext = new LibraryLoadContext(moduleSource); Assembly Assembly; ApplicationPart ApplicationPart; foreach (string LibraryPath in LibraryPaths) { // load each assembly using its filepath Assembly = LoadContext.LoadFromAssemblyPath(LibraryPath); // create an application part for that assembly ApplicationPart = LibraryPath.EndsWith(".Views.dll") ? new CompiledRazorAssemblyPart(Assembly) as ApplicationPart : new AssemblyPart(Assembly); // register the application part PartManager.ApplicationParts.Add(ApplicationPart); // if it is NOT the *.Views.dll add it to a list for later use if (!LibraryPath.EndsWith(".Views.dll")) { _dynamicallyLoadedLibraries.Add(Assembly); } } } }
public async Task <Unit> DeleteByPath(LibraryPath libraryPath, string path) { IEnumerable <int> ids = await _dbConnection.QueryAsync <int>( @"SELECT E.Id FROM Episode E INNER JOIN MediaItem MI on E.Id = MI.Id INNER JOIN MediaVersion MV on E.Id = MV.EpisodeId INNER JOIN MediaFile MF on MV.Id = MF.MediaVersionId WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path", new { LibraryPathId = libraryPath.Id, Path = path }); await using TvContext dbContext = _dbContextFactory.CreateDbContext(); foreach (int episodeId in ids) { Episode episode = await dbContext.Episodes.FindAsync(episodeId); dbContext.Episodes.Remove(episode); } await dbContext.SaveChangesAsync(); return(Unit.Default); }
private async Task <Unit> ScanEpisodes( LibraryPath libraryPath, string ffprobePath, Season season, string seasonPath) { foreach (string file in _localFileSystem.ListFiles(seasonPath) .Filter(f => VideoFileExtensions.Contains(Path.GetExtension(f))).OrderBy(identity)) { // TODO: figure out how to rebuild playlists Either <BaseError, Episode> maybeEpisode = await _televisionRepository .GetOrAddEpisode(season, libraryPath, file) .BindT( episode => UpdateStatistics(new MediaItemScanResult <Episode>(episode), ffprobePath) .MapT(_ => episode)) .BindT(UpdateMetadata) .BindT(UpdateThumbnail); maybeEpisode.IfLeft( error => _logger.LogWarning("Error processing episode at {Path}: {Error}", file, error.Value)); } return(Unit.Default); }
public async Task <List <int> > DeleteByPath(LibraryPath libraryPath, string path) { await using TvContext dbContext = _dbContextFactory.CreateDbContext(); List <int> ids = await _dbConnection.QueryAsync <int>( @"SELECT M.Id FROM Movie M INNER JOIN MediaItem MI on M.Id = MI.Id INNER JOIN MediaVersion MV on M.Id = MV.MovieId INNER JOIN MediaFile MF on MV.Id = MF.MediaVersionId WHERE MI.LibraryPathId = @LibraryPathId AND MF.Path = @Path", new { LibraryPathId = libraryPath.Id, Path = path }) .Map(result => result.ToList()); foreach (int movieId in ids) { Movie movie = await dbContext.Movies.FindAsync(movieId); dbContext.Movies.Remove(movie); } bool changed = await dbContext.SaveChangesAsync() > 0; return(changed ? ids : new List <int>()); }
/// <summary> /// Executes the task. /// </summary> public override bool Execute() { CommandLineBuilder commandLine = new CommandLineBuilder(); commandLine.AppendSwitchIfNotNull("/attr:", _attributeFile); if (Closed) { commandLine.AppendSwitch("/closed"); } if (CopyAttributes) { commandLine.AppendSwitch("/copyattrs"); } if (DebugInfo) { commandLine.AppendSwitch("/ndebug"); } if (Internalize) { commandLine.AppendSwitch("/internalize:" + ExcludeFile); } if (ShouldLog) { if (LogFile == null) { commandLine.AppendSwitch("/log"); } else { commandLine.AppendSwitch("/log:"); commandLine.AppendFileNameIfNotNull(LogFile); } } commandLine.AppendSwitchIfNotNull("/keyfile:", SnkFile); commandLine.AppendSwitchIfNotNull("/target:", TargetKind); if (MergeXml) { commandLine.AppendSwitch("/xmldocs"); } TargetDotNetFrameworkVersion frameworkVersion; string framework; switch (TargetFrameworkVersion?.Trim().ToLowerInvariant()) { //v2.0, v3.0, v3.5, v4.0, v4.5, and v4.5.1. case "v2.0": frameworkVersion = TargetDotNetFrameworkVersion.Version20; framework = "v2"; break; case "v3.0": frameworkVersion = TargetDotNetFrameworkVersion.Version30; framework = "v2"; break; case "v3.5": frameworkVersion = TargetDotNetFrameworkVersion.Version35; framework = "v2"; break; case "v4.0": frameworkVersion = TargetDotNetFrameworkVersion.Version40; framework = "v4"; break; // ReSharper disable RedundantCaseLabel case "v4.5": case "v4.5.1": case "v4.5.2": case "v4.6": // ReSharper restore RedundantCaseLabel default: frameworkVersion = TargetDotNetFrameworkVersion.Version45; framework = "v4"; break; } DotNetFrameworkArchitecture platformArchitecture; switch (TargetPlatform?.Trim().ToLowerInvariant()) { case "x86": platformArchitecture = DotNetFrameworkArchitecture.Bitness32; break; case "x64": platformArchitecture = DotNetFrameworkArchitecture.Bitness64; break; default: platformArchitecture = DotNetFrameworkArchitecture.Current; break; } string toolPath = ToolLocationHelper.GetPathToDotNetFramework( frameworkVersion, platformArchitecture); Debug.Assert(Log != null); Log.LogMessage( MessageImportance.Normal, "Merge Framework: {0}, {1}", TargetFrameworkVersion, toolPath); commandLine.AppendSwitch($"/targetplatform:{framework},{toolPath}"); if (LibraryPath != null) { List <string> list = new List <string>(LibraryPath.Select(taskItem => taskItem.ItemSpec)) { "." }; foreach (string dir in list) { commandLine.AppendSwitchIfNotNull("/lib:", dir); } } commandLine.AppendSwitchIfNotNull("/out:", OutputFile); commandLine.AppendFileNamesIfNotNull(InputAssemblies, " "); try { Log.LogMessage( MessageImportance.Normal, "Merging {0} assembl{1} to '{2}'.", InputAssemblies.Length, InputAssemblies.Length != 1 ? "ies" : "y", _outputFile); Log.LogMessage(MessageImportance.Low, ILMergeTool + " " + commandLine); Process proc = new Process { StartInfo = new ProcessStartInfo(ILMergeTool, commandLine.ToString()) { RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false } }; proc.OutputDataReceived += (sender, args) => { Debug.Assert(args != null); // Null is sent when the stream closes, so skip it if (!string.IsNullOrEmpty(args.Data)) { Log.LogMessage(args.Data); } }; proc.ErrorDataReceived += (sender, args) => { Debug.Assert(args != null); // Null is sent when the stream closes, so skip it if (!string.IsNullOrEmpty(args.Data)) { Log.LogError(args.Data); } }; proc.Start(); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); if (proc.ExitCode != 0) { Log.LogError("ILMerge exited with error code {0}.", proc.ExitCode); } else { Log.LogMessage("ILMerge completed successfully."); } return(proc.ExitCode == 0); } catch (Exception ex) { Log.LogErrorFromException(ex); return(false); } }