-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
190 lines (164 loc) · 9.01 KB
/
Program.cs
File metadata and controls
190 lines (164 loc) · 9.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
using BackupGitRepo.Extensions;
using LibGit2Sharp;
using System.Text;
using Utils;
namespace BackupGitRepo;
class Program {
static string sRepositoryDir = "", sBackupDir = "", sGitStatusFilePath = "";
static bool sSkipUntracked = false, sIncludeGitIgnored = false;
static void Main (string[] args) {
try {
var isUpdated = Task.Run (async () => await SelfUpdater.Run ("MetaNaveen", "BackupGitRepo", "BackupGitRepo.exe")).GetAwaiter ().GetResult ();
if (!isUpdated) throw new Exception ("Unknown reason.");
} catch (Exception ex) {
Console.WriteLine ($"Self update failed! with error '{ex.Message}'.\nRunning with the current version...");
}
var appInfo = AssemblyUtils.GetAssemblyVersion ();
if (string.IsNullOrEmpty (appInfo.Name)) appInfo.Name = "BackupGitRepo";
appInfo.Name += ".exe";
Console.WriteLine ($"App Version: {appInfo.Major}.{appInfo.Minor}\n");
if (args.Length == 0) {
Console.WriteLine ($"USAGE: {appInfo.Name} [-su | -ii] <RepoDirectoryPath> [<BackupDirectoryPath>]");
Environment.Exit (-1);
}
// -su - skipUntracked
// -ii - Include GitIgnored
if (args[0].StartsWith ("-su", StringComparison.OrdinalIgnoreCase)) {
args = args.Skip (1).ToArray ();
sSkipUntracked = true;
}
if (args[0].StartsWith ("-ii", StringComparison.OrdinalIgnoreCase)) {
args = args.Skip (1).ToArray ();
sIncludeGitIgnored = true;
}
sRepositoryDir = Path.GetFullPath (GetCurrentDirectoryOrArgument (args, 0));
// Validates repo dir
if (!Directory.Exists (Path.Combine (sRepositoryDir, ".git"))) {
Console.WriteLine ($"Could not find .git directory at given path. '{sRepositoryDir}'");
Environment.Exit (-1);
}
var repoName = Path.GetFileName (sRepositoryDir);
if (string.IsNullOrEmpty (repoName)) repoName = sRepositoryDir.GetParentOrDrivePath ();
using var repo = new Repository (sRepositoryDir); // Gets repo from the path to .git
sBackupDir = Path.GetFullPath (GetBackupDirectoryOrDefault (args, 1, repoName, repo.Head.FriendlyName));
// Validates backup dir
if (!sBackupDir.IsValidDirectoryPath ()) {
Console.WriteLine ($"Not a valid directory. '{sBackupDir}'");
Environment.Exit (-1);
}
// Checks if Repo and Backup dir are different
//if (string.Equals (sRepositoryDir, sBackupDir, StringComparison.OrdinalIgnoreCase)) {
// Console.WriteLine ($"Repo and Backup directories path should not be same!!!");
// Environment.Exit (-1);
//}
var commonPath = sBackupDir.GetCommonPath (sRepositoryDir);
// Takes subDirName\\backupFilename upto the datetime stamp.
var backupRelativeDir = sBackupDir[commonPath.Length..].TrimStart (Path.DirectorySeparatorChar)[..^2]; // Omits _1, _2, ...
Console.WriteLine ($"=> Repo Directory: {sRepositoryDir}");
Console.WriteLine ($"=> Backup Directory: {sBackupDir}");
Console.WriteLine ($"=> Backup Started...");
// Processing Repo to log changes and to take backup
bool isBackupSuccess = false;
try {
#region RepoChangeLog
var sbModified = new StringBuilder ();
var sbUntracked = new StringBuilder ();
// Retrieves git status without including .gitignored files
var files = repo.RetrieveStatus (new StatusOptions { IncludeIgnored = sIncludeGitIgnored, IncludeUntracked = true });
foreach (var file in files) {
var state = file.State;
var isUntracked = state.HasFlag (FileStatus.NewInWorkdir);
var s = GetFileStatusName (state); // Gets status name - New/Modified/Deleted/Renamed/TypeChanged
if (!file.FilePath.StartsWith (backupRelativeDir, StringComparison.OrdinalIgnoreCase)) {
if (isUntracked) {
sbUntracked.AppendLine ($"'{file.FilePath}'");
} else sbModified.AppendLine ($"'{file.FilePath}'");
}
}
var sb = new StringBuilder ();
sb.AppendLine ($"BRANCH: {repo.Head.FriendlyName}\n");
if (sbModified.Length > 0) {
sb.AppendLine ("CHANGES IN TRACKED FILES: ********************************************************");
sb.AppendLine (sbModified.ToString () + "\n");
}
if (sbUntracked.Length > 0) {
sb.AppendLine ("UNTRACKED NEW FILES/FOLDERS: ********************************************************");
sb.AppendLine (sbUntracked.ToString () + "\n");
}
File.WriteAllText (sGitStatusFilePath, sb.ToString ());
//Console.WriteLine (sb.ToString ());
#endregion
#region BackupRepoFiles
// Takes backup of the files
foreach (var item in files) {
if (item.State != FileStatus.Unaltered) { // git ignored files are not considered by default. // item.State != FileStatus.Ignored
// checks for files in the parent folder/subfolders.
var filePath = item.FilePath.NormalizePathSeparators ();
//Console.WriteLine ($"{item.State} - {filePath}");
if (!filePath.StartsWith (backupRelativeDir, StringComparison.OrdinalIgnoreCase)) {
if (sSkipUntracked && item.State.HasFlag (FileStatus.NewInWorkdir)) continue; // Skips untracked files if required
string srcPath = Path.Combine (sRepositoryDir, item.FilePath);
var isDir = Directory.Exists (srcPath);
if (!File.Exists (srcPath) && !isDir) continue; // checks if the file is not deleted
string destFilePath = Path.Combine (sBackupDir, item.FilePath);
var dirName = Path.GetDirectoryName (destFilePath) ?? ""; // gets directory of file. if directory, returns same directory's name
if (!string.IsNullOrEmpty (dirName)) Directory.CreateDirectory (dirName);
if (isDir) { // only for gitignored (folder level)
Console.WriteLine ($"+ Copied directory: {item.FilePath}");
foreach (var f in Directory.GetFiles (srcPath)) {
var fileName = Path.GetFileName (f);
var dest = Path.Combine (destFilePath, fileName);
var src = Path.Combine (srcPath, fileName);
File.Copy (src, dest, true);
}
} else {
File.Copy (srcPath, destFilePath, true);
Console.WriteLine ($"+ Copied file: {item.FilePath}");
}
}
}
}
#endregion
isBackupSuccess = true;
} catch (LibGit2Sharp.RepositoryNotFoundException ex) {
Console.WriteLine ($"RepositoryNotFoundException: {ex.Message}");
isBackupSuccess = false;
} catch (Exception ex) {
Console.WriteLine ($"Unknown Exception: {ex.Message}");
isBackupSuccess = false;
}
Console.WriteLine ($"=> Backup {(isBackupSuccess ? "completed." : "failed.")}");
Environment.Exit (0);
}
static string GetCurrentDirectoryOrArgument (string[] args, int index) {
return args.Length > index ? args[index] : Directory.GetCurrentDirectory ();
}
static string GetBackupDirectoryOrDefault (string[] args, int index, string repoName, string branchName) {
string dateSuffix = DateTime.Now.ToString ("yyyyMMdd");
string defaultBackupDir = "";
var isBackupDirArg = args.Length > index;
string backupDir = isBackupDirArg ? Path.GetFullPath (args[index]) : sRepositoryDir;
string backupFolderName = "";
int i = 1;
do {
backupFolderName = $"Backup_{repoName}_{branchName}_{dateSuffix}_{i++}";
defaultBackupDir = Path.Combine (backupDir, backupFolderName);
}
while (Directory.Exists (defaultBackupDir));
Directory.CreateDirectory (defaultBackupDir);
sGitStatusFilePath = Path.Combine (defaultBackupDir, backupFolderName + ".txt");
File.WriteAllText (sGitStatusFilePath, ""); // Creating file with empty content.
return defaultBackupDir;
}
/// <summary>Gets file status name w.r.t FileStatus enum flags.</summary>
static string GetFileStatusName (FileStatus fileStatus) {
return fileStatus switch {
_ when fileStatus.HasFlag (FileStatus.NewInWorkdir) => "[ADDED]",
_ when fileStatus.HasFlag (FileStatus.ModifiedInWorkdir) => "[MODIFIED]",
_ when fileStatus.HasFlag (FileStatus.RenamedInWorkdir) => "[RENAMED]",
_ when fileStatus.HasFlag (FileStatus.DeletedFromWorkdir) => "[DELETED]",
_ when fileStatus.HasFlag (FileStatus.TypeChangeInWorkdir) => "[TYPECHANGED]",
_ => string.Join (" | ", Enum.GetValues (typeof (FileStatus)).Cast<FileStatus> ().Where (f => fileStatus.HasFlag (f)).Select (f => f))
};
}
}