// Copy the source code public virtual void CopyUnixSrc(string baseOutputDir) { // Generate an Output directory name string outDir = baseOutputDir; string outSrcDir = baseOutputDir; Con.WriteLine("BuildSrcKit for '{0}'...", this.IDString); Con.WriteLine("BuildSrcKit Output Dir = '{0}'.", outDir); string tsFile = Path.Combine(outDir, "TimeStamp.txt"); string timeStamp = Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime); Con.WriteLine("timestamp={0}", timeStamp); if (Directory.Exists(outDir)) { } else { Directory.CreateDirectory(outDir); } // Copy the source code foreach (string srcDirName in SrcDirNameList) { string srcFullPath = Path.Combine(Paths.BaseDirName, srcDirName); string destFullPath = Path.Combine(outSrcDir, srcDirName); IO.CopyDir(srcFullPath, destFullPath, new IO.CopyDirPreCopyDelegate(CopySrcFilesDelegate), false, true, true, true, true); } IO.FileCopy(Path.Combine(Paths.BaseDirName, "CurrentBuild.txt"), Path.Combine(outSrcDir, "CurrentBuild.txt"), true, false); }
public static void WriteBuildInfoToTextFile(int build, int version, string name, DateTime date, string filename) { using (StreamWriter w = new StreamWriter(filename)) { w.WriteLine("BUILD_NUMBER {0}", build); w.WriteLine("VERSION {0}", version); w.WriteLine("BUILD_NAME {0}", name); w.WriteLine("BUILD_DATE {0}", Str.DateTimeToStrShort(date)); w.Flush(); w.Close(); } }
// Initialize static Paths() { // Starting date and time string Paths.StartDateTimeStr = Str.DateTimeToStrShort(Paths.StartDateTime); // Check whether the execution path is the bin directory in the VPN directory if (Paths.SolutionBinDirName.EndsWith(@"\bin", StringComparison.InvariantCultureIgnoreCase) == false) { throw new ApplicationException(string.Format("'{0}' is not a VPN bin directory.", Paths.SolutionBinDirName)); } // Determine the Visual Studio solution file string slnFileName = Directory.EnumerateFiles(SolutionBaseDirName).Where(x => x.EndsWith(".sln")).Single(); Paths.VisualStudioSolutionFileName = Path.Combine(SolutionBaseDirName, slnFileName); if (File.Exists(Paths.VisualStudioSolutionFileName) == false) { throw new ApplicationException(string.Format("'{0}' is not a VPN base directory.", Paths.SolutionBaseDirName)); } // Get Microsoft SDK directory if (IntPtr.Size == 8) { Paths.MicrosoftSDKDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0", "InstallationFolder")); } else { Paths.MicrosoftSDKDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0", "InstallationFolder")); } if (Str.IsEmptyStr(Paths.MicrosoftSDKDir)) { throw new ApplicationException("Microsoft SDK not found."); } Paths.MicrosoftSDKBinDir = Path.Combine(Paths.MicrosoftSDKDir, @"bin\x86"); if (File.Exists(Path.Combine(Paths.MicrosoftSDKBinDir, "rc.exe")) == false) { // rc.exe not found. Enum alternative sub directories string tmp = Path.GetDirectoryName(Paths.MicrosoftSDKBinDir); foreach (string subDir in Directory.EnumerateDirectories(tmp).OrderByDescending(x => x)) { string tmp2 = Path.Combine(tmp, subDir, "x86"); if (File.Exists(Path.Combine(tmp2, "rc.exe"))) { Paths.MicrosoftSDKBinDir = tmp2; break; } } } // Get makecat.exe file name Paths.MakeCatFilename = Path.Combine(Paths.MicrosoftSDKBinDir, "makecat.exe"); // Get the rc.exe file name Paths.RcFilename = Path.Combine(Paths.MicrosoftSDKBinDir, "rc.exe"); // Get the cmd.exe file name Paths.CmdFileName = Path.Combine(Env.SystemDir, "cmd.exe"); if (File.Exists(Paths.CmdFileName) == false) { throw new ApplicationException(string.Format("File '{0}' not found.", Paths.CmdFileName)); } // Get the TMP directory Paths.TmpDirName = Path.Combine(Paths.SolutionBaseDirName, "tmp"); if (Directory.Exists(Paths.TmpDirName) == false) { Directory.CreateDirectory(Paths.TmpDirName); } }
// Build SrcKit public virtual bool BuildSrcKit(string baseOutputDir, bool debugMode) { // Generate an Output directory name string outDir = Path.Combine(baseOutputDir, this.CrossLibName); string outSrcDir = Path.Combine(outDir, "src"); Con.WriteLine("BuildSrcKit for '{0}'...", this.IDString); Con.WriteLine("CrossLib Name: '{0}'.", this.CrossLibName); Con.WriteLine("BuildSrcKit Output Dir = '{0}'.", outDir); string tsFile = Path.Combine(outDir, "TimeStamp.txt"); string timeStamp = Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime); Con.WriteLine("timestamp={0}", timeStamp); if (Directory.Exists(outDir)) { bool ok = false; // See TimeStamp.txt file if the directory already exists try { string[] ts = File.ReadAllLines(tsFile); if (ts[0] == timeStamp) { ok = true; } } catch { } if (ok) { Con.WriteLine("Skipped for '{0}'.", this.IDString); return(false); } } else { Directory.CreateDirectory(outDir); } // Copy the source code foreach (string srcDirName in SrcDirNameList) { string srcFullPath = Path.Combine(Paths.BaseDirName, srcDirName); string destFullPath = Path.Combine(outSrcDir, srcDirName); bool delete_bom = true; if (Str.InStr(srcDirName, "\\hamcore")) { delete_bom = false; } IO.CopyDir(srcFullPath, destFullPath, new IO.CopyDirPreCopyDelegate(CopySrcFilesDelegate), false, true, true, delete_bom); } IO.FileCopy(Path.Combine(Paths.BaseDirName, "CurrentBuild.txt"), Path.Combine(outSrcDir, "CurrentBuild.txt"), true, false); IO.FileCopy(Path.Combine(Paths.BaseDirName, "GlobalConst.h"), Path.Combine(outSrcDir, "GlobalConst.h"), true, false); IO.FileCopy(Path.Combine(Paths.BaseDirName, @"DebugFiles\Replace.h"), Path.Combine(outSrcDir, "Replace.h"), true, false); IO.FileCopy(Path.Combine(Paths.BaseDirName, @"bin\BuiltHamcoreFiles\hamcore_unix\hamcore.se2"), Path.Combine(outSrcDir, @"bin\hamcore.se2"), true, false); // Copy Crosslibs IO.CopyDir(Path.Combine(this.CrossLibBaseDir, this.CrossLibName), Path.Combine(outSrcDir, @"lib"), delegate(FileInfo fi) { if (fi.DirectoryName.IndexOf(@".svn", StringComparison.InvariantCultureIgnoreCase) != -1) { return(false); } return(true); }, false, true, true, false); // Generate Makefile for compilation byte[] makeFileDataForCross = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(GenerateMakeFileForCompile(outSrcDir, debugMode, true).ToString()), new byte[] { 10, }); byte[] makeFileDataForSelf = Str.NormalizeCrlf(Str.Utf8Encoding.GetBytes(GenerateMakeFileForCompile(outSrcDir, debugMode, false).ToString()), new byte[] { 10, }); string makeFileName = Path.Combine(outSrcDir, "Makefile"); File.WriteAllBytes(makeFileName, makeFileDataForCross); // TimeStamp.txt File.WriteAllText(tsFile, timeStamp); // Create a tar.gz string tarGzFileName = Path.Combine(outSrcDir, this.SrcKitFileName); Con.WriteLine("Creating '{0}'...", tarGzFileName); List <string> files = new List <string>(); foreach (string srcDirName in Util.CombineArray <string>(SrcDirNameList, new string[] { "lib" })) { string dirFullPath = Path.Combine(outSrcDir, srcDirName); string[] fileList = Directory.GetFiles(dirFullPath, "*", srcDirName.Equals("lib", StringComparison.InvariantCultureIgnoreCase) ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories); foreach (string fileName in fileList) { files.Add(fileName); } } files.Add(Path.Combine(outSrcDir, @"CurrentBuild.txt")); files.Add(Path.Combine(outSrcDir, @"bin\hamcore.se2")); files.Add(Path.Combine(outSrcDir, @"Replace.h")); files.Add(Path.Combine(outSrcDir, @"GlobalConst.h")); files.Sort(); TarPacker tar = new TarPacker(); foreach (string file in files) { byte[] fileData = File.ReadAllBytes(file); tar.AddFileSimple(@"src\" + IO.GetRelativeFileName(file, outSrcDir), fileData, 0, fileData.Length, File.GetLastWriteTime(file), "0000750", "0000640"); } tar.AddFileSimple(@"src\Makefile", makeFileDataForSelf, 0, makeFileDataForSelf.Length, DateTime.Now, "0000750", "0000640"); tar.Finish(); byte[] tarGzData = tar.CompressToGZip(); File.WriteAllBytes(tarGzFileName, tarGzData); IO.MakeDir(Paths.ReleaseSrckitDir); File.WriteAllBytes(Path.Combine(Paths.ReleaseSrckitDir, this.SrcKitFileName), tarGzData); Con.WriteLine("Completed."); return(true); }
// Get the DebugSnapshot directory name public static string GetDebugSnapstotDirName() { return(Path.Combine(Paths.DebugSnapshotBaseDir, Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime))); }
// Initialize static Paths() { // Starting date and time string Paths.StartDateTimeStr = Str.DateTimeToStrShort(Paths.StartDateTime); // Check whether the execution path is the bin directory in the VPN directory if (Paths.BinDirName.EndsWith(@"\bin", StringComparison.InvariantCultureIgnoreCase) == false) { throw new ApplicationException(string.Format("'{0}' is not a VPN bin directory.", Paths.BinDirName)); } if (File.Exists(Paths.VPN4SolutionFileName) == false) { throw new ApplicationException(string.Format("'{0}' is not a VPN base directory.", Paths.BaseDirName)); } // Get the VC++ directory // Visual Studio 2008 if (IntPtr.Size == 4) { Paths.VisualStudioVCDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Microsoft\VisualStudio\10.0\Setup\VC", "ProductDir")); } else { Paths.VisualStudioVCDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\Setup\VC", "ProductDir")); } if (Str.IsEmptyStr(Paths.VisualStudioVCDir)) { throw new ApplicationException("Visual C++ directory not found.\n"); } if (Directory.Exists(Paths.VisualStudioVCDir) == false) { throw new ApplicationException(string.Format("Directory '{0}' not found.", Paths.VisualStudioVCDir)); } // Get the VC++ batch file name Paths.VisualStudioVCBatchFileName = Path.Combine(Paths.VisualStudioVCDir, "vcvarsall.bat"); if (File.Exists(Paths.VisualStudioVCBatchFileName) == false) { throw new ApplicationException(string.Format("File '{0}' not found.", Paths.VisualStudioVCBatchFileName)); } bool x86_dir = false; // Get Microsoft SDK 6.0a directory if (IntPtr.Size == 4) { Paths.MicrosoftSDKDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v7.0A", "InstallationFolder")); } else { Paths.MicrosoftSDKDir = IO.RemoteLastEnMark(Reg.ReadStr(RegRoot.LocalMachine, @"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A", "InstallationFolder")); } // Get makecat.exe file name Paths.MakeCatFilename = Path.Combine(Paths.MicrosoftSDKDir, @"bin\" + (x86_dir ? @"x86\" : "") + "makecat.exe"); // Get the rc.exe file name Paths.RcFilename = Path.Combine(Paths.MicrosoftSDKDir, @"bin\" + (x86_dir ? @"x86\" : "") + "rc.exe"); // Get the cmd.exe file name Paths.CmdFileName = Path.Combine(Env.SystemDir, "cmd.exe"); if (File.Exists(Paths.CmdFileName) == false) { throw new ApplicationException(string.Format("File '{0}' not found.", Paths.CmdFileName)); } // Get .NET Framework 3.5 directory Paths.DotNetFramework35Dir = Path.Combine(Env.WindowsDir, @"Microsoft.NET\Framework\v4.0.30319"); // Get msbuild.exe directory Paths.MSBuildFileName = Path.Combine(Paths.DotNetFramework35Dir, "MSBuild.exe"); if (File.Exists(Paths.MSBuildFileName) == false) { throw new ApplicationException(string.Format("File '{0}' not found.", Paths.MSBuildFileName)); } // Get the TMP directory Paths.TmpDirName = Path.Combine(Paths.BaseDirName, "tmp"); if (Directory.Exists(Paths.TmpDirName) == false) { Directory.CreateDirectory(Paths.TmpDirName); } }
// 1 つのディレクトリをバックアップする public async Task DoSingleDirBackupAsync(string srcDir, string destDir, CancellationToken cancel = default, string?ignoreDirNames = null) { DateTimeOffset now = DateTimeOffset.Now; FileSystemEntity[]? srcDirEnum = null; string[] ignoreDirNamesList = ignoreDirNames._NonNull()._Split(StringSplitOptions.RemoveEmptyEntries, ",", ";"); FileMetadata?srcDirMetadata = null; bool noError = true; try { if (srcDir._IsSamei(destDir)) { throw new CoresException($"srcDir == destDir. Directory path: '{srcDir}'"); } srcDirMetadata = await Fs.GetDirectoryMetadataAsync(srcDir, cancel : cancel); srcDirEnum = (await Fs.EnumDirectoryAsync(srcDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); FileSystemEntity[] destDirEnum = new FileSystemEntity[0]; DirSuperBackupMetadata?destDirOldMetaData = null; DirSuperBackupMetadata destDirNewMetaData; // 宛先ディレクトリがすでに存在しているかどうか検査する if (await Fs.IsDirectoryExistsAsync(destDir, cancel)) { destDirEnum = await Fs.EnumDirectoryAsync(destDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel); // 宛先ディレクトリに存在するメタデータファイルのうち最新のファイルを取得する destDirOldMetaData = await GetLatestMetaDataFileNameAsync(destDir, destDirEnum, cancel); } else { // 宛先ディレクトリがまだ存在していない場合は作成する await Fs.CreateDirectoryAsync(destDir, FileFlags.BackupMode | FileFlags.AutoCreateDirectory, cancel); } // 宛先ディレクトリの日付情報のみ属性書き込みする try { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } catch { // 属性書き込みは失敗してもよい } // 新しいメタデータを作成する destDirNewMetaData = new DirSuperBackupMetadata(); destDirNewMetaData.FileList = new List <DirSuperBackupMetadataFile>(); destDirNewMetaData.TimeStamp = now; destDirNewMetaData.DirMetadata = srcDirMetadata; destDirNewMetaData.DirList = new List <string>(); // 元ディレクトリに存在するサブディレクトリ名一覧をメタデータに追記する foreach (var subDir in srcDirEnum.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false)) { // シンボリックリンクは無視する if (subDir.IsSymbolicLink == false) { // 無視リストのいずれにも合致しない場合のみ if (ignoreDirNamesList.Where(x => x._IsSamei(subDir.Name)).Any() == false) { destDirNewMetaData.DirList.Add(subDir.Name); } } } // 元ディレクトリに存在するファイルを 1 つずつバックアップする var fileEntries = srcDirEnum.Where(x => x.IsFile); RefInt concurrentNum = new RefInt(); AsyncLock SafeLock = new AsyncLock(); await TaskUtil.ForEachAsync(Options.NumThreads, fileEntries, async (srcFile, taskIndex, cancel) => { long?encryptedPhysicalSize = null; await Task.Yield(); string destFilePath = Fs.PathParser.Combine(destDir, srcFile.Name); if (Options.EncryptPassword._IsNullOrZeroLen() == false) { destFilePath += Consts.Extensions.CompressedXtsAes256; } FileMetadata?srcFileMetadata = null; concurrentNum.Increment(); try { srcFileMetadata = await Fs.GetFileMetadataAsync(srcFile.FullPath, cancel: cancel); // このファイルと同一のファイル名がすでに宛先ディレクトリに物理的に存在するかどうか確認する bool exists = await Fs.IsFileExistsAsync(destFilePath, cancel); bool fileChangedOrNew = false; if (exists) { // すでに宛先ディレクトリに存在する物理的なファイルのメタデータを取得する FileMetadata destExistsMetadata = await Fs.GetFileMetadataAsync(destFilePath, cancel: cancel); if (Options.EncryptPassword._IsNullOrZeroLen()) { // 暗号化なし // ファイルサイズを比較する if (destExistsMetadata.Size != srcFile.Size) { // ファイルサイズが異なる fileChangedOrNew = true; } } else { // 暗号化あり // 宛先ディレクトリのメタデータにファイル情報が存在し、そのメタデータ情報におけるファイルサイズが元ファイルと同じであり、 // かつそのメタデータ情報に記載されている EncryptedPhysicalSize が宛先ディレクトリにある物理ファイルと全く同一である // 場合は、宛先ファイルが正しく存在すると仮定する string tmp1 = Fs.PathParser.GetFileName(destFilePath); if ((destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSamei(tmp1) && x.EncryptedPhysicalSize == destExistsMetadata.Size && x.MetaData.Size == srcFile.Size).Any() ?? false) == false) { // ファイルサイズが異なるとみなす fileChangedOrNew = true; } } // 日付を比較する。ただし宛先ディレクトリの物理的なファイルの日付は信用できないので、メタデータ上のファイルサイズと比較する if (destDirOldMetaData != null) { DirSuperBackupMetadataFile?existsFileMetadataFromDirMetadata = destDirOldMetaData.FileList.Where(x => x.FileName._IsSamei(srcFile.Name)).SingleOrDefault(); if (existsFileMetadataFromDirMetadata == null) { // メタデータ上に存在しない fileChangedOrNew = true; } else { if (existsFileMetadataFromDirMetadata.MetaData !.LastWriteTime !.Value.Ticks != srcFileMetadata.LastWriteTime !.Value.Ticks) { // 最終更新日時が異なる fileChangedOrNew = true; } } } else { // 宛先ディレクトリ上にメタデータがない fileChangedOrNew = true; } } else { // 新しいファイルである fileChangedOrNew = true; } string?oldFilePathToDelete = null; if (fileChangedOrNew) { // ファイルが新しいか、または更新された場合は、そのファイルをバックアップする // ただし、バックアップ先に同名のファイルがすでに存在する場合は、 // .old.xxxx.YYYYMMDD_HHMMSS.0123._backup_history のような形式でまだ存在しない連番に古いファイル名をリネームする if (exists) { using (await SafeLock.LockWithAwait(cancel)) { string yymmdd = Str.DateTimeToStrShort(DateTime.UtcNow); string newOldFileName; // 連番でかつ存在していないファイル名を決定する for (int i = 0; ; i++) { string newOldFileNameCandidate = $".old.{Fs.PathParser.GetFileName(destFilePath)}.{yymmdd}.{i:D4}{Consts.Extensions.DirSuperBackupHistory}"; if (srcDirEnum.Where(x => x.Name._IsSamei(newOldFileNameCandidate)).Any() == false) { if (await Fs.IsFileExistsAsync(Fs.PathParser.Combine(destDir, newOldFileNameCandidate), cancel) == false) { newOldFileName = newOldFileNameCandidate; break; } } } // 変更されたファイル名を ._backup_history ファイルにリネーム実行する string newOldFilePath = Fs.PathParser.Combine(destDir, newOldFileName); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileRename", destFilePath, newOldFilePath)); await Fs.MoveFileAsync(destFilePath, newOldFilePath, cancel); oldFilePathToDelete = newOldFilePath; // 隠しファイルにする try { var meta = await Fs.GetFileMetadataAsync(newOldFilePath, cancel: cancel); if (meta.Attributes != null && meta.Attributes.Bit(FileAttributes.Hidden) == false) { FileMetadata meta2 = new FileMetadata(attributes: meta.Attributes.BitAdd(FileAttributes.Hidden)); await Fs.SetFileMetadataAsync(newOldFilePath, meta2, cancel); } } catch { } } } // ファイルをコピーする // 属性は、ファイルの日付情報のみコピーする await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("FileCopy", srcFile.FullPath, destFilePath)); FileFlags flags = FileFlags.BackupMode | FileFlags.Async; if (this.Options.Flags.Bit(DirSuperBackupFlags.BackupNoVerify) == false) { flags |= FileFlags.CopyFile_Verify; } await Fs.CopyFileAsync(srcFile.FullPath, destFilePath, new CopyFileParams(flags: flags, metadataCopier: new FileMetadataCopier(FileMetadataCopyMode.TimeAll), encryptOption: Options.EncryptPassword._IsNullOrZeroLen() ? EncryptOption.None : EncryptOption.Encrypt | EncryptOption.Compress, encryptPassword: Options.EncryptPassword, deleteFileIfVerifyFailed: true), cancel: cancel); try { if (Options.EncryptPassword._IsNullOrZeroLen() == false) { var newFileMetadata = await Fs.GetFileMetadataAsync(destFilePath, FileMetadataGetFlags.NoPhysicalFileSize, cancel); encryptedPhysicalSize = newFileMetadata.Size; } } catch { } if (Options.Flags.Bit(DirSuperBackupFlags.BackupMakeHistory) == false) { // History を残さない場合 // コピーに成功したので ._backup_history ファイルは削除する if (oldFilePathToDelete._IsNotZeroLen()) { try { await Fs.DeleteFileAsync(oldFilePathToDelete, flags: FileFlags.BackupMode | FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel); } catch { } } } Stat.Copy_NumFiles++; Stat.Copy_TotalSize += srcFile.Size; } else { if (Options.EncryptPassword._IsNullOrZeroLen() == false) { string tmp1 = Fs.PathParser.GetFileName(destFilePath); encryptedPhysicalSize = destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSame(tmp1) && x.MetaData.Size == srcFile.Size).FirstOrDefault()?.EncryptedPhysicalSize; if (encryptedPhysicalSize.HasValue == false) { encryptedPhysicalSize = destDirOldMetaData?.FileList.Where(x => x.EncrypedFileName._IsSamei(tmp1) && x.MetaData.Size == srcFile.Size).FirstOrDefault()?.EncryptedPhysicalSize; } } Stat.Skip_NumFiles++; Stat.Skip_TotalSize += srcFile.Size; // ファイルの日付情報のみ更新する try { await Fs.SetFileMetadataAsync(destFilePath, srcFileMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } catch { // ファイルの日付情報の更新は失敗してもよい } } } catch (Exception ex) { Stat.Error_NumFiles++; Stat.Error_TotalSize += srcFile.Size; // ファイル単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("FileError", srcFile.FullPath, destFilePath, ex.Message)); noError = false; } finally { concurrentNum.Decrement(); } // このファイルに関するメタデータを追加する if (srcFileMetadata != null) { lock (destDirNewMetaData.FileList) { destDirNewMetaData.FileList.Add(new DirSuperBackupMetadataFile() { FileName = srcFile.Name, EncrypedFileName = Options.EncryptPassword._IsNullOrZeroLen() ? null : srcFile.Name + Consts.Extensions.CompressedXtsAes256, MetaData = srcFileMetadata, EncryptedPhysicalSize = encryptedPhysicalSize, }); } } }, cancel : cancel); // 新しいメタデータをファイル名でソートする destDirNewMetaData.FileList = destDirNewMetaData.FileList.OrderBy(x => x.FileName, StrComparer.IgnoreCaseComparer).ToList(); destDirNewMetaData.DirList = destDirNewMetaData.DirList.OrderBy(x => x, StrComparer.IgnoreCaseComparer).ToList(); // 新しいメタデータを書き込む string newMetadataFilePath = Fs.PathParser.Combine(destDir, $"{PrefixMetadata}{Str.DateTimeToStrShortWithMilliSecs(now.UtcDateTime)}{SuffixMetadata}"); await Fs.WriteJsonToFileAsync(newMetadataFilePath, destDirNewMetaData, FileFlags.BackupMode | FileFlags.OnCreateSetCompressionFlag, cancel : cancel); } catch (Exception ex) { Stat.Error_Dir++; noError = false; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError1", srcDir, destDir, ex.Message)); } // 再度 宛先ディレクトリの日付情報のみ属性書き込みする (Linux の場合、中のファイルを更新するとディレクトリの日時が変ってしまうため) try { if (srcDirMetadata != null) { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } } catch { // 属性書き込みは失敗してもよい } if (srcDirEnum != null) { bool ok = false; try { // ソースディレクトリの列挙に成功した場合は、サブディレクトリに対して再帰的に実行する foreach (var subDir in srcDirEnum.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false)) { // シンボリックリンクは無視する if (subDir.IsSymbolicLink == false) { // 無視リストのいずれにも合致しない場合のみ if (ignoreDirNamesList.Where(x => x._IsSamei(subDir.Name)).Any() == false) { await DoSingleDirBackupAsync(Fs.PathParser.Combine(srcDir, subDir.Name), Fs.PathParser.Combine(destDir, subDir.Name), cancel, ignoreDirNames); } } } ok = true; } catch (Exception ex) { // 何らかのディレクトリ単位のエラーで catch されていないものが発生 Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirError2", srcDir, destDir, ex.Message)); } if (ok) { if (noError) { // ここまでの処理で何も問題がなければ (このディレクトリ内のすべてのファイルのコピーやメタデータの更新に成功しているなであれば) // Sync オプションが付与されている場合、不要なサブディレクトリとファイルを削除する if (this.Options.Flags.Bit(DirSuperBackupFlags.BackupSync)) { try { // 両方のディレクトリを再列挙いたします var srcDirEnum2 = (await Fs.EnumDirectoryAsync(srcDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); var destDirEnum2 = (await Fs.EnumDirectoryAsync(destDir, false, EnumDirectoryFlags.NoGetPhysicalSize, cancel)).OrderBy(x => x.Name, StrComparer.IgnoreCaseComparer).ToArray(); // 余分なファイルを削除いたします var extraFiles = destDirEnum2.Where(x => x.IsFile && x.IsSymbolicLink == false) .Where(x => x.Name._StartWithi(DirSuperBackup.PrefixMetadata) == false && x.Name._EndsWithi(DirSuperBackup.SuffixMetadata) == false) .Where(x => srcDirEnum2.Where(y => y.IsFile && y.Name._IsSameiTrim(x.Name)).Any() == false) .Where(x => srcDirEnum2.Where(y => y.IsFile && (y.Name + Consts.Extensions.CompressedXtsAes256)._IsSameiTrim(x.Name)).Any() == false); foreach (var extraFile in extraFiles) { string fullPath = Fs.PathParser.Combine(destDir, extraFile.Name); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("DirSyncDeleteFile", fullPath)); try { await Fs.DeleteFileAsync(fullPath, FileFlags.BackupMode | FileFlags.ForceClearReadOnlyOrHiddenBitsOnNeed, cancel); Stat.SyncDelete_NumFiles++; } catch (Exception ex) { Stat.Error_NumDeleteFiles++; await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncDeleteFileError", fullPath, ex.Message)); } } // 余分なサブディレクトリを削除いたします var extraSubDirs = destDirEnum2.Where(x => x.IsDirectory && x.IsCurrentOrParentDirectory == false && x.IsSymbolicLink == false) .Where(x => srcDirEnum2.Where(y => y.IsDirectory && y.IsCurrentOrParentDirectory == false && y.Name._IsSameiTrim(x.Name)).Any() == false); foreach (var extraSubDir in extraSubDirs) { string fullPath = Fs.PathParser.Combine(destDir, extraSubDir.Name); await WriteLogAsync(DirSuperBackupLogType.Info, Str.CombineStringArrayForCsv("DirSyncDeleteSubDir", fullPath)); try { await Fs.DeleteDirectoryAsync(fullPath, true, cancel); Stat.SyncDelete_NumDirs++; } catch (Exception ex) { Stat.Error_NumDeleteDirs++; await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncDeleteSubDirError", fullPath, ex.Message)); } } } catch (Exception ex) { // 何らかのディレクトリ単位のエラーで catch されていないものが発生 Stat.Error_Dir++; // ディレクトリ単位のエラー発生 await WriteLogAsync(DirSuperBackupLogType.Error, Str.CombineStringArrayForCsv("DirSyncEnumError", srcDir, destDir, ex.Message)); } } } } } // 再度 宛先ディレクトリの日付情報のみ属性書き込みする (Linux の場合、中のファイルを更新するとディレクトリの日時が変ってしまうため) try { if (srcDirMetadata != null) { await Fs.SetFileMetadataAsync(destDir, srcDirMetadata.Clone(FileMetadataCopyMode.TimeAll), cancel); } } catch { // 属性書き込みは失敗してもよい } }
static int ReleaseUnix(ConsoleService c, string cmdName, string str) { ConsoleParam[] args = { new ConsoleParam("[id]"), new ConsoleParam("IGNOREERROR"), new ConsoleParam("DEBUG"), new ConsoleParam("SERIAL"), }; ConsoleParamValueList vl = c.ParseCommandList(cmdName, str, args); int version, build; string name; DateTime date; Win32BuildUtil.ReadBuildInfoFromTextFile(out build, out version, out name, out date); BuildSoftware[] softs = BuildSoftwareList.List; bool serial = vl["SERIAL"].BoolValue; if (Str.IsEmptyStr(vl.DefaultParam.StrValue)) { Con.WriteLine("IDs:"); foreach (BuildSoftware soft in softs) { if (soft.Os.IsWindows == false) { soft.SetBuildNumberVersionName(build, version, name, date); Con.WriteLine(" {0}", soft.IDString); Con.WriteLine(" - \"{0}\"", soft.OutputFileName); } } } else { string key = vl.DefaultParam.StrValue; bool all = false; if ("all".StartsWith(key, StringComparison.InvariantCultureIgnoreCase)) { all = true; } if ("clean".StartsWith(key, StringComparison.InvariantCultureIgnoreCase)) { // Delete the release directory Paths.DeleteAllReleaseTarGz(); Con.WriteLine("Clean completed."); return(0); } List <BuildSoftware> o = new List <BuildSoftware>(); foreach (BuildSoftware soft in softs) { soft.SetBuildNumberVersionName(build, version, name, date); if (soft.Os.IsWindows == false) { if (all || soft.IDString.IndexOf(key, StringComparison.InvariantCultureIgnoreCase) != -1) { o.Add(soft); } } } if (o.Count == 0) { throw new ApplicationException(string.Format("Software ID '{0}' not found.", key)); } else { if (all) { // Delete the release directory Paths.DeleteAllReleaseTarGz(); } else { IO.MakeDir(Paths.ReleaseDir); } if (serial) { // Build in series int i; for (i = 0; i < o.Count; i++) { Con.WriteLine("{0} / {1}: Executing for '{2}'...", i + 1, o.Count, o[i].IDString); BuildHelper.BuildMain(o[i], vl["DEBUG"].BoolValue); } } else if (o.Count == 1) { // To build BuildHelper.BuildMain(o[0], vl["DEBUG"].BoolValue); } else { // Make a child process build Process[] procs = new Process[o.Count]; int i; for (i = 0; i < o.Count; i++) { Con.WriteLine("{0} / {1}: Executing for '{2}'...", i + 1, o.Count, o[i].IDString); procs[i] = Kernel.Run(Env.ExeFileName, string.Format("/PAUSEIFERROR:{1} /DT:{2} /CMD:ReleaseUnix /DEBUG:{3} {0}", o[i].IDString, vl["IGNOREERROR"].BoolValue ? "no" : "yes", Str.DateTimeToStrShort(BuildSoftwareList.ListCreatedDateTime), vl["DEBUG"].BoolValue ? "yes" : "no") ); } Con.WriteLine("Waiting child processes..."); int numError = 0; for (i = 0; i < o.Count; i++) { procs[i].WaitForExit(); bool ok = procs[i].ExitCode == 0; if (ok == false) { numError++; } Con.WriteLine("{0} / {1} ({2}):", i + 1, o.Count, o[i].IDString); Con.WriteLine(" {0}", ok ? "Success" : "* Error *"); } Con.WriteLine(); if (numError != 0) { throw new ApplicationException(string.Format("{0} Errors.", numError)); } Con.WriteLine("No Errors."); } } } return(0); }