예제 #1
0
 public CliPatcherInitVM(ProfileVM profile)
     : base(profile)
 {
     Patcher = new CliPatcherVM(profile);
     _CanCompleteConfiguration = Patcher.WhenAnyValue(x => x.PathToExecutable.ErrorState)
                                 .Cast <ErrorResponse, ErrorResponse>()
                                 .ToGuiProperty(this, nameof(CanCompleteConfiguration), ErrorResponse.Success);
 }
예제 #2
0
        public PatcherVM(ProfileVM parent, PatcherSettings?settings)
        {
            DisplayedObject = this;
            InternalID      = Interlocked.Increment(ref NextID);
            ErrorVM         = new ErrorVM("Error", backAction: () =>
            {
                DisplayedObject = this;
            });

            Profile     = parent;
            _IsSelected = this.WhenAnyValue(x => x.Profile.SelectedPatcher)
                          .Select(x => x == this)
                          .ToGuiProperty(this, nameof(IsSelected));

            // Set to settings
            IsOn     = settings?.On ?? false;
            Nickname = settings?.Nickname ?? string.Empty;

            DeleteCommand = ReactiveCommand.Create(() =>
            {
                parent.Config.MainVM.TargetConfirmation = new ConfirmationActionVM(
                    "Confirm",
                    $"Are you sure you want to delete {DisplayName}?",
                    Delete);
            });

            this.WhenAnyValue(x => x.IsSelected)
            .DistinctUntilChanged()
            .Where(x => x)
            .Subscribe(_ =>
            {
                DisplayedObject = this;
            })
            .DisposeWith(this);

            this.WhenAnyValue(x => x.State.RunnableState)
            .Subscribe(state =>
            {
                if (state.Failed)
                {
                    ErrorVM.String = state.Reason;
                }
                else
                {
                    ErrorVM.String = null;
                }
            })
            .DisposeWith(this);
        }
예제 #3
0
        public SolutionPatcherInitVM(ProfileVM profile)
            : base(profile)
        {
            MVM           = profile.Config.MainVM;
            OpenCodeAfter = profile.Config.MainVM.Settings.OpenIdeAfterCreating;
            New.ParentDirPath.TargetPath = profile.Config.MainVM.Settings.MainRepositoryFolder;

            var initializer = this.WhenAnyValue(x => x.SelectedIndex)
                              .Select <int, ASolutionInitializer>(x =>
            {
                return(((SolutionInitType)x) switch
                {
                    SolutionInitType.ExistingSolution => ExistingSolution,
                    SolutionInitType.New => New,
                    SolutionInitType.ExistingProject => ExistingProject,
                    _ => throw new NotImplementedException(),
                });
            })
예제 #4
0
        public CliPatcherVM(ProfileVM parent, CliPatcherSettings?settings = null)
            : base(parent, settings)
        {
            CopyInSettings(settings);
            _DisplayName = this.WhenAnyValue(
                x => x.Nickname,
                x => x.PathToExecutable.TargetPath,
                (Nickname, PathToExecutable) => (Nickname, PathToExecutable))
                           .Select(x =>
            {
                if (string.IsNullOrWhiteSpace(x.Nickname))
                {
                    try
                    {
                        return(Path.GetFileNameWithoutExtension(x.PathToExecutable));
                    }
                    catch (Exception)
                    {
                        return("<Naming Error>");
                    }
                }
                else
                {
                    return(x.Nickname);
                }
            })
                           .ToGuiProperty <string>(this, nameof(DisplayName));

            _State = this.WhenAnyValue(x => x.PathToExecutable.ErrorState)
                     .Select(e =>
            {
                return(new ConfigurationState()
                {
                    IsHaltingError = !e.Succeeded,
                    RunnableState = e
                });
            })
                     .ToGuiProperty <ConfigurationState>(this, nameof(State), new ConfigurationState(ErrorResponse.Fail("Evaluating"))
            {
                IsHaltingError = false
            });
        }
예제 #5
0
        public NewProfileVM(ConfigurationVM config, Action <ProfileVM> postRun)
        {
            ReleaseOptions.AddRange(EnumExt.GetValues <GameRelease>());

            this.WhenAnyValue(x => x.SelectedGame)
            .Subscribe(game =>
            {
                if (game == null)
                {
                    return;
                }
                var profile = new ProfileVM(config, game.Value)
                {
                    Nickname = Nickname
                };
                config.Profiles.AddOrUpdate(profile);
                postRun(profile);
            })
            .DisposeWith(this);
        }
예제 #6
0
        public CodeSnippetPatcherVM(ProfileVM parent, CodeSnippetPatcherSettings?settings = null)
            : base(parent, settings)
        {
            CopyInSettings(settings);
            _DisplayName = this.WhenAnyValue(x => x.Nickname)
                           .Select(x =>
            {
                if (string.IsNullOrWhiteSpace(x))
                {
                    return("<No Name>");
                }
                else
                {
                    return(x);
                }
            })
                           .ToGuiProperty <string>(this, nameof(DisplayName), string.Empty);

            IObservable <(MemoryStream?AssemblyStream, EmitResult?CompileResults, Exception?Exception)> compileResults =
                Observable.Merge(
                    // Anytime code changes, wipe and mark as "compiling"
                    this.WhenAnyValue(x => x.Code)
                    .Select(_ => (default(MemoryStream?), default(EmitResult?), default(Exception?))),
                    // Start actual compiling task,
                    this.WhenAnyValue(x => x.Code)
                    // Throttle input
                    .Throttle(TimeSpan.FromMilliseconds(350), RxApp.MainThreadScheduler)
                    // Stick on background thread
                    .ObserveOn(RxApp.TaskpoolScheduler)
                    .Select(code =>
            {
                CancellationTokenSource cancel = new CancellationTokenSource();
                try
                {
                    var emit = CodeSnippetPatcherRun.Compile(
                        parent.Release,
                        ID,
                        code,
                        cancel.Token,
                        out var assembly);
                    return(emit.Success ? assembly : default, emit, default(Exception?));
예제 #7
0
        public PatcherVM(ProfileVM parent, PatcherSettings?settings)
        {
            InternalID = Interlocked.Increment(ref NextID);

            Profile     = parent;
            _IsSelected = this.WhenAnyValue(x => x.Profile.Config.SelectedPatcher)
                          .Select(x => x == this)
                          .ToGuiProperty(this, nameof(IsSelected));

            // Set to settings
            IsOn     = settings?.On ?? false;
            Nickname = settings?.Nickname ?? string.Empty;

            DeleteCommand = ReactiveCommand.Create(() =>
            {
                parent.Config.MainVM.ActiveConfirmation = new ConfirmationActionVM(
                    "Confirm",
                    $"Are you sure you want to delete {DisplayName}?",
                    Delete);
            });
        }
예제 #8
0
        public SolutionPatcherVM(ProfileVM parent, SolutionPatcherSettings?settings = null)
            : base(parent, settings)
        {
            CopyInSettings(settings);
            SolutionPath.Filters.Add(new CommonFileDialogFilter("Solution", ".sln"));
            SelectedProjectPath.Filters.Add(new CommonFileDialogFilter("Project", ".csproj"));

            _DisplayName = Observable.CombineLatest(
                this.WhenAnyValue(x => x.Nickname),
                this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath)
                .StartWith(settings?.ProjectSubpath ?? string.Empty),
                (nickname, path) =>
            {
                if (!string.IsNullOrWhiteSpace(nickname))
                {
                    return(nickname);
                }
                try
                {
                    var name = Path.GetFileName(Path.GetDirectoryName(path));
                    if (string.IsNullOrWhiteSpace(name))
                    {
                        return(string.Empty);
                    }
                    return(name);
                }
                catch (Exception)
                {
                    return(string.Empty);
                }
            })
                           .ToProperty(this, nameof(DisplayName), Nickname);

            AvailableProjects = SolutionPatcherConfigLogic.AvailableProject(
                this.WhenAnyValue(x => x.SolutionPath.TargetPath))
                                .ObserveOnGui()
                                .ToObservableCollection(this);

            var projPath = SolutionPatcherConfigLogic.ProjectPath(
                solutionPath: this.WhenAnyValue(x => x.SolutionPath.TargetPath),
                projectSubpath: this.WhenAnyValue(x => x.ProjectSubpath));

            projPath
            .Subscribe(p => SelectedProjectPath.TargetPath = p)
            .DisposeWith(this);

            _State = Observable.CombineLatest(
                this.WhenAnyValue(x => x.SolutionPath.ErrorState),
                this.WhenAnyValue(x => x.SelectedProjectPath.ErrorState),
                this.WhenAnyValue(x => x.Profile.Config.MainVM)
                .Select(x => x.DotNetSdkInstalled)
                .Switch(),
                (sln, proj, dotnet) =>
            {
                if (sln.Failed)
                {
                    return(new ConfigurationState(sln));
                }
                if (!dotnet.Acceptable)
                {
                    return(new ConfigurationState(ErrorResponse.Fail("No dotnet SDK installed")));
                }
                return(new ConfigurationState(proj));
            })
                     .ToGuiProperty <ConfigurationState>(this, nameof(State), new ConfigurationState(ErrorResponse.Fail("Evaluating"))
            {
                IsHaltingError = false
            });

            OpenSolutionCommand = ReactiveCommand.Create(
                canExecute: this.WhenAnyValue(x => x.SolutionPath.InError)
                .Select(x => !x),
                execute: () =>
            {
                try
                {
                    Process.Start(new ProcessStartInfo(SolutionPath.TargetPath)
                    {
                        UseShellExecute = true,
                    });
                }
                catch (Exception ex)
                {
                    Log.Logger.Error(ex, $"Error opening solution: {SolutionPath.TargetPath}");
                }
            });

            var metaPath = this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath)
                           .Select(projPath =>
            {
                try
                {
                    return(Path.Combine(Path.GetDirectoryName(projPath) !, Constants.MetaFileName));
                }
                catch (Exception)
                {
                    return(string.Empty);
                }
            })
                           .Replay(1)
                           .RefCount();

            // Set up meta file sync
            metaPath
            .Select(path =>
            {
                return(Noggog.ObservableExt.WatchFile(path)
                       .StartWith(Unit.Default)
                       .Throttle(TimeSpan.FromMilliseconds(500), RxApp.MainThreadScheduler)
                       .Select(_ =>
                {
                    if (!File.Exists(path))
                    {
                        return default;
                    }
                    try
                    {
                        return JsonConvert.DeserializeObject <PatcherCustomization>(
                            File.ReadAllText(path),
                            Execution.Constants.JsonSettings);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex, "Error reading in meta");
                    }
                    return default(PatcherCustomization?);
                }));
            })
            .Switch()
            .DistinctUntilChanged()
            .ObserveOnGui()
            .Subscribe(info =>
            {
                if (info == null)
                {
                    return;
                }
                if (info.Nickname != null)
                {
                    this.Nickname = info.Nickname;
                }
                this.LongDescription  = info.LongDescription ?? string.Empty;
                this.ShortDescription = info.OneLineDescription ?? string.Empty;
                this.Visibility       = info.Visibility;
                this.Versioning       = info.PreferredAutoVersioning;
                this.RequiredMods.SetTo(info.RequiredMods
                                        .SelectWhere(x => TryGet <ModKey> .Create(ModKey.TryFromNameAndExtension(x, out var modKey), modKey))
                                        .Select(m => new ModKeyItemViewModel(m)));
            })
            .DisposeWith(this);

            Observable.CombineLatest(
                this.WhenAnyValue(x => x.DisplayName),
                this.WhenAnyValue(x => x.ShortDescription),
                this.WhenAnyValue(x => x.LongDescription),
                this.WhenAnyValue(x => x.Visibility),
                this.WhenAnyValue(x => x.Versioning),
                this.RequiredMods
                .ToObservableChangeSet()
                .Transform(x => x.ModKey)
                .AddKey(x => x)
                .Sort(ModKey.Alphabetical, SortOptimisations.ComparesImmutableValuesOnly, resetThreshold: 0)
                .QueryWhenChanged()
                .Select(x => x.Items)
                .StartWith(Enumerable.Empty <ModKey>()),
                metaPath,
                (nickname, shortDesc, desc, visibility, versioning, reqMods, meta) => (nickname, shortDesc, desc, visibility, versioning, reqMods: reqMods.Select(x => x.FileName).OrderBy(x => x).ToArray(), meta))
            .DistinctUntilChanged()
            .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler)
            .Skip(1)
            .Subscribe(x =>
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(x.meta))
                    {
                        return;
                    }
                    File.WriteAllText(x.meta,
                                      JsonConvert.SerializeObject(
                                          new PatcherCustomization()
                    {
                        OneLineDescription      = x.shortDesc,
                        LongDescription         = x.desc,
                        Visibility              = x.visibility,
                        Nickname                = x.nickname,
                        PreferredAutoVersioning = x.versioning,
                        RequiredMods            = x.reqMods
                    },
                                          Formatting.Indented,
                                          Execution.Constants.JsonSettings));
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Error writing out meta");
                }
            })
            .DisposeWith(this);

            ReloadAutogeneratedSettingsCommand = ReactiveCommand.Create(() => { });
            PatcherSettings = new PatcherSettingsVM(
                Logger,
                this,
                projPath
                .Merge(ReloadAutogeneratedSettingsCommand.EndingExecution()
                       .WithLatestFrom(projPath, (_, p) => p))
                .Select(p => (GetResponse <string> .Succeed(p), default(string?))),
                needBuild: true)
                              .DisposeWith(this);
        }
예제 #9
0
        public GitPatcherInitVM(ProfileVM profile)
            : base(profile)
        {
            Patcher = new GitPatcherVM(profile);

            _CanCompleteConfiguration = this.WhenAnyValue(x => x.Patcher.RepoClonesValid)
                                        .Select(x => ErrorResponse.Create(x))
                                        .ToGuiProperty(this, nameof(CanCompleteConfiguration), ErrorResponse.Success);

            PatcherRepos = Observable.Return(Unit.Default)
                           .ObserveOn(RxApp.TaskpoolScheduler)
                           .SelectTask(async _ =>
            {
                try
                {
                    var localRepoPath = await GitUtility.CheckOrCloneRepo(
                        GetResponse <string> .Succeed("https://github.com/Mutagen-Modding/Synthesis.Registry"),
                        Paths.RegistryFolder,
                        Log.Logger.Error,
                        CancellationToken.None);
                    if (localRepoPath.Failed)
                    {
                        Error = localRepoPath;
                        return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
                    }
                    using var repo = new Repository(localRepoPath.Value.Local);

                    var master = repo.Branches.Where(b => b.IsCurrentRepositoryHead).FirstOrDefault();
                    if (master == null)
                    {
                        Error = ErrorResponse.Fail("Could not find master branch");
                        Log.Logger.Error(Error.Reason);
                        return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
                    }
                    repo.Reset(ResetMode.Hard, repo.Branches[$"{master.RemoteName}/{master.FriendlyName}"].Tip);

                    var listingPath = Path.Combine(repo.Info.WorkingDirectory, Constants.AutomaticListingFileName);
                    if (!File.Exists(listingPath))
                    {
                        Error = ErrorResponse.Fail("Could not locate listing file");
                        Log.Logger.Error(Error.Reason);
                        return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
                    }
                    var settings = new JsonSerializerOptions();
                    settings.Converters.Add(new JsonStringEnumConverter());
                    var customization = JsonSerializer.Deserialize <MutagenPatchersListing>(File.ReadAllText(listingPath), settings) !;
                    return(customization.Repositories
                           .NotNull()
                           .SelectMany(repo =>
                    {
                        var repoVM = new RepositoryStoreListingVM(repo);
                        return repo.Patchers
                        .Select(p =>
                        {
                            return new PatcherStoreListingVM(this, p, repoVM);
                        });
                    })
                           .AsObservableChangeSet());
                }
                catch (Exception ex)
                {
                    Log.Logger.Error(ex, "Error downloading patcher listing");
                    Error = ErrorResponse.Fail(ex);
                }
                return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
            })
                           .Switch()
                           .Sort(Comparer <PatcherStoreListingVM> .Create((x, y) => x.Name.CompareTo(y.Name)))
                           .Filter(this.WhenAnyValue(x => x.ShowAll)
                                   .DistinctUntilChanged()
                                   .Select(show => new Func <PatcherStoreListingVM, bool>(
                                               (p) =>
            {
                if (p.Raw.Customization?.Visibility is VisibilityOptions.Visible)
                {
                    return(true);
                }
                else if (p.Raw.Customization?.Visibility is VisibilityOptions.IncludeButHide)
                {
                    return(show);
                }
                else if (p.Raw.Customization?.Visibility is VisibilityOptions.Exclude)
                {
                    return(false);                                                                               // just in case.
                }
                else
                {
                    return(true);
                }
            })))
                           .Filter(this.WhenAnyValue(x => x.Search)
                                   .Debounce(TimeSpan.FromMilliseconds(350), RxApp.MainThreadScheduler)
                                   .Select(x => x.Trim())
                                   .DistinctUntilChanged()
                                   .Select(search =>
            {
                if (string.IsNullOrWhiteSpace(search))
                {
                    return(new Func <PatcherStoreListingVM, bool>(_ => true));
                }
                return(new Func <PatcherStoreListingVM, bool>(
                           (p) =>
                {
                    if (p.Name.Contains(search, StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    if (p.Raw.Customization?.OneLineDescription?.Contains(search, StringComparison.OrdinalIgnoreCase) ?? false)
                    {
                        return true;
                    }
                    return false;
                }));
            }))
                           .ToObservableCollection(this);

            OpenPopulationInfoCommand = ReactiveCommand.Create(() => Utility.NavigateToPath(Constants.ListingRepositoryAddress));
            ClearSearchCommand        = ReactiveCommand.Create(() => Search = string.Empty);
        }
예제 #10
0
 public PatcherInitVM(ProfileVM profile)
 {
     Profile = profile;
 }
예제 #11
0
        public PatchersRunVM(ConfigurationVM parent, ProfileVM profile)
        {
            Config         = parent;
            RunningProfile = profile;
            Patchers.AddOrUpdate(RunningProfile.Patchers.Items
                                 .Where(x => x.IsOn)
                                 .Select(p => p.ToRunner(this)));
            PatchersDisplay = Patchers.Connect()
                              .ToObservableCollection(this);
            if (parent.SelectedPatcher != null &&
                Patchers.TryGetValue(parent.SelectedPatcher.InternalID, out var run))
            {
                SelectedPatcher = run;
            }

            BackCommand = ReactiveCommand.Create(() =>
            {
                parent.SelectedPatcher    = SelectedPatcher?.Config;
                parent.MainVM.ActivePanel = parent;
            },
                                                 canExecute: this.WhenAnyValue(x => x.Running)
                                                 .Select(running => !running));
            CancelCommand = ReactiveCommand.CreateFromTask(
                execute: Cancel,
                canExecute: this.WhenAnyValue(x => x.Running));

            _reporter.Overall
            .ObserveOnGui()
            .Subscribe(ex =>
            {
                Log.Logger.Error(ex, "Error while running patcher pipeline");
                ResultError = ex;
            })
            .DisposeWith(this);
            _reporter.PrepProblem
            .Select(data => (data, type: "prepping"))
            .Merge(_reporter.RunProblem
                   .Select(data => (data, type: "running")))
            .ObserveOnGui()
            .Subscribe(i =>
            {
                var vm          = Patchers.Get(i.data.Key);
                vm.State        = GetResponse <RunState> .Fail(RunState.Error, i.data.Error);
                SelectedPatcher = vm;
                Log.Logger
                .ForContext(nameof(PatcherVM.DisplayName), i.data.Run.Name)
                .Error(i.data.Error, $"Error while prepping {i.type}");
            })
            .DisposeWith(this);
            _reporter.Starting
            .ObserveOnGui()
            .Subscribe(i =>
            {
                var vm   = Patchers.Get(i.Key);
                vm.State = GetResponse <RunState> .Succeed(RunState.Started);
                Log.Logger
                .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name)
                .Information($"Starting");
            })
            .DisposeWith(this);
            _reporter.RunSuccessful
            .ObserveOnGui()
            .Subscribe(i =>
            {
                var vm   = Patchers.Get(i.Key);
                vm.State = GetResponse <RunState> .Succeed(RunState.Finished);
                Log.Logger
                .ForContext(nameof(PatcherVM.DisplayName), i.Run.Name)
                .Information("Finished {RunTime}", vm.RunTime);
            })
            .DisposeWith(this);
            _reporter.Output
            .Subscribe(s =>
            {
                Log.Logger
                .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name)
                .Information(s.String);
            })
            .DisposeWith(this);
            _reporter.Error
            .Subscribe(s =>
            {
                Log.Logger
                .ForContextIfNotNull(nameof(PatcherVM.DisplayName), s.Run?.Name)
                .Error(s.String);
            })
            .DisposeWith(this);

            // Clear selected patcher on showing error
            this.ShowOverallErrorCommand.StartingExecution()
            .Subscribe(_ => this.SelectedPatcher = null)
            .DisposeWith(this);

            _DetailDisplay = Observable.Merge(
                this.WhenAnyValue(x => x.SelectedPatcher)
                .Select(i => i as object),
                this.ShowOverallErrorCommand.EndingExecution()
                .Select(_ => ResultError == null ? null : new OverallErrorVM(ResultError)))
                             .ToGuiProperty(this, nameof(DetailDisplay));
        }
예제 #12
0
        public SolutionPatcherVM(ProfileVM parent, SolutionPatcherSettings?settings = null)
            : base(parent, settings)
        {
            CopyInSettings(settings);
            SolutionPath.Filters.Add(new CommonFileDialogFilter("Solution", ".sln"));
            SelectedProjectPath.Filters.Add(new CommonFileDialogFilter("Project", ".csproj"));

            _DisplayName = Observable.CombineLatest(
                this.WhenAnyValue(x => x.Nickname),
                this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath)
                .StartWith(settings?.ProjectSubpath ?? string.Empty),
                (nickname, path) =>
            {
                if (!string.IsNullOrWhiteSpace(nickname))
                {
                    return(nickname);
                }
                try
                {
                    var name = Path.GetFileName(Path.GetDirectoryName(path));
                    if (string.IsNullOrWhiteSpace(name))
                    {
                        return(string.Empty);
                    }
                    return(name);
                }
                catch (Exception)
                {
                    return(string.Empty);
                }
            })
                           .ToProperty(this, nameof(DisplayName), Nickname);

            AvailableProjects = SolutionPatcherConfigLogic.AvailableProject(
                this.WhenAnyValue(x => x.SolutionPath.TargetPath))
                                .ObserveOnGui()
                                .ToObservableCollection(this);

            var projPath = SolutionPatcherConfigLogic.ProjectPath(
                solutionPath: this.WhenAnyValue(x => x.SolutionPath.TargetPath),
                projectSubpath: this.WhenAnyValue(x => x.ProjectSubpath));

            projPath
            .Subscribe(p => SelectedProjectPath.TargetPath = p)
            .DisposeWith(this);

            _State = Observable.CombineLatest(
                this.WhenAnyValue(x => x.SolutionPath.ErrorState),
                this.WhenAnyValue(x => x.SelectedProjectPath.ErrorState),
                this.WhenAnyValue(x => x.Profile.Config.MainVM)
                .Select(x => x.DotNetSdkInstalled)
                .Switch(),
                (sln, proj, dotnet) =>
            {
                if (sln.Failed)
                {
                    return(new ConfigurationState(sln));
                }
                if (dotnet == null)
                {
                    return(new ConfigurationState(ErrorResponse.Fail("No dotnet SDK installed")));
                }
                return(new ConfigurationState(proj));
            })
                     .ToGuiProperty <ConfigurationState>(this, nameof(State), new ConfigurationState(ErrorResponse.Fail("Evaluating"))
            {
                IsHaltingError = false
            });

            OpenSolutionCommand = ReactiveCommand.Create(
                canExecute: this.WhenAnyValue(x => x.SolutionPath.InError)
                .Select(x => !x),
                execute: () =>
            {
                try
                {
                    Process.Start(new ProcessStartInfo(SolutionPath.TargetPath)
                    {
                        UseShellExecute = true,
                    });
                }
                catch (Exception ex)
                {
                    Log.Logger.Error(ex, $"Error opening solution: {SolutionPath.TargetPath}");
                }
            });

            var metaPath = this.WhenAnyValue(x => x.SelectedProjectPath.TargetPath)
                           .Select(projPath =>
            {
                try
                {
                    return(Path.Combine(Path.GetDirectoryName(projPath) !, Constants.MetaFileName));
                }
                catch (Exception)
                {
                    return(string.Empty);
                }
            })
                           .Replay(1)
                           .RefCount();

            // Set up meta file sync
            metaPath
            .Select(path =>
            {
                return(Noggog.ObservableExt.WatchFile(path)
                       .StartWith(Unit.Default)
                       .Select(_ =>
                {
                    try
                    {
                        return JsonConvert.DeserializeObject <PatcherCustomization>(
                            File.ReadAllText(path),
                            Execution.Constants.JsonSettings);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex, "Error reading in meta");
                    }
                    return default(PatcherCustomization?);
                }));
            })
            .Switch()
            .DistinctUntilChanged()
            .ObserveOnGui()
            .Subscribe(info =>
            {
                if (info == null)
                {
                    return;
                }
                if (info.Nickname != null)
                {
                    this.Nickname = info.Nickname;
                }
                this.LongDescription  = info.LongDescription ?? string.Empty;
                this.ShortDescription = info.OneLineDescription ?? string.Empty;
                this.Visibility       = info.Visibility;
                this.Versioning       = info.PreferredAutoVersioning;
            })
            .DisposeWith(this);

            Observable.CombineLatest(
                this.WhenAnyValue(x => x.DisplayName),
                this.WhenAnyValue(x => x.ShortDescription),
                this.WhenAnyValue(x => x.LongDescription),
                this.WhenAnyValue(x => x.Visibility),
                this.WhenAnyValue(x => x.Versioning),
                metaPath,
                (nickname, shortDesc, desc, visibility, versioning, meta) => (nickname, shortDesc, desc, visibility, versioning, meta))
            .DistinctUntilChanged()
            .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler)
            .Skip(1)
            .Subscribe(x =>
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(x.meta))
                    {
                        return;
                    }
                    File.WriteAllText(x.meta,
                                      JsonConvert.SerializeObject(
                                          new PatcherCustomization()
                    {
                        OneLineDescription      = x.shortDesc,
                        LongDescription         = x.desc,
                        Visibility              = x.visibility,
                        Nickname                = x.nickname,
                        PreferredAutoVersioning = x.versioning
                    },
                                          Formatting.Indented,
                                          Execution.Constants.JsonSettings));
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Error writing out meta");
                }
            })
            .DisposeWith(this);
        }
예제 #13
0
        public GitPatcherInitVM(ProfileVM profile)
            : base(profile)
        {
            Patcher = new GitPatcherVM(profile);
            this.CompositeDisposable.Add(Patcher);

            _CanCompleteConfiguration = this.WhenAnyValue(x => x.Patcher.State)
                                        .Select(x => x.RunnableState)
                                        .ToGuiProperty(this, nameof(CanCompleteConfiguration), ErrorResponse.Success);

            PatcherRepos = Observable.Return(Unit.Default)
                           .ObserveOn(RxApp.TaskpoolScheduler)
                           .SelectTask(async _ =>
            {
                try
                {
                    var gitHubClient         = new GitHubClient(new ProductHeaderValue("Synthesis"));
                    gitHubClient.Credentials = new Credentials("9b58542a2ca303d7ced129cc404191f8eea519f7");
                    var content = await gitHubClient.Repository.Content.GetAllContents("Noggog", "Synthesis.Registry", Constants.AutomaticListingFileName);
                    if (content.Count != 1)
                    {
                        return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
                    }
                    var customization = JsonSerializer.Deserialize <MutagenPatchersListing>(content[0].Content);
                    return(customization.Repositories
                           .NotNull()
                           .SelectMany(repo =>
                    {
                        var repoVM = new RepositoryStoreListingVM(repo);
                        return repo.Patchers
                        .Select(p =>
                        {
                            return new PatcherStoreListingVM(this, p, repoVM);
                        });
                    })
                           .AsObservableChangeSet());
                }
                catch (Exception ex)
                {
                    Log.Logger.Error(ex, "Error downloading patcher listing");
                    Error = ErrorResponse.Fail(ex);
                }
                return(Observable.Empty <IChangeSet <PatcherStoreListingVM> >());
            })
                           .Switch()
                           .Sort(Comparer <PatcherStoreListingVM> .Create((x, y) => x.Name.CompareTo(y.Name)))
                           .Filter(this.WhenAnyValue(x => x.ShowAll)
                                   .DistinctUntilChanged()
                                   .Select(show => new Func <PatcherStoreListingVM, bool>(
                                               (p) =>
            {
                if (p.Raw.Customization?.Visibility is VisibilityOptions.Visible)
                {
                    return(true);
                }
                else if (p.Raw.Customization?.Visibility is VisibilityOptions.IncludeButHide)
                {
                    return(show);
                }
                else if (p.Raw.Customization?.Visibility is VisibilityOptions.Exclude)
                {
                    return(false);                                                                               // just in case.
                }
                else
                {
                    return(true);
                }
            })))
                           .Filter(this.WhenAnyValue(x => x.Search)
                                   .Debounce(TimeSpan.FromMilliseconds(350), RxApp.MainThreadScheduler)
                                   .Select(x => x.Trim())
                                   .DistinctUntilChanged()
                                   .Select(search =>
            {
                if (string.IsNullOrWhiteSpace(search))
                {
                    return(new Func <PatcherStoreListingVM, bool>(_ => true));
                }
                return(new Func <PatcherStoreListingVM, bool>(
                           (p) =>
                {
                    if (p.Name.Contains(search, StringComparison.OrdinalIgnoreCase))
                    {
                        return true;
                    }
                    if (p.Raw.Customization?.OneLineDescription?.Contains(search, StringComparison.OrdinalIgnoreCase) ?? false)
                    {
                        return true;
                    }
                    return false;
                }));
            }))
                           .ToObservableCollection(this);

            OpenPopulationInfoCommand = ReactiveCommand.Create(() => Utility.NavigateToPath(Constants.ListingRepositoryAddress));
            ClearSearchCommand        = ReactiveCommand.Create(() => Search = string.Empty);
        }