Exemple #1
0
        public GetResponse <ICommit> TryGet(
            IGitRepository repo,
            RepoTarget targets,
            GitPatcherVersioning patcherVersioning,
            CancellationToken cancel)
        {
            var commit = repo.TryGetCommit(targets.TargetSha, out var validSha);

            if (!validSha)
            {
                return(GetResponse <ICommit> .Fail("Malformed sha string"));
            }

            cancel.ThrowIfCancellationRequested();
            if (commit == null)
            {
                bool fetchIfMissing = ShouldFetchIfMissing.Should(patcherVersioning);
                if (!fetchIfMissing)
                {
                    return(GetResponse <ICommit> .Fail("Could not locate commit with given sha"));
                }
                repo.Fetch();
                commit = repo.TryGetCommit(targets.TargetSha, out _);
                if (commit == null)
                {
                    return(GetResponse <ICommit> .Fail("Could not locate commit with given sha"));
                }
            }

            return(GetResponse <ICommit> .Succeed(commit));
        }
Exemple #2
0
        public IObservable <IChangeSet <IModListingGetter> > Get(out IObservable <ErrorResponse> state, IScheduler?scheduler = null)
        {
            var results = ObservableExt.WatchFile(_pluginListingsFilePath.Path, fileWatcherFactory: _fileSystem.FileSystemWatcher)
                          .StartWith(Unit.Default)
                          .Select(_ =>
            {
                try
                {
                    return(GetResponse <IObservable <IChangeSet <IModListingGetter> > > .Succeed(
                               _listingsProvider.Get()
                               .AsObservableChangeSet()));
                }
                catch (Exception ex)
                {
                    return(GetResponse <IObservable <IChangeSet <IModListingGetter> > > .Fail(ex));
                }
            })
                          .Replay(1)
                          .RefCount();

            state = results
                    .Select(r => (ErrorResponse)r);
            return(results
                   .Select(r =>
            {
                return r.Value ?? Observable.Empty <IChangeSet <IModListingGetter> >();
            })
                   .Switch()
                   .ObserveOnIfApplicable(scheduler));
        }
Exemple #3
0
        public IObservable <IChangeSet <IModListingGetter> > Get(out IObservable <ErrorResponse> state)
        {
            var path = ListingsPathProvider.Path;

            if (path == null)
            {
                state = Observable.Return(ErrorResponse.Success);
                return(Observable.Empty <IChangeSet <IModListingGetter> >());
            }
            var raw = ObservableExt.WatchFile(path.Value, fileWatcherFactory: _fileSystem.FileSystemWatcher, throwIfInvalidPath: true)
                      .StartWith(Unit.Default)
                      .Select(_ =>
            {
                try
                {
                    return(GetResponse <IObservable <IChangeSet <IModListingGetter> > > .Succeed(
                               ListingsReader.Read(_fileSystem.File.OpenRead(path.Value))
                               .AsObservableChangeSet()));
                }
                catch (Exception ex)
                {
                    return(GetResponse <IObservable <IChangeSet <IModListingGetter> > > .Fail(ex));
                }
            });

            state = raw
                    .Select(r => (ErrorResponse)r);
            return(raw
                   .Select(r =>
            {
                return r.Value ?? Observable.Empty <IChangeSet <IModListingGetter> >();
            })
                   .Switch());
        }
        public static async Task <GetResponse <string> > GetExecutablePath(string projectPath, CancellationToken cancel, Action <string>?log)
        {
            // Hacky way to locate executable, but running a build and extracting the path its logs spit out
            // Tried using Buildalyzer, but it has a lot of bad side effects like clearing build outputs when
            // locating information like this.
            using var proc = ProcessWrapper.Create(
                      new System.Diagnostics.ProcessStartInfo("dotnet", GetBuildString($"\"{projectPath}\"")),
                      cancel: cancel);
            log?.Invoke($"({proc.StartInfo.WorkingDirectory}): {proc.StartInfo.FileName} {proc.StartInfo.Arguments}");
            List <string> outs = new();

            using var outp = proc.Output.Subscribe(o => outs.Add(o));
            List <string> errs = new();

            using var errp = proc.Error.Subscribe(o => errs.Add(o));
            var result = await proc.Run();

            if (errs.Count > 0)
            {
                throw new ArgumentException($"{string.Join("\n", errs)}");
            }
            if (!TryGetExecutablePathFromOutput(outs, out var path))
            {
                log?.Invoke($"Could not locate target executable: {string.Join(Environment.NewLine, outs)}");
                return(GetResponse <string> .Fail("Could not locate target executable."));
            }
            return(GetResponse <string> .Succeed(path));
        }
Exemple #5
0
        public static async Task <GetResponse <TRet> > ExtractInfoFromProject <TRet>(string projPath, CancellationToken cancel, Func <Assembly, GetResponse <TRet> > getter)
        {
            if (cancel.IsCancellationRequested)
            {
                return(GetResponse <TRet> .Fail("Cancelled"));
            }

            // We copy to a temp folder, as despite all the hoops jumped through to unload the assembly,
            // it still seems to lock the dll files.  For whatever reason, though, deleting the folder
            // containing all those files seems to work out? This is definitely a hack.  Unload should
            // ideally just work out of the box.
            using var tempFolder = new TempFolder(Path.Combine(Paths.LoadingFolder, Path.GetRandomFileName()));
            if (cancel.IsCancellationRequested)
            {
                return(GetResponse <TRet> .Fail("Cancelled"));
            }
            CopyDirectory(Path.GetDirectoryName(projPath) !, tempFolder.Dir.Path, cancel);
            projPath = Path.Combine(tempFolder.Dir.Path, Path.GetFileName(projPath));
            var exec = await DotNetCommands.GetExecutablePath(projPath, cancel);

            if (exec.Failed)
            {
                return(exec.BubbleFailure <TRet>());
            }
            return(AssemblyLoading.ExecuteAndForceUnload(exec.Value, getter));
        }
Exemple #6
0
        private static GetResponse <object> GetObjectFromRegistry(RegistryKey key, string valueName)
        {
            var value = key.GetValue(valueName);

            return(value == null
                ? GetResponse <object> .Fail($"RegistryKey {key} does not have value {valueName}!")
                : GetResponse <object> .Succeed(value));
        }
Exemple #7
0
 public GetResponse <TRet> BubbleResult <TRet>(TRet item)
 {
     if (Exception != null)
     {
         return(GetResponse <TRet> .Fail(item, Exception));
     }
     return(GetResponse <TRet> .Create(successful : Succeeded, val : item, reason : Reason));
 }
Exemple #8
0
 public GetResponse <TRet> BubbleFailure <TRet>()
 {
     if (Exception == null)
     {
         return(GetResponse <TRet> .Fail(Reason));
     }
     return(GetResponse <TRet> .Fail(Exception));
 }
        public GetResponse <DriverRepoInfo> Prepare(GetResponse <string> remotePath, CancellationToken cancel)
        {
            // Clone and/or double check the clone is correct
            var state = CheckOrClone.Check(
                remotePath,
                DriverRepoDirectoryProvider.Path,
                cancel);

            if (state.Failed)
            {
                _logger.Error("Failed to check out driver repository: {Reason}", state.Reason);
                return(state.BubbleFailure <DriverRepoInfo>());
            }

            cancel.ThrowIfCancellationRequested();

            // Grab all the interesting metadata
            List <DriverTag>            tags;
            Dictionary <string, string> branchShas;
            IBranch masterBranch;

            try
            {
                using var repoCheckout = RepoCheckouts.Get(DriverRepoDirectoryProvider.Path);

                var masterBranchGet = ResetToLatestMain.TryReset(repoCheckout.Repository);
                if (masterBranchGet.Failed)
                {
                    _logger.Error("Failed to check out driver repository: {Reason}", masterBranchGet.Reason);
                    return(masterBranchGet.BubbleFailure <DriverRepoInfo>());
                }

                masterBranch = masterBranchGet.Value;

                RetrieveRepoVersioningPoints.Retrieve(repoCheckout.Repository, out tags, out branchShas);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Failed to check out driver repository");
                return(GetResponse <DriverRepoInfo> .Fail(ex));
            }

            var paths = GetDriverPaths.Get();

            if (paths.Failed)
            {
                _logger.Error("Failed to check out driver repository: {Reason}", paths.Reason);
                return(paths.BubbleFailure <DriverRepoInfo>());
            }

            return(new DriverRepoInfo(
                       SolutionPath: paths.Value.SolutionPath,
                       MasterBranchName: masterBranch.FriendlyName,
                       BranchShas: branchShas,
                       Tags: tags,
                       AvailableProjects: paths.Value.AvailableProjects));
        }
Exemple #10
0
        public static IObservable <IChangeSet <LoadOrderListing> > GetLiveLoadOrder(
            FilePath cccFilePath,
            DirectoryPath dataFolderPath,
            out IObservable <ErrorResponse> state,
            bool orderListings = true)
        {
            var raw = ObservableExt.WatchFile(cccFilePath.Path)
                      .StartWith(Unit.Default)
                      .Select(_ =>
            {
                try
                {
                    return(GetResponse <IObservable <IChangeSet <ModKey> > > .Succeed(
                               File.ReadAllLines(cccFilePath.Path)
                               .Select(x => ModKey.FromNameAndExtension(x))
                               .AsObservableChangeSet()));
                }
                catch (Exception ex)
                {
                    return(GetResponse <IObservable <IChangeSet <ModKey> > > .Fail(ex));
                }
            })
                      .Replay(1)
                      .RefCount();

            state = raw
                    .Select(r => (ErrorResponse)r);
            var ret = ObservableListEx.And(
                raw
                .Select(r =>
            {
                return(r.Value ?? Observable.Empty <IChangeSet <ModKey> >());
            })
                .Switch(),
                ObservableExt.WatchFolderContents(dataFolderPath.Path)
                .Transform(x =>
            {
                if (ModKey.TryFromNameAndExtension(Path.GetFileName(x), out var modKey))
                {
                    return(TryGet <ModKey> .Succeed(modKey));
                }
                return(TryGet <ModKey> .Failure);
            })
                .Filter(x => x.Succeeded)
                .Transform(x => x.Value)
                .RemoveKey())
                      .Transform(x => new LoadOrderListing(x, true));

            if (orderListings)
            {
                ret = ret.OrderListings();
            }
            return(ret);
        }
        public GetResponse <DriverPaths> Get()
        {
            var slnPath = SolutionFileLocator.GetPath(DriverRepoDirectoryProvider.Path);

            if (slnPath == null)
            {
                return(GetResponse <DriverPaths> .Fail("Could not locate solution to run."));
            }

            var availableProjs = AvailableProjectsRetriever.Get(slnPath.Value).ToList();

            return(new DriverPaths(slnPath.Value, availableProjs));
        }
Exemple #12
0
        public GetResponse <RepoTarget> Get(
            IGitRepository repo,
            GitPatcherVersioning patcherVersioning)
        {
            string?targetSha;
            string?target;

            switch (patcherVersioning.Versioning)
            {
            case PatcherVersioningEnum.Tag:
                if (string.IsNullOrWhiteSpace(patcherVersioning.Target))
                {
                    return(GetResponse <RepoTarget> .Fail("No tag selected"));
                }
                repo.Fetch();
                if (!repo.TryGetTagSha(patcherVersioning.Target, out targetSha))
                {
                    return(GetResponse <RepoTarget> .Fail("Could not locate tag"));
                }
                target = patcherVersioning.Target;
                break;

            case PatcherVersioningEnum.Commit:
                targetSha = patcherVersioning.Target;
                if (string.IsNullOrWhiteSpace(targetSha))
                {
                    return(GetResponse <RepoTarget> .Fail("Could not locate commit"));
                }
                target = patcherVersioning.Target;
                break;

            case PatcherVersioningEnum.Branch:
                if (string.IsNullOrWhiteSpace(patcherVersioning.Target))
                {
                    return(GetResponse <RepoTarget> .Fail($"Target branch had no name."));
                }
                repo.Fetch();
                if (!repo.TryGetBranch(patcherVersioning.Target, out var targetBranch))
                {
                    return(GetResponse <RepoTarget> .Fail($"Could not locate branch: {patcherVersioning.Target}"));
                }
                targetSha = targetBranch.Tip.Sha;
                target    = patcherVersioning.Target;
                break;

            default:
                throw new NotImplementedException();
            }
            return(GetResponse <RepoTarget> .Succeed(
                       new RepoTarget(targetSha, target)));
        }
        public GetResponse <IBranch> TryReset(IGitRepository repo)
        {
            var master = repo.MainBranch;

            if (master == null)
            {
                return(GetResponse <IBranch> .Fail("Could not find main branch"));
            }

            repo.ResetHard();
            repo.Checkout(master);
            repo.Pull();
            return(GetResponse <IBranch> .Succeed(master));
        }
Exemple #14
0
        internal static GetResponse <string> GetStringValueFromRegistry(RegistryKey key, string valueName)
        {
            var objectRes = GetObjectFromRegistry(key, valueName);

            if (objectRes.Failed)
            {
                return(objectRes.BubbleFailure <string>());
            }

            var sValue = objectRes.Value.ToString() ?? string.Empty;

            return(string.IsNullOrEmpty(sValue)
                ? GetResponse <string> .Fail($"Value {valueName} in RegistryKey {key} is null or empty!")
                : GetResponse <string> .Succeed(sValue));
        }
Exemple #15
0
 public RunnableStateProvider(
     ISchedulerProvider schedulerProvider,
     ICheckoutInputProvider checkoutInputProvider,
     IPrepareRunnableState prepareRunnableState)
 {
     _State = checkoutInputProvider.Input
              .Throttle(TimeSpan.FromMilliseconds(150), schedulerProvider.MainThread)
              .DistinctUntilChanged()
              .ObserveOn(schedulerProvider.TaskPool)
              .Select(prepareRunnableState.Prepare)
              .Switch()
              .ToGuiProperty(this, nameof(State), new ConfigurationState <RunnerRepoInfo>(
                                 GetResponse <RunnerRepoInfo> .Fail("Constructing runnable state"))
     {
         IsHaltingError = false
     }, deferSubscription: true);
 }
Exemple #16
0
    public Translator(
        Type nullTranslator,
        Type genericCaster,
        Type loquiTranslation,
        Type enumTranslation)
    {
        this.genericCaster    = genericCaster;
        this.loquiTranslation = loquiTranslation;
        this.enumTranslation  = enumTranslation;

        var nullCasterType  = genericCaster.MakeGenericType(typeof(Object));
        var nullTranslation = Activator.CreateInstance(nullTranslator) !;

        NullTranslationItem = GetResponse <ObjTransl> .Succeed((ObjTransl)Activator.CreateInstance(nullCasterType, new object[] { nullTranslation }) !);

        var genInterfType = typeof(ObjTransl).GetGenericTypeDefinition();

        foreach (var kv in TypeExt.GetInheritingFromGenericInterface(genInterfType))
        {
            if (kv.Value.IsAbstract)
            {
                continue;
            }
            if (kv.Value.Equals(genericCaster))
            {
                continue;
            }
            if (kv.Value.IsGenericTypeDefinition)
            {
                GenericTypes.Add(kv.Value);
                continue;
            }
            Type transItemType = kv.Key.GetGenericArguments()[0];
            try
            {
                SetTranslator(
                    GetCaster(kv.Value, transItemType),
                    transItemType);
            }
            catch (Exception ex)
            {
                typeDict[transItemType] = GetResponse <ObjTransl> .Fail(ex);
            }
        }
    }
        public GetResponse <string> Validate(
            string projName,
            GetResponse <string> sln)
        {
            if (string.IsNullOrWhiteSpace(projName))
            {
                return(GetResponse <string> .Fail("Project needs a name."));
            }
            if (!StringExt.IsViableFilename(projName))
            {
                return(GetResponse <string> .Fail($"Project had invalid path characters."));
            }
            if (projName.IndexOf(' ') != -1)
            {
                return(GetResponse <string> .Fail($"Project name cannot contain spaces."));
            }

            // Just mark as success until we have one and can analyze further
            if (sln.Failed)
            {
                return(GetResponse <string> .Succeed(string.Empty));
            }

            try
            {
                var projPath = Path.Combine(Path.GetDirectoryName(sln.Value) !, projName, $"{projName}.csproj");
                if (_FileSystem.File.Exists(projPath))
                {
                    return(GetResponse <string> .Fail($"Target project folder cannot already exist as a file: {projPath}"));
                }
                if (_FileSystem.Directory.Exists(projPath) &&
                    (_FileSystem.Directory.EnumerateFiles(projPath).Any() ||
                     _FileSystem.Directory.EnumerateDirectories(projPath).Any()))
                {
                    return(GetResponse <string> .Fail($"Target project folder must be empty: {projPath}"));
                }
                return(GetResponse <string> .Succeed(projPath));
            }
            catch (ArgumentException)
            {
                return(GetResponse <string> .Fail("Improper project name. Go simpler."));
            }
        }
 public CheckoutInputProvider(
     IRunnerRepositoryPreparation runnerRepositoryState,
     ISelectedProjectInputVm selectedProjectInput,
     IPatcherVersioningFollower patcherTargeting,
     INugetVersioningFollower nugetTargeting)
 {
     Input = Observable.CombineLatest(
         runnerRepositoryState.State,
         selectedProjectInput.Picker.PathState()
         .Select(x => x.Succeeded ? x : GetResponse <string> .Fail("No patcher project selected.")),
         patcherTargeting.ActivePatcherVersion,
         nugetTargeting.ActiveNugetVersion,
         (runnerState, proj, patcherVersioning, libraryNugets) => new PotentialCheckoutInput(
             runnerState,
             proj,
             patcherVersioning,
             libraryNugets))
             .Replay(1)
             .RefCount();
 }
Exemple #19
0
        public GetResponse <RepositoryListing[]> Get(CancellationToken cancel)
        {
            var prepResp = PrepRegistryRepository.Prep(cancel);

            if (prepResp.Failed)
            {
                return(prepResp.BubbleFailure <RepositoryListing[]>());
            }

            var listingPath = FilePathProvider.Path;

            if (!_fileSystem.File.Exists(listingPath))
            {
                return(GetResponse <RepositoryListing[]> .Fail("Could not locate listing file"));
            }

            var customization = ListingReader.Read(listingPath);

            return(customization.Repositories);
        }
        public async Task <GetResponse <string> > Query(FilePath projectPath, CancellationToken cancel)
        {
            // Hacky way to locate executable, but running a build and extracting the path its logs spit out
            // Tried using Buildalyzer, but it has a lot of bad side effects like clearing build outputs when
            // locating information like this.
            var result = await Runner.RunAndCapture(
                StartInfoProvider.Construct(projectPath),
                cancel : cancel).ConfigureAwait(false);

            if (result.Errors.Count > 0)
            {
                return(GetResponse <string> .Fail($"{string.Join(Environment.NewLine, result.Errors)}"));
            }
            if (!RetrievePath.TryGet(projectPath, result.Out, out var path))
            {
                _Logger.Warning("Could not locate target executable: {Lines}", string.Join(Environment.NewLine, result.Out));
                return(GetResponse <string> .Fail("Could not locate target executable."));
            }
            return(GetResponse <string> .Succeed(path));
        }
        /// <summary>
        /// Takes a span aligned to a major record, and attempts to locate the game setting type.
        /// Will throw if the span is misaligned or doesn't start at a valid major record header.
        /// </summary>
        /// <param name="span">Data beginning at the start of a major record</param>
        /// <param name="meta">Game meta information to use in parsing</param>
        /// <returns>A response of the GameSettingType if found, or a reason if not.</returns>
        public static GetResponse <GameSettingType> GetGameSettingType(ReadOnlyMemorySlice <byte> span, GameConstants meta)
        {
            var majorMeta = meta.MajorRecordFrame(span);
            var edidLoc   = UtilityTranslation.FindFirstSubrecord(majorMeta.Content, meta, Constants.EditorID);

            if (edidLoc == null)
            {
                return(GetResponse <GameSettingType> .Fail($"EDID was not located"));
            }
            var edidMeta = meta.SubrecordFrame(majorMeta.Content.Slice(edidLoc.Value));
            var edid     = BinaryStringUtility.ProcessWholeToZString(edidMeta.Content);

            if (edid.Length == 0)
            {
                return(GetResponse <GameSettingType> .Fail("No EDID parsed."));
            }
            if (!TryGetGameSettingType(edid[0], out var settingType))
            {
                return(GetResponse <GameSettingType> .Fail($"Unknown game setting type: {edid[0]}"));
            }
            return(GetResponse <GameSettingType> .Succeed(settingType));
        }
Exemple #22
0
 static XmlTranslator()
 {
     foreach (var kv in TypeExt.GetInheritingFromGenericInterface(typeof(IXmlTranslation <>)))
     {
         Type transItemType = kv.Key.GetGenericArguments()[0];
         try
         {
             object xmlTransl                = Activator.CreateInstance(kv.Value);
             var    xmlConverterGenType      = typeof(XmlTranslationCaster <>).MakeGenericType(transItemType);
             IXmlTranslation <Object> transl = Activator.CreateInstance(xmlConverterGenType, args: new object[] { xmlTransl }) as IXmlTranslation <Object>;
             SetTranslator(transl, transItemType);
         }
         catch (Exception ex)
         {
             var resp = typeDict.TryCreateValue(
                 transItemType,
                 () =>
             {
                 return(new NotifyingItem <GetResponse <IXmlTranslation <Object> > >());
             }).Value = GetResponse <IXmlTranslation <object> > .Fail(ex);
         }
     }
 }
Exemple #23
0
        public GetResponse <string?> TryGetVersioning()
        {
            if (Versioning == NugetVersioningEnum.Latest && NewestVersion == null)
            {
                return(GetResponse <string?> .Fail($"Latest {Nickname} version is desired, but latest version is not known."));
            }
            var ret = Versioning switch
            {
                NugetVersioningEnum.Latest => NewestVersion,
                NugetVersioningEnum.Match => null,
                NugetVersioningEnum.Manual => ManualVersion,
                _ => throw new NotImplementedException(),
            };

            if (Versioning == NugetVersioningEnum.Manual)
            {
                if (ret.IsNullOrWhitespace())
                {
                    return(GetResponse <string?> .Fail($"Manual {Nickname} versioning had no input"));
                }
            }
            return(ret);
        }
Exemple #24
0
        public static async Task <GetResponse <string> > GetExecutablePath(string projectPath, CancellationToken cancel)
        {
            // Hacky way to locate executable, but running a build and extracting the path its logs spit out
            // Tried using Buildalyzer, but it has a lot of bad side effects like clearing build outputs when
            // locating information like this.
            using var proc = ProcessWrapper.Create(
                      new System.Diagnostics.ProcessStartInfo("dotnet", GetBuildString($"\"{projectPath}\"")),
                      cancel: cancel);
            List <string> outs = new List <string>();

            using var outp = proc.Output.Subscribe(o => outs.Add(o));
            List <string> errs = new List <string>();

            using var errp = proc.Error.Subscribe(o => errs.Add(o));
            var result = await proc.Run();

            if (errs.Count > 0)
            {
                throw new ArgumentException($"{string.Join("\n", errs)}");
            }
            int index = outs.IndexOf("Build succeeded.");

            if (index == -1 || index < 2)
            {
                return(GetResponse <string> .Fail("Could not locate target executable."));
            }
            var          line      = outs[index - 2];
            const string delimiter = " -> ";

            index = line.IndexOf(delimiter);
            if (index == -1)
            {
                return(GetResponse <string> .Fail("Could not locate target executable."));
            }
            return(GetResponse <string> .Succeed(line.Substring(index + delimiter.Length).Trim()));
        }
Exemple #25
0
        public async Task <ConfigurationState <RunnerRepoInfo> > Checkout(
            CheckoutInput checkoutInput,
            CancellationToken cancel)
        {
            try
            {
                cancel.ThrowIfCancellationRequested();

                _logger.Information("Targeting {PatcherVersioning}", checkoutInput.PatcherVersioning);

                using var repoCheckout = RepoCheckouts.Get(RunnerRepoDirectoryProvider.Path);

                var target = ResetToTarget.Reset(repoCheckout.Repository, checkoutInput.PatcherVersioning, cancel);
                if (target.Failed)
                {
                    return(target.BubbleFailure <RunnerRepoInfo>());
                }

                cancel.ThrowIfCancellationRequested();

                checkoutInput.LibraryNugets.Log(_logger);

                var slnPath = SolutionFileLocator.GetPath(RunnerRepoDirectoryProvider.Path);
                if (slnPath == null)
                {
                    return(GetResponse <RunnerRepoInfo> .Fail("Could not locate solution to run."));
                }

                var foundProjSubPath = RunnerRepoProjectPathRetriever.Get(slnPath.Value, checkoutInput.Proj);
                if (foundProjSubPath == null)
                {
                    return(GetResponse <RunnerRepoInfo> .Fail($"Could not locate target project file: {checkoutInput.Proj}."));
                }

                cancel.ThrowIfCancellationRequested();

                ModifyRunnerProjects.Modify(
                    slnPath.Value,
                    drivingProjSubPath: foundProjSubPath.SubPath,
                    versions: checkoutInput.LibraryNugets.ReturnIfMatch(new NugetVersionPair(null, null)),
                    listedVersions: out var listedVersions);

                var runInfo = new RunnerRepoInfo(
                    SolutionPath: slnPath,
                    ProjPath: foundProjSubPath.FullPath,
                    MetaPath: _metaFilePathProvider.Path,
                    Target: target.Value.Target,
                    CommitMessage: target.Value.CommitMessage,
                    CommitDate: target.Value.CommitDate,
                    ListedVersions: listedVersions,
                    TargetVersions: checkoutInput.LibraryNugets.ReturnIfMatch(listedVersions));

                return(GetResponse <RunnerRepoInfo> .Succeed(runInfo));
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                return(GetResponse <RunnerRepoInfo> .Fail(ex));
            }
        }
Exemple #26
0
        public AutogeneratedSettingsVM(
            SettingsConfiguration config,
            string projPath,
            string displayName,
            IObservable <IChangeSet <LoadOrderEntryVM> > loadOrder,
            IObservable <ILinkCache> linkCache,
            Action <string> log)
        {
            var targetSettingsVM = Observable.Return(Unit.Default)
                                   .ObserveOn(RxApp.TaskpoolScheduler)
                                   .Select(_ =>
            {
                return(Observable.Create <(bool Processing, GetResponse <ReflectionSettingsBundleVM> SettingsVM)>(async(observer, cancel) =>
                {
                    try
                    {
                        observer.OnNext((true, GetResponse <ReflectionSettingsBundleVM> .Fail("Loading")));
                        var reflectionBundle = await ReflectionSettingsBundleVM.ExtractBundle(
                            projPath,
                            targets: config.Targets,
                            detectedLoadOrder: loadOrder,
                            linkCache: linkCache,
                            displayName: displayName,
                            log: log,
                            cancel: cancel);
                        if (reflectionBundle.Failed)
                        {
                            observer.OnNext((false, reflectionBundle));
                            return;
                        }
                        observer.OnNext((false, reflectionBundle.Value));
                    }
                    catch (Exception ex)
                    {
                        observer.OnNext((false, GetResponse <ReflectionSettingsBundleVM> .Fail(ex)));
                    }
                    observer.OnCompleted();
                }));
            })
                                   .Switch()
                                   .DisposePrevious()
                                   .Replay(1)
                                   .RefCount();

            _SettingsLoading = targetSettingsVM
                               .Select(t => t.Processing)
                               .ToGuiProperty(this, nameof(SettingsLoading), deferSubscription: true);

            _Bundle = targetSettingsVM
                      .Select(x =>
            {
                if (x.Processing || x.SettingsVM.Failed)
                {
                    return(new ReflectionSettingsBundleVM());
                }
                return(x.SettingsVM.Value);
            })
                      .ObserveOnGui()
                      .Select(x =>
            {
                SelectedSettings = x.Settings?.FirstOrDefault();
                return(x);
            })
                      .DisposePrevious()
                      .ToGuiProperty <ReflectionSettingsBundleVM?>(this, nameof(Bundle), initialValue: null, deferSubscription: true);

            _Status = targetSettingsVM
                      .Select(x => (ErrorResponse)x.SettingsVM)
                      .ToGuiProperty(this, nameof(Error), ErrorResponse.Success, deferSubscription: true);
        }
Exemple #27
0
        public ProfileVM(ConfigurationVM parent, GameRelease?release = null, string?id = null)
        {
            ID      = id ?? Guid.NewGuid().ToString();
            Config  = parent;
            Release = release ?? GameRelease.Oblivion;
            AddGitPatcherCommand      = ReactiveCommand.Create(() => SetInitializer(new GitPatcherInitVM(this)));
            AddSolutionPatcherCommand = ReactiveCommand.Create(() => SetInitializer(new SolutionPatcherInitVM(this)));
            AddCliPatcherCommand      = ReactiveCommand.Create(() => SetInitializer(new CliPatcherInitVM(this)));
            AddSnippetPatcherCommand  = ReactiveCommand.Create(() => SetPatcherForInitialConfiguration(new CodeSnippetPatcherVM(this)));

            ProfileDirectory = Path.Combine(Execution.Paths.WorkingDirectory, ID);
            WorkingDirectory = Execution.Paths.ProfileWorkingDirectory(ID);

            var dataFolderResult = this.WhenAnyValue(x => x.DataPathOverride)
                                   .Select(path =>
            {
                if (path != null)
                {
                    return(Observable.Return(GetResponse <string> .Succeed(path)));
                }
                Log.Logger.Information("Starting to locate data folder");
                return(this.WhenAnyValue(x => x.Release)
                       .ObserveOn(RxApp.TaskpoolScheduler)
                       .Select(x =>
                {
                    try
                    {
                        if (!GameLocations.TryGetGameFolder(x, out var gameFolder))
                        {
                            return GetResponse <string> .Fail("Could not automatically locate Data folder.  Run Steam/GoG/etc once to properly register things.");
                        }
                        return GetResponse <string> .Succeed(Path.Combine(gameFolder, "Data"));
                    }
                    catch (Exception ex)
                    {
                        return GetResponse <string> .Fail(string.Empty, ex);
                    }
                }));
            })
                                   .Switch()
                                   // Watch folder for existance
                                   .Select(x =>
            {
                if (x.Failed)
                {
                    return(Observable.Return(x));
                }
                return(Noggog.ObservableExt.WatchFile(x.Value)
                       .StartWith(Unit.Default)
                       .Select(_ =>
                {
                    if (Directory.Exists(x.Value))
                    {
                        return x;
                    }
                    return GetResponse <string> .Fail($"Data folder did not exist: {x.Value}");
                }));
            })
                                   .Switch()
                                   .StartWith(GetResponse <string> .Fail("Data folder uninitialized"))
                                   .Replay(1)
                                   .RefCount();

            _DataFolder = dataFolderResult
                          .Select(x => x.Value)
                          .ToGuiProperty <string>(this, nameof(DataFolder), string.Empty);

            dataFolderResult
            .Subscribe(d =>
            {
                if (d.Failed)
                {
                    Log.Logger.Error($"Could not locate data folder: {d.Reason}");
                }
                else
                {
                    Log.Logger.Information($"Data Folder: {d.Value}");
                }
            })
            .DisposeWith(this);

            var loadOrderResult = Observable.CombineLatest(
                this.WhenAnyValue(x => x.Release),
                dataFolderResult,
                (release, dataFolder) => (release, dataFolder))
                                  .ObserveOn(RxApp.TaskpoolScheduler)
                                  .Select(x =>
            {
                if (x.dataFolder.Failed)
                {
                    return(Results: Observable.Empty <IChangeSet <LoadOrderEntryVM> >(), State: Observable.Return(ErrorResponse.Fail("Data folder not set")));
                }
                Log.Logger.Error($"Getting live load order for {x.release} -> {x.dataFolder.Value}");
                var liveLo = Mutagen.Bethesda.LoadOrder.GetLiveLoadOrder(x.release, x.dataFolder.Value, out var errors)
                             .Transform(listing => new LoadOrderEntryVM(listing, x.dataFolder.Value))
                             .DisposeMany();
                return(Results: liveLo, State: errors);
            })
                                  .StartWith((Results: Observable.Empty <IChangeSet <LoadOrderEntryVM> >(), State: Observable.Return(ErrorResponse.Fail("Load order uninitialized"))))
                                  .Replay(1)
                                  .RefCount();

            LoadOrder = loadOrderResult
                        .Select(x => x.Results)
                        .Switch()
                        .AsObservableList();

            loadOrderResult.Select(lo => lo.State)
            .Switch()
            .Subscribe(loErr =>
            {
                if (loErr.Succeeded)
                {
                    Log.Logger.Information($"Load order location successful");
                }
                else
                {
                    Log.Logger.Information($"Load order location error: {loErr.Reason}");
                }
            })
            .DisposeWith(this);

            _LargeOverallError = Observable.CombineLatest(
                dataFolderResult,
                loadOrderResult
                .Select(x => x.State)
                .Switch(),
                Patchers.Connect()
                .ObserveOnGui()
                .FilterOnObservable(p => p.WhenAnyValue(x => x.IsOn), scheduler: RxApp.MainThreadScheduler)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <PatcherVM>()),
                Patchers.Connect()
                .ObserveOnGui()
                .FilterOnObservable(p => Observable.CombineLatest(
                                        p.WhenAnyValue(x => x.IsOn),
                                        p.WhenAnyValue(x => x.State.IsHaltingError),
                                        (on, halting) => on && halting),
                                    scheduler: RxApp.MainThreadScheduler)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <PatcherVM>()),
                LoadOrder.Connect()
                .ObserveOnGui()
                .FilterOnObservable(
                    x => x.WhenAnyValue(y => y.Exists)
                    .DistinctUntilChanged()
                    .Select(x => !x),
                    scheduler: RxApp.MainThreadScheduler)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <LoadOrderEntryVM>())
                .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler),
                (dataFolder, loadOrder, enabledPatchers, erroredEnabledPatchers, missingMods) =>
            {
                if (enabledPatchers.Count == 0)
                {
                    return(GetResponse <PatcherVM> .Fail("There are no enabled patchers to run."));
                }
                if (!dataFolder.Succeeded)
                {
                    return(dataFolder.BubbleFailure <PatcherVM>());
                }
                if (!loadOrder.Succeeded)
                {
                    return(loadOrder.BubbleFailure <PatcherVM>());
                }
                if (missingMods.Count > 0)
                {
                    return(GetResponse <PatcherVM> .Fail($"Load order had mods that were missing:{Environment.NewLine}{string.Join(Environment.NewLine, missingMods.Select(x => x.Listing.ModKey))}"));
                }
                if (erroredEnabledPatchers.Count > 0)
                {
                    var errPatcher = erroredEnabledPatchers.First();
                    return(GetResponse <PatcherVM> .Fail(errPatcher, $"\"{errPatcher.DisplayName}\" has a blocking error: {errPatcher.State.RunnableState.Reason}"));
                }
                return(GetResponse <PatcherVM> .Succeed(null !));
            })
Exemple #28
0
        public ProfileVM(ConfigurationVM parent, GameRelease?release = null, string?id = null)
        {
            ID      = id ?? Guid.NewGuid().ToString();
            Config  = parent;
            Release = release ?? GameRelease.Oblivion;
            AddGitPatcherCommand      = ReactiveCommand.Create(() => SetInitializer(new GitPatcherInitVM(this)));
            AddSolutionPatcherCommand = ReactiveCommand.Create(() => SetInitializer(new SolutionPatcherInitVM(this)));
            AddCliPatcherCommand      = ReactiveCommand.Create(() => SetInitializer(new CliPatcherInitVM(this)));
            AddSnippetPatcherCommand  = ReactiveCommand.Create(() => SetPatcherForInitialConfiguration(new CodeSnippetPatcherVM(this)));

            ProfileDirectory = Path.Combine(Execution.Constants.WorkingDirectory, ID);
            WorkingDirectory = Execution.Constants.ProfileWorkingDirectory(ID);

            var dataFolderResult = this.WhenAnyValue(x => x.Release)
                                   .ObserveOn(RxApp.TaskpoolScheduler)
                                   .Select(x =>
            {
                try
                {
                    return(GetResponse <string> .Succeed(
                               Path.Combine(x.ToWjGame().MetaData().GameLocation().ToString(), "Data")));
                }
                catch (Exception ex)
                {
                    return(GetResponse <string> .Fail(string.Empty, ex));
                }
            })
                                   .Replay(1)
                                   .RefCount();

            _DataFolder = dataFolderResult
                          .Select(x => x.Value)
                          .ToGuiProperty <string>(this, nameof(DataFolder));

            var loadOrderResult = Observable.CombineLatest(
                this.WhenAnyValue(x => x.Release),
                dataFolderResult,
                (release, dataFolder) => (release, dataFolder))
                                  .ObserveOn(RxApp.TaskpoolScheduler)
                                  .Select(x =>
            {
                if (x.dataFolder.Failed)
                {
                    return(Results: Observable.Empty <IChangeSet <LoadOrderListing> >(), State: Observable.Return <ErrorResponse>(ErrorResponse.Fail("Data folder not set")));
                }
                var path = Mutagen.Bethesda.LoadOrder.GetPluginsPath(x.release);
                return(Results: Mutagen.Bethesda.LoadOrder.GetLiveLoadOrder(x.release, path, x.dataFolder.Value, out var errors), State: errors);
            })
                                  .Replay(1)
                                  .RefCount();

            LoadOrder = loadOrderResult
                        .Select(x => x.Results)
                        .Switch()
                        .AsObservableList();

            _LargeOverallError = Observable.CombineLatest(
                dataFolderResult,
                loadOrderResult
                .Select(x => x.State)
                .Switch(),
                Patchers.Connect()
                .AutoRefresh(x => x.IsOn)
                .Filter(p => p.IsOn)
                .AutoRefresh(x => x.State)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <PatcherVM>()),
                (dataFolder, loadOrder, coll) =>
            {
                if (coll.Count == 0)
                {
                    return(GetResponse <PatcherVM> .Fail("There are no enabled patchers to run."));
                }
                if (!dataFolder.Succeeded)
                {
                    return(dataFolder.BubbleFailure <PatcherVM>());
                }
                if (!loadOrder.Succeeded)
                {
                    return(loadOrder.BubbleFailure <PatcherVM>());
                }
                var blockingError = coll.FirstOrDefault(p => p.State.IsHaltingError);
                if (blockingError != null)
                {
                    return(GetResponse <PatcherVM> .Fail(blockingError, $"\"{blockingError.DisplayName}\" has a blocking error"));
                }
                return(GetResponse <PatcherVM> .Succeed(null !));
            })
Exemple #29
0
        public ProfileVm(
            ILifetimeScope scope,
            IPatcherInitializationVm initVm,
            IProfileDataFolderVm dataFolder,
            IProfileIdentifier ident,
            IProfileNameVm nameProvider,
            IProfileLoadOrder loadOrder,
            IProfileDirectories dirs,
            IProfileVersioning versioning,
            IProfileDisplayControllerVm profileDisplay,
            ILockToCurrentVersioning lockSetting,
            ISelectedProfileControllerVm selProfile,
            IProfileExporter exporter,
            IProfileGroupsList groupsList,
            IEnvironmentErrorsVm environmentErrors,
            OverallErrorVm overallErrorVm,
            StartRun startRun,
            ILogger logger)
        {
            Scope              = scope;
            Init               = initVm;
            OverallErrorVm     = overallErrorVm;
            NameVm             = nameProvider;
            Groups             = groupsList.Groups;
            DataFolderOverride = dataFolder;
            Versioning         = versioning;
            LockSetting        = lockSetting;
            Exporter           = exporter;
            DisplayController  = profileDisplay;
            _startRun          = startRun;
            _logger            = logger;
            ID      = ident.ID;
            Release = ident.Release;

            GroupsDisplay = new SourceListUiFunnel <GroupVm>(Groups, this);

            ProfileDirectory = dirs.ProfileDirectory;
            WorkingDirectory = dirs.WorkingDirectory;

            EnvironmentErrors = environmentErrors;

            _dataFolder = dataFolder.WhenAnyValue(x => x.Path)
                          .ToGuiProperty <DirectoryPath>(this, nameof(DataFolder), string.Empty, deferSubscription: true);

            LoadOrder = loadOrder.LoadOrder;

            var enabledGroups = Groups.Connect()
                                .ObserveOnGui()
                                .FilterOnObservable(p => p.WhenAnyValue(x => x.IsOn), scheduler: RxApp.MainThreadScheduler)
                                .RefCount();

            var enabledGroupModKeys = enabledGroups
                                      .Transform(x => x.ModKey)
                                      .QueryWhenChanged(q => q.ToHashSet())
                                      .Replay(1).RefCount();

            _blockingError = Observable.CombineLatest(
                dataFolder.WhenAnyValue(x => x.DataFolderResult),
                loadOrder.WhenAnyValue(x => x.State),
                enabledGroups
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <GroupVm>()),
                enabledGroups
                .FilterOnObservable(g => g.WhenAnyValue(x => x.State).Select(x => x.IsHaltingError))
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <GroupVm>()),
                LoadOrder.Connect()
                .FilterOnObservable(
                    x =>
            {
                return(Observable.CombineLatest(
                           x.WhenAnyValue(y => y.Exists)
                           .DistinctUntilChanged(),
                           enabledGroupModKeys
                           .Select(groupModKeys => groupModKeys.Contains(x.ModKey)),
                           (exists, isEnabledGroupKey) => !exists && !isEnabledGroupKey));
            },
                    scheduler: RxApp.MainThreadScheduler)
                .QueryWhenChanged(q => q)
                .StartWith(Noggog.ListExt.Empty <ReadOnlyModListingVM>())
                .Throttle(TimeSpan.FromMilliseconds(200), RxApp.MainThreadScheduler),
                this.WhenAnyValue(x => x.IgnoreMissingMods),
                (dataFolder, loadOrder, enabledGroups, erroredEnabledGroups, missingMods, ignoreMissingMods) =>
            {
                if (enabledGroups.Count == 0)
                {
                    return(GetResponse <ViewModel> .Fail("There are no enabled groups to run."));
                }
                if (!dataFolder.Succeeded)
                {
                    return(dataFolder.BubbleFailure <ViewModel>());
                }
                if (!loadOrder.Succeeded)
                {
                    return(loadOrder.BubbleFailure <ViewModel>());
                }
                if (!ignoreMissingMods && missingMods.Count > 0)
                {
                    return(GetResponse <ViewModel> .Fail($"Load order had mods that were missing:{Environment.NewLine}{string.Join(Environment.NewLine, missingMods.Select(x => x.ModKey))}"));
                }
                if (erroredEnabledGroups.Count > 0)
                {
                    var errGroup = erroredEnabledGroups.First();
                    return(GetResponse <ViewModel> .Fail(errGroup, $"\"{errGroup.Name}\" has a blocking error: {errGroup.State}"));
                }
                return(GetResponse <ViewModel> .Succeed(null !));
            })
        public NewSolutionInitVM()
        {
            ParentDirPath.PathType         = PathPickerVM.PathTypeOptions.Folder;
            ParentDirPath.ExistCheckOption = PathPickerVM.CheckOptions.On;

            _SolutionPath = Observable.CombineLatest(
                this.ParentDirPath.PathState(),
                this.WhenAnyValue(x => x.SolutionName),
                (parentDir, slnName) =>
            {
                if (string.IsNullOrWhiteSpace(slnName))
                {
                    return(GetResponse <string> .Fail(val: slnName, reason: "Solution needs a name."));
                }

                // Will reevaluate once parent dir is fixed
                if (parentDir.Failed)
                {
                    return(GetResponse <string> .Succeed(value: slnName));
                }
                try
                {
                    var slnPath = Path.Combine(parentDir.Value, slnName);
                    if (File.Exists(slnPath))
                    {
                        return(GetResponse <string> .Fail(val: slnName, reason: $"Target solution folder cannot already exist as a file: {slnPath}"));
                    }
                    if (Directory.Exists(slnPath) &&
                        (Directory.EnumerateFiles(slnPath).Any() ||
                         Directory.EnumerateDirectories(slnPath).Any()))
                    {
                        return(GetResponse <string> .Fail(val: slnName, reason: $"Target solution folder must be empty: {slnPath}"));
                    }
                    return(GetResponse <string> .Succeed(Path.Combine(slnPath, $"{slnName}.sln")));
                }
                catch (ArgumentException)
                {
                    return(GetResponse <string> .Fail(val: slnName, reason: "Improper solution name. Go simpler."));
                }
            })
                            .ToGuiProperty(this, nameof(SolutionPath));

            var validation = Observable.CombineLatest(
                this.ParentDirPath.PathState(),
                this.WhenAnyValue(x => x.SolutionName),
                this.WhenAnyValue(x => x.SolutionPath),
                this.WhenAnyValue(x => x.ProjectName),
                (parentDir, slnName, sln, proj) =>
            {
                // Use solution name if proj empty.
                if (string.IsNullOrWhiteSpace(proj))
                {
                    proj = SolutionNameProcessor(slnName);
                }
                return(parentDir, sln, proj, validation: SolutionInitialization.ValidateProjectPath(proj, sln));
            })
                             .Replay(1)
                             .RefCount();

            _ProjectError = validation
                            .Select(i => (ErrorResponse)i.validation)
                            .ToGuiProperty <ErrorResponse>(this, nameof(ProjectError), ErrorResponse.Success);

            InitializationCall = validation
                                 .Select((i) =>
            {
                if (i.parentDir.Failed)
                {
                    return(i.parentDir.BubbleFailure <InitializerCall>());
                }
                if (i.sln.Failed)
                {
                    return(i.sln.BubbleFailure <InitializerCall>());
                }
                if (i.validation.Failed)
                {
                    return(i.validation.BubbleFailure <InitializerCall>());
                }
                return(GetResponse <InitializerCall> .Succeed(async(profile) =>
                {
                    var patcher = new SolutionPatcherVM(profile);
                    SolutionInitialization.CreateSolutionFile(i.sln.Value);
                    SolutionInitialization.CreateProject(i.validation.Value, patcher.Profile.Release.ToCategory());
                    SolutionInitialization.AddProjectToSolution(i.sln.Value, i.validation.Value);
                    SolutionInitialization.GenerateGitIgnore(Path.GetDirectoryName(i.sln.Value) !);
                    patcher.SolutionPath.TargetPath = i.sln.Value;
                    var projName = Path.GetFileNameWithoutExtension(i.validation.Value);
                    patcher.ProjectSubpath = Path.Combine(projName, $"{projName}.csproj");
                    return patcher.AsEnumerable();
                }));
            });

            _ProjectNameWatermark = this.WhenAnyValue(x => x.SolutionName)
                                    .Select(x => string.IsNullOrWhiteSpace(x) ? "The name of the patcher" : SolutionNameProcessor(x))
                                    .ToGuiProperty <string>(this, nameof(ProjectNameWatermark), string.Empty);
        }