Example #1
0
            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);
            }
Example #2
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);
 }
Example #3
0
        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();
        }
Example #4
0
        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;
        }
Example #5
0
            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();
                });
            }
Example #6
0
 public RSyncDownloader(Repository repo)
 {
     this.repository = repo;
 }
Example #7
0
        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;
        }
Example #8
0
 // Returns true if this sync item is current on the given rootPath.
 public bool isCurrent(Repository repository)
 {
     return !isOutdated(repository);
 }
Example #9
0
            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;
            }
Example #10
0
            // 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);
            }
Example #11
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;
        }
Example #12
0
        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();
        }
Example #13
0
        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();
        }
Example #14
0
            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)
                            ));
                }
            }