public long SizeOnDisk(Repository repository) { long sz = 0; if (this.name.EndsWith("/")) { if (Directory.Exists(repository.RootPath + "/" + this.name)) sz += new DirectoryInfo(repository.RootPath + "/" + this.name).SizeOnDisk(); } else { var fileInfo = new FileInfo(repository.RootPath + "/" + this.name); if (fileInfo.Exists) sz += fileInfo.Length; // Check partial dir var partialInfo = new FileInfo(fileInfo.Directory.FullName + "/catflap.partials/" + fileInfo.Name); // Check the current-transfer temp dir for in-flight ransfers if (Directory.Exists(repository.TmpPath)) { sz += Directory.EnumerateFiles(repository.TmpPath). Where(x => new FileInfo(x).Name.ToLowerInvariant().StartsWith(fileInfo.Name.ToLowerInvariant())). Select(x => new FileInfo(x).Length).Sum(); } // Otherwise, check for partials else if (partialInfo.Exists) sz += partialInfo.Length; } return sz.Clamp(0); }
/* * Substitutable variables: * * %root% - the root directory (e.g. where catflap.exe is located) * %app% - the app directory, where catflap stores it's internal data (e.g. catflap.exe.catflap) * %user% - the stored user credential, if any */ private string SubstituteVars(Repository repository, string a) { return a. Replace("%app%", repository.AppPath). Replace("%root%", repository.RootPath). Replace("%user%", repository.Username); }
public LoginWindow(Repository r) { InitializeComponent(); ThemeManager.ChangeAppStyle(Application.Current, ThemeManager.Accents.First(x => x.Name == "Crimson"), ThemeManager.AppThemes.First(x => x.Name == "BaseLight")); repo = r; txtUser.Text = r.Username; txtPasswd.Text = r.Password; txtUser.Focus(); }
public TrustDBWindow(Repository r) { InitializeComponent(); Title = Text.t("pubkeywindow_window_title"); infotext.Text = Text.t("pubkeywindow_infotext"); btnGo.Content = Text.t("pubkeywindow_button_go_start"); ThemeManager.ChangeAppStyle(Application.Current, MainWindow.accentOK, ThemeManager.AppThemes.First(x => x.Name == "BaseLight")); repository = r; }
public async Task Run(Repository repository, string[] additionalArgs) { var cmd = SubstituteVars(repository, this.execute); var args = SubstituteVars(repository, this.arguments) + (" " + string.Join(" ", additionalArgs)).TrimEnd(' '); Process pProcess = new System.Diagnostics.Process(); pProcess.StartInfo.FileName = cmd; pProcess.StartInfo.UseShellExecute = this.shellExecute; if (pProcess.StartInfo.Verbs.Contains(this.verb)) pProcess.StartInfo.Verb = this.verb; pProcess.StartInfo.Arguments = args; pProcess.StartInfo.WorkingDirectory = repository.RootPath; await Task.Run(delegate() { pProcess.Start(); pProcess.WaitForExit(); }); }
public RSyncDownloader(Repository repo) { this.repository = repo; }
private async Task<bool> setup(string url) { url = url.Trim().TrimEnd('/') + "/"; if (!url.StartsWith("http://") && !url.StartsWith("https://")) url = "http://" + url; var fi = new FileInfo(Assembly.GetExecutingAssembly().Location); var rootPath = Directory.GetCurrentDirectory(); var appPath = rootPath + "\\" + fi.Name + ".catflap"; var repo = new Repository(url, rootPath, appPath); Manifest mf; try { mf = repo.AuthPolicy.Execute(() => repo.GetManifestFromRemote()); } catch (Exception ex) { MessageBox.Show(ex.Message, "Isso não parece ser um repositório válido"); Console.WriteLine(ex.ToString()); return false; } if (mf.warnWhenSetupWithoutFiles.Count() > 0) { var currentContents = Directory.GetFiles(rootPath).Select(x => new FileInfo(x).Name.ToLowerInvariant()); var diff = mf.warnWhenSetupWithoutFiles.Select(x => new FileInfo(x).Name.ToLowerInvariant()).Except(currentContents); if (diff.Count() > 0) { var setupAnyways = await this.ShowMessageAsync("Arquivos não encontrados?", "Este manifesto precisa rodar em um diretório que contém alguns " + "arquivos, mas você não possuí os seguintes:\n\n" + string.Join(", ", diff) + "\n\n" + "Ques continuar mesmo assim?", MessageDialogStyle.AffirmativeAndNegative); if (MessageDialogResult.Negative == setupAnyways) return false; } } if (mf.warnWhenSetupWithUntracked) { var currentContents = Directory.GetFiles(rootPath). Select(x => System.IO.Path.GetFileName(x)). Concat( Directory.GetDirectories(rootPath). Select(x => System.IO.Path.GetFileName(x)). Select(x => x + "/") ).Select(x => x.ToLower()); var skip = new string[] { fi.Name.ToLower(), fi.Name.ToLower() + ".catflap/", fi.Name.ToLower() + ".setup" }; var untracked = currentContents.Except(mf.sync.Select(x => x.name.ToLower())).Except(skip); if (untracked.Count() > 0) { var ret = MessageBox.Show( "ESTE REPOSITÓRIO RECOMANDA INICIAR EM UM DIRETÓRIO VAZIO.\n\n" + "Você está configurando um repositório que já contém alguns arquivos:\n\n" + String.Join("\n", untracked.Take(10)) + "\n..\n\n" + "Que continuar mesmo assim?", "Arquivos não rastreados no diretório, continuar?", MessageBoxButton.YesNo); if (ret == MessageBoxResult.No) return false; } } Directory.CreateDirectory(appPath); System.IO.File.WriteAllText(appPath + "\\catflap.json", JsonConvert.SerializeObject(mf)); var wantShortcut = await this.ShowMessageAsync("Criar um atalho na desktop?", "Você gostaria de criar um atalho na desktop?\n" + "Isso será perguntado somente uma vez. Futuramente, utilize o menu 'preferências'.", MessageDialogStyle.AffirmativeAndNegative); if (MessageDialogResult.Affirmative == wantShortcut) repo.MakeDesktopShortcut(); return true; }
// Returns true if this sync item is current on the given rootPath. public bool isCurrent(Repository repository) { return !isOutdated(repository); }
private bool isOutdated(Repository repository) { bool thisIsDirectory = this.name.EndsWith("/"); string path = repository.RootPath + "/" + this.name; SyncItem thisOld = repository.CurrentManifest.sync.Find(_f_old => _f_old.name.ToLowerInvariant() == this.name.ToLowerInvariant()); if (thisOld == null) return true; FileInfo fileInfo = new FileInfo(path); bool thisPathExists = (thisIsDirectory && new DirectoryInfo(path).Exists) || (!thisIsDirectory && fileInfo.Exists); // Special handling for delete syncitems: any existing item is outdated because // we need to delete it. if (this.type == "delete") if (this.ignoreExisting.GetValueOrDefault()) return false; else return thisPathExists; // Local data doesn't even exist. outdated. if (!thisPathExists) return true; // special sync item flag: ignore any existing data. if (this.ignoreExisting.GetValueOrDefault()) return false; // old manifest item has a revision, we have a revision, and it's a mismatch if (thisOld.revision > 0 && this.revision > 0 && this.revision != thisOld.revision) return true; // Timestamp mismatch - we're too old (or too young) if (Math.Abs((fileInfo.LastWriteTime - this.mtime).TotalSeconds) > 1) return true; // We can't possibly have enough data, size mismatch. if (SizeOnDisk(repository) < this.size) return true; if (thisIsDirectory) { var directoryElements = Utils.GetDirectoryElements(path); // Not enough files. if (directoryElements.Count() < this.count) return true; } return false; }
// Returns the number of bytes that need to be transferred AT THE VERY LEAST // to bring this sync item uptodate. This is used for estimating to-transfer // data. public long ToTransfer(Repository repository) { if (isCurrent(repository)) return 0; if (this.type == "delete") return 0; return (this.size - SizeOnDisk(repository)).Clamp(0); }
private async Task<bool> setup(string url) { url = url.Trim().TrimEnd('/') + "/"; if (!url.StartsWith("http://") && !url.StartsWith("https://")) url = "https://" + url; var fi = new FileInfo(Assembly.GetExecutingAssembly().Location); var rootPath = Directory.GetCurrentDirectory(); var appPath = rootPath + "\\" + fi.Name + ".catflap"; var repo = new Repository(url, rootPath, appPath); Manifest mf; try { mf = BusyWindow.WithBusyWindow(() => repo.AuthPolicy.Execute(() => repo.GetManifestFromRemote())); } catch (Exception ex) { MessageBox.Show(Text.t("setup_manifest_invalid_long", url, ex.Message), Text.t("setup_manifest_invalid")); return false; } if (mf.warnWhenSetupWithoutFiles.Count() > 0) { var currentContents = Directory.GetFiles(rootPath).Select(x => new FileInfo(x).Name.ToLowerInvariant()); var diff = mf.warnWhenSetupWithoutFiles.Select(x => new FileInfo(x).Name.ToLowerInvariant()).Except(currentContents); if (diff.Count() > 0) { var setupAnyways = await this.ShowMessageAsync(Text.t("setup_expected_missing"), Text.t("setup_expected_missing_long", string.Join(", ", diff)), MessageDialogStyle.AffirmativeAndNegative); if (MessageDialogResult.Negative == setupAnyways) return false; } } if (mf.warnWhenSetupWithUntracked) { var currentContents = Directory.GetFiles(rootPath). Select(x => System.IO.Path.GetFileName(x)). Concat( Directory.GetDirectories(rootPath). Select(x => System.IO.Path.GetFileName(x)). Select(x => x + "/") ).Select(x => x.ToLower()); var skip = new string[] { fi.Name.ToLower(), fi.Name.ToLower() + ".catflap/", fi.Name.ToLower() + ".setup" }; var untracked = currentContents.Except(mf.sync.Select(x => x.name.ToLower())).Except(skip); if (untracked.Count() > 0) { var ret = MessageBox.Show( Text.t("setup_warn_untracked_long", String.Join("\n", untracked.Take(10))), Text.t("setup_warn_untracked"), MessageBoxButton.YesNo); if (ret == MessageBoxResult.No) return false; } } Directory.CreateDirectory(appPath); System.IO.File.WriteAllText(appPath + "\\catflap.json", JsonConvert.SerializeObject(mf)); if (mf.runAction != null && mf.runAction.execute != "") { var wantShortcut = await this.ShowMessageAsync( Text.t("setup_shortcut_ask"), Text.t("setup_shortcut_ask_long"), MessageDialogStyle.AffirmativeAndNegative); if (MessageDialogResult.Affirmative == wantShortcut) repo.MakeDesktopShortcut(); } return true; }
public MainWindow() { InitializeComponent(); labelDownloadStatus.Text = ""; btnCancel.Visibility = System.Windows.Visibility.Hidden; var fi = new FileInfo(Assembly.GetExecutingAssembly().Location); rootPath = Directory.GetCurrentDirectory(); Log("%root% = " + rootPath); appPath = rootPath + "\\" + fi.Name + ".catflap"; Log("%app% = " + appPath); Directory.SetCurrentDirectory(rootPath); if (!File.Exists(appPath + "\\catflap.json")) { var sw = new SetupWindow(); if (!sw.SetupOk) { var ret = sw.ShowDialog(); if (!ret.Value) { Application.Current.Shutdown(); return; } } } Assembly assembly = Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); string major = String.Join(".", fvi.FileVersion.Split('.').Take(3)); string point = String.Join(".", fvi.FileVersion.Split('.').Skip(3)); foreach (string src in resourcesToPurge) { var x = appPath + "\\" + src; if (File.Exists(x)) { Log("Deleting obsolete bundled file: " + src); File.Delete(x); } } foreach (string src in resourcesToUnpack) { var dst = src; if (dst.EndsWith(".gz")) dst = dst.Substring(0, dst.Length - 3); if (!File.Exists(appPath + "\\" + dst) || File.GetLastWriteTime(appPath + "\\" + dst) != File.GetLastWriteTime(fi.FullName)) { Log("Extracting bundled file: " + src); App.ExtractResource(src, appPath + "\\" + dst); File.SetLastWriteTime(appPath + "\\" + dst, File.GetLastWriteTime(fi.FullName)); } } this.Activated += new EventHandler((o, ea) => { if (repository.LatestManifest != null) { repository.UpdateStatus(); this.SetGlobalStatus(); } }); this.KeyDown += new KeyEventHandler(async (o, kea) => { if (kea.Key == Key.F5) { await UpdateRootManifest(); repository.UpdateStatus(); this.SetGlobalStatus(); } }); this.repository = new Repository(rootPath, appPath); this.repository.OnDownloadStatusInfoChanged += OnDownloadStatusInfoChangedHandler; this.repository.OnDownloadMessage += (string message, bool show) => { if (show) labelDownloadStatus.Dispatcher.Invoke((Action)(() => labelDownloadStatus.Text = message.Trim())); Log(message); }; if (App.mArgs.Contains("-nolock")) { App.mArgs = App.mArgs.Where(x => x != "-nolock").ToArray(); IgnoreRepositoryLock = true; } if (App.mArgs.Contains("-simulate")) { repository.Simulate = true; } if (App.mArgs.Contains("-nocheck")) { App.mArgs = App.mArgs.Where(x => x != "-nocheck").ToArray(); this.repository.AlwaysAssumeCurrent = true; } if (App.mArgs.Contains("-run")) { App.mArgs = App.mArgs.Where(x => x != "-run").ToArray(); UpdateAndRun(false); } else if (App.mArgs.Contains("-runwait")) { App.mArgs = App.mArgs.Where(x => x != "-runwait").ToArray(); UpdateAndRun(false); } else UpdateRootManifest(); }
public MainWindow() { InitializeComponent(); btnVerify.Content = Text.t("mainwindow_button_verify"); btnOpenInExplorer.Content = Text.t("mainwindow_button_openfolder"); btnMakeShortcut.Content = Text.t("mainwindow_button_shortcut"); btnShowHideLog.Content = Text.t("mainwindow_button_more"); logFlyout.Header = Text.t("mainwindow_logflyout_header"); this.Visibility = System.Windows.Visibility.Collapsed; labelDownloadStatus.Text = ""; btnCancel.Visibility = System.Windows.Visibility.Hidden; var fi = new FileInfo(Assembly.GetExecutingAssembly().Location); string rootPath = Directory.GetCurrentDirectory(); string appPath = rootPath + "\\" + fi.Name + ".catflap"; Directory.SetCurrentDirectory(rootPath); Logger.OnLogMessage += (string msg) => logTextBox.Dispatcher.Invoke((Action)(() => { logTextBox.Text += msg; logTextBox.ScrollToEnd(); })); Assembly assembly = Assembly.GetExecutingAssembly(); FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); string major = String.Join(".", fvi.FileVersion.Split('.').Take(3)); string point = String.Join(".", fvi.FileVersion.Split('.').Skip(3)); btnHelp.Content = "catflap v" + major + (point == "0" ? "" : "." + point); Logger.Info("Version: " + btnHelp.Content); if (!File.Exists(appPath + "\\catflap.json")) { Logger.Info("First time setup."); var sw = new SetupWindow(); if (!sw.SetupOk) { var ret = sw.ShowDialog(); if (!ret.Value) { Application.Current.Shutdown(); return; } } } EmbeddedResources.Update(appPath); this.Activated += new EventHandler((o, ea) => { if (repository.LatestManifest != null) { repository.UpdateStatus(); this.RefreshProgress(UIState.Unchanged); } }); this.KeyDown += new KeyEventHandler(async (o, kea) => { if (kea.Key == Key.F5 && cts == null) { await UpdateRootManifest(); repository.UpdateStatus(); this.RefreshProgress(UIState.OK); } }); this.repository = new Repository(rootPath, appPath); if (File.Exists(appPath + "/log.txt")) File.Delete(appPath + "/log.txt"); if (appPath != null && Directory.Exists(appPath)) Logger.OnLogMessage += (string msg) => { if (msg != null) try { System.IO.File.AppendAllText(appPath + "/log.txt", msg); } catch (IOException) { } // Cannot write log file. Weird but nothing to be done about it. }; this.repository.OnDownloadStatusInfoChanged += OnDownloadStatusInfoChangedHandler; this.repository.OnDownloadMessage += (string message, bool show) => { if (show) labelDownloadStatus.Dispatcher.Invoke((Action)(() => labelDownloadStatus.Text = message.Trim())); Logger.Info(message); }; Logger.Info("argv: " + String.Join(" ", App.mArgs)); if (App.mArgs.Contains("-nolock")) { App.mArgs = App.mArgs.Where(x => x != "-nolock").ToArray(); IgnoreRepositoryLock = true; } if (App.mArgs.Contains("-simulate")) { repository.Simulate = true; } if (App.mArgs.Contains("-nocheck")) { App.mArgs = App.mArgs.Where(x => x != "-nocheck").ToArray(); this.repository.AlwaysAssumeCurrent = true; } if (App.mArgs.Contains("-fixperm")) { if (!Utils.IsUserAdministrator()) { MessageBox.Show("-fixperm requires Administator privileges, but " + "I can't request those myself.\n\nTry 'Run as administrator' with a shortcut."); } else if (MessageBox.Show( "This resets all permissions on the current repository to the currently logged in user, " + "removes all custom object ACLs and only allows inherited access rights " + "(those of the parent directory " + Directory.GetParent(rootPath) + ") to apply.\n\n" + "!! This is a destructive operation and cannot be undone.\n" + "!! This will not touch any files outside of the repository root " + rootPath + ".\n\n" + "Continue?", "Force-reset permissions on complete repository?", MessageBoxButton.OKCancel) == MessageBoxResult.OK) { Utils.FixPermissions(rootPath); MessageBox.Show("All done. Exiting."); } Application.Current.Shutdown(); } else if (App.mArgs.Contains("-run")) { App.mArgs = App.mArgs.Where(x => x != "-run").ToArray(); UpdateAndRun(false); } else if (App.mArgs.Contains("-runwait")) { App.mArgs = App.mArgs.Where(x => x != "-runwait").ToArray(); UpdateAndRun(false); } else UpdateRootManifest(); }
private bool isOutdated(Repository repository) { if (this.name.EndsWith("/")) { var directoryElements = Utils.GetDirectoryElements(repository.RootPath + "/" + this.name); // Always check dirs that .. return (this.type == "rsync" && ( // Always check dirs that .. // don't exist locally yet !Directory.Exists(repository.RootPath + "/" + this.name) || (!this.ignoreExisting.GetValueOrDefault() && ( // are not young enough mtime Math.Abs((new FileInfo(repository.RootPath + "/" + this.name).LastWriteTime - this.mtime).TotalSeconds) > 1 || // have mismatching item count directoryElements.Count() < this.count || // are not big enough directoryElements.Sum(file => file.Length) < this.size )) )) || (this.type == "delete" && ( Directory.Exists(repository.RootPath + "/" + this.name) )); } else { return (this.type == "rsync" && ( !File.Exists(repository.RootPath + "/" + this.name) || (!this.ignoreExisting.GetValueOrDefault() && ( (this.mtime != null && Math.Abs((new FileInfo(repository.RootPath + "/" + this.name).LastWriteTime - this.mtime).TotalSeconds) > 1) || (new FileInfo(repository.RootPath + "/" + this.name).Length != this.size) )) )) || (this.type == "delete" && ( File.Exists(repository.RootPath + "/" + this.name) )); } }