Ejemplo n.º 1
0
        void MergeBundleFileNode(TreeNode fileNode, TreeNode[] checkedModNodes, Merge merge, bool isNew)
        {
            _outputPath = Path.Combine(Paths.MergedBundleContent, fileNode.Text);

            if (File.Exists(_outputPath) && !ConfirmOutputOverwrite(_outputPath))
            {
                return;
            }

            _vanillaFile = null;

            var metadata1 = checkedModNodes[0].GetMetadata();
            var source1   = MergeSource.FromBundle(new FileInfo(metadata1.FilePath), metadata1.FileHash);

            for (int i = 1; i < checkedModNodes.Length; ++i)
            {
                ++ProgressInfo.CurrentMergeNum;

                var metadata2 = checkedModNodes[i].GetMetadata();
                var source2   = MergeSource.FromBundle(new FileInfo(metadata2.FilePath), metadata2.FileHash);

                if (!GetUnpackedFiles(fileNode.Text, ref source1, ref source2))
                {
                    if (DialogResult.Abort != HandleCanceledMerge(checkedModNodes.Length - i - 1, merge))
                    {
                        continue;
                    }
                    break;
                }

                var mergedFile = MergeText(merge, source1, source2, true);
                if (mergedFile != null)
                {
                    source1 = MergeSource.FromFlatFile(mergedFile, null);
                }
                else if (DialogResult.Abort == HandleCanceledMerge(checkedModNodes.Length - i - 1, merge))
                {
                    break;
                }
            }

            if (merge.BundleName != null && isNew && merge.Mods.Count > 1)
            {
                _bundleChanged = true;
                _pendingBundleMerges.Add(merge);
            }
        }
Ejemplo n.º 2
0
        FileInfo MergeText(Merge merge, MergeSource source1, MergeSource source2, bool isBundled)
        {
            ProgressInfo.CurrentAction = $"Merging {source1.Name} && {source2.Name} — waiting for KDiff3 to close";

            var exitCode = KDiff3.Run(source1, source2, _vanillaFile, _outputPath, !isBundled);

            if (exitCode == 0)
            {
                if (!source1.TextFile.FullName.EqualsIgnoreCase(_outputPath) &&
                    !source1.TextFile.FullName.StartsWithIgnoreCase(Paths.MergedBundleContentAbsolute))
                {
                    _inventory.AddModToMerge(source1, merge);
                }

                if (!source2.TextFile.FullName.EqualsIgnoreCase(_outputPath) &&
                    !source2.TextFile.FullName.StartsWithIgnoreCase(Paths.MergedBundleContentAbsolute))
                {
                    _inventory.AddModToMerge(source2, merge);
                }

                if (Program.Settings.Get <bool>("PlayCompletionSounds"))
                {
                    System.Media.SystemSounds.Asterisk.Play();
                }
                if (Program.Settings.Get <bool>("ReportAfterMerge"))
                {
                    using (var reportForm = new MergeReportForm(
                               ProgressInfo.CurrentMergeNum, ProgressInfo.TotalMergeCount,
                               source1.TextFile.FullName, source2.TextFile.FullName, _outputPath,
                               source1.Name, source2.Name))
                    {
                        ProgressInfo.CurrentAction = "Showing merge report";
                        Program.MainForm.ShowModal(reportForm);
                    }
                }
                return(new FileInfo(_outputPath));
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 3
0
        void MergeFlatFileNode(TreeNode fileNode, TreeNode[] checkedModNodes, Merge merge, bool isNew)
        {
            var metadata1 = checkedModNodes[0].GetMetadata();
            var source1   = MergeSource.FromFlatFile(new FileInfo(metadata1.FilePath), metadata1.FileHash);

            var relPath = Paths.GetRelativePath(
                source1.TextFile.FullName,
                Path.Combine(Paths.ModsDirectory, source1.Name));

            _outputPath = Path.Combine(Paths.ModsDirectory, _mergedModName, relPath);

            if (File.Exists(_outputPath) && !ConfirmOutputOverwrite(_outputPath))
            {
                return;
            }

            _vanillaFile = new FileInfo(fileNode.GetMetadata().FilePath);

            for (int i = 1; i < checkedModNodes.Length; ++i)
            {
                ++ProgressInfo.CurrentMergeNum;

                var metadata2 = checkedModNodes[i].GetMetadata();
                var source2   = MergeSource.FromFlatFile(new FileInfo(metadata2.FilePath), metadata2.FileHash);

                var mergedFile = MergeText(merge, source1, source2, false);
                if (mergedFile != null)
                {
                    source1 = MergeSource.FromFlatFile(mergedFile, null);
                }
                else if (DialogResult.Abort == HandleCanceledMerge(checkedModNodes.Length - i - 1, merge))
                {
                    break;
                }
            }

            if (isNew && merge.Mods.Count > 1)
            {
                ProgressInfo.CurrentAction = "Adding script merge to inventory";
                _inventory.Merges.Add(merge);
            }
        }
Ejemplo n.º 4
0
        static void MergeToMain()
        {
            try
            {
                WorkspaceInfo mWkInfo = FindWorkspace.InfoForApplicationPath(Application.dataPath, Plastic.API);

                if (mWkInfo == null)
                {
                    return;
                }

                RepositorySpec repSpec = Plastic.API.GetRepositorySpec(mWkInfo);
                RepositoryInfo repInfo = Plastic.API.GetRepositoryInfo(repSpec);

                BranchInfo workingBranchInfo = Plastic.API.GetWorkingBranch(mWkInfo);
                BranchInfo mainBranchInfo    = Plastic.API.GetMainBranch(repSpec);

                if (workingBranchInfo.BranchId == mainBranchInfo.BranchId)
                {
                    return;
                }

                SpecGenerator specGenerator   = new SpecGenerator(repInfo);
                BranchSpec    sourceSpec      = specGenerator.GenBranchSpec(false, workingBranchInfo.BranchName);
                BranchSpec    destinationSpec = specGenerator.GenBranchSpec(false, mainBranchInfo.BranchName);

                MergeSource mergeSource = MergeSourceBuilder.BuildMergeSource(repInfo,
                                                                              null, sourceSpec, destinationSpec, new MergeParameters());
                BuildMerge.ApplyMergeForMerge(mWkInfo, null).MergeTo(mergeSource, mMergeComments);
            }
            finally
            {
                string plasticIniFilePah = Path.Combine(Application.dataPath, "../plastic.ini");
                File.Delete(plasticIniFilePah);
            }
        }
 void IPlasticAPI.PerformUpdateMerge(WorkspaceInfo wkInfo, MergeSource mergeSource, MergeResult mergeResult, ICmdNotifier notifier)
 {
     throw new NotImplementedException();
 }
Ejemplo n.º 6
0
        bool GetUnpackedFiles(string contentRelativePath, ref MergeSource source1, ref MergeSource source2)
        {
            if (_vanillaFile == null)
            {
                ProgressInfo.CurrentAction = "Searching for corresponding vanilla bundle";

                var bundleDirsList =
                    Directory.GetDirectories(Paths.BundlesDirectory)
                    .Select(path => Path.Combine(path, "bundles"))
                    .Concat(
                        Directory.GetDirectories(Paths.DlcDirectory)
                        .Where(path => new Regex("DLC[0-9]*$", RegexOptions.IgnoreCase).IsMatch(path) ||
                               new Regex("ep[0-9]$", RegexOptions.IgnoreCase).IsMatch(path) ||
                               new Regex("bob$", RegexOptions.IgnoreCase).IsMatch(path))
                        .Select(path => Path.Combine(path, Paths.BundleBase, "bundles"))
                        )
                    .Where(path => Directory.Exists(path))
                    .OrderBy(path => path, new LoadOrderComparer())
                    .ToList();

                // Ensure patch bundle directories are always last
                var patchDirs  = bundleDirsList.FindAll(x => x.Contains("patch"));
                var bundleDirs = bundleDirsList
                                 .Except(patchDirs)
                                 .Union(patchDirs)
                                 .ToArray();

                for (int i = bundleDirs.Length - 1; i >= 0; --i)  // Search vanilla directories in reverse
                {                                                 // order, as patches & DLC override content.
                    var bundleFiles = Directory.GetFiles(bundleDirs[i], "*.bundle");
                    foreach (var bundle in bundleFiles)
                    {
                        var contentPaths = QuickBms.GetBundleContentPaths(bundle);
                        if (contentPaths.Any(path => path.EqualsIgnoreCase(contentRelativePath)))
                        {
                            _vanillaFile = new FileInfo(bundle);
                            break;
                        }
                    }
                    if (_vanillaFile != null)
                    {
                        break;
                    }
                }
                if (_vanillaFile != null)
                {
                    ProgressInfo.CurrentAction = "Unpacking vanilla bundle content file";
                    var vanillaContentPath = UnpackFile(_vanillaFile.FullName, contentRelativePath, "Vanilla");
                    _vanillaFile = new FileInfo(vanillaContentPath);
                }
            }

            if (source1.TextFile == null)
            {
                ProgressInfo.CurrentAction = $"Unpacking bundle content file for {source1.Name}";
                var modContentFile1 = UnpackFile(source1.Bundle.FullName, contentRelativePath, "Mod 1");
                if (modContentFile1 == null)
                {
                    return(false);
                }
                source1.TextFile = new FileInfo(modContentFile1);
            }
            ProgressInfo.CurrentAction = $"Unpacking bundle content file for {source2.Name}";
            var modContentFile2 = UnpackFile(source2.Bundle.FullName, contentRelativePath, "Mod 2");

            if (modContentFile2 == null)
            {
                return(false);
            }
            source2.TextFile = new FileInfo(modContentFile2);
            return(true);
        }
        bool GetUnpackedFiles(string contentRelativePath, ref MergeSource source1, ref MergeSource source2)
        {
            if (_vanillaFile == null)
            {
                ProgressInfo.CurrentAction = "Searching for corresponding vanilla bundle";

                var bundleDirs =
                    Directory.GetDirectories(Paths.BundlesDirectory)
                        .Select(path => Path.Combine(path, "bundles"))
                        .Concat(
                            Directory.GetDirectories(Paths.DlcDirectory)
                                .Where(path => new Regex("DLC[0-9]*$").IsMatch(path) || new Regex("ep[0-9]$").IsMatch(path))
                                .Select(path => Path.Combine(path, Paths.BundleBase, "bundles"))
                        )
                        .Where(path => Directory.Exists(path))
                        .OrderBy(path => path, new LoadOrderComparer())
                        .ToArray();

                for (int i = bundleDirs.Length - 1; i >= 0; --i)  // Search vanilla directories in reverse
                {                                                 // order, as patches & DLC override content.
                    var bundleFiles = Directory.GetFiles(bundleDirs[i], "*.bundle");
                    foreach (var bundle in bundleFiles)
                    {
                        var contentPaths = QuickBms.GetBundleContentPaths(bundle);
                        if (contentPaths.Any(path => path.EqualsIgnoreCase(contentRelativePath)))
                        {
                            _vanillaFile = new FileInfo(bundle);
                            break;
                        }
                    }
                    if (_vanillaFile != null)
                        break;
                }
                if (_vanillaFile != null)
                {
                    ProgressInfo.CurrentAction = "Unpacking vanilla bundle content file";
                    var vanillaContentPath = UnpackFile(_vanillaFile.FullName, contentRelativePath, "Vanilla");
                    _vanillaFile = new FileInfo(vanillaContentPath);
                }
            }

            if (source1.TextFile == null)
            {
                ProgressInfo.CurrentAction = $"Unpacking bundle content file for {source1.Name}";
                var modContentFile1 = UnpackFile(source1.Bundle.FullName, contentRelativePath, "Mod 1");
                if (modContentFile1 == null)
                    return false;
                source1.TextFile = new FileInfo(modContentFile1);
            }
            ProgressInfo.CurrentAction = $"Unpacking bundle content file for {source2.Name}";
            var modContentFile2 = UnpackFile(source2.Bundle.FullName, contentRelativePath, "Mod 2");
            if (modContentFile2 == null)
                return false;
            source2.TextFile = new FileInfo(modContentFile2);
            return true;
        }
        FileInfo MergeText(Merge merge, MergeSource source1, MergeSource source2)
        {
            ProgressInfo.CurrentAction = $"Merging {source1.Name} && {source2.Name} — waiting for KDiff3 to close";

            var exitCode = KDiff3.Run(source1, source2, _vanillaFile, _outputPath);

            if (exitCode == 0)
            {
                if (!source1.TextFile.FullName.EqualsIgnoreCase(_outputPath)
                    && !source1.TextFile.FullName.StartsWithIgnoreCase(Paths.MergedBundleContentAbsolute))
                {
                    _inventory.AddModToMerge(source1, merge);
                }

                if (!source2.TextFile.FullName.EqualsIgnoreCase(_outputPath)
                    && !source2.TextFile.FullName.StartsWithIgnoreCase(Paths.MergedBundleContentAbsolute))
                {
                    _inventory.AddModToMerge(source2, merge);
                }

                if (Program.Settings.Get<bool>("PlayCompletionSounds"))
                {
                    System.Media.SystemSounds.Asterisk.Play();
                }
                if (Program.Settings.Get<bool>("ReportAfterMerge"))
                {
                    using (var reportForm = new MergeReportForm(
                        ProgressInfo.CurrentMergeNum, ProgressInfo.TotalMergeCount,
                        source1.TextFile.FullName, source2.TextFile.FullName, _outputPath,
                        source1.Name, source2.Name))
                    {
                        ProgressInfo.CurrentAction = "Showing merge report";
                        Program.MainForm.ShowModal(reportForm);
                    }
                }
                return new FileInfo(_outputPath);
            }
            else
                return null;
        }
Ejemplo n.º 9
0
        }   // public static CompareResult CompareTwoOfAKind<T>
        

        /// <summary>
        /// Merge two sorted lists, returning a new sorted list containg the new
        /// or updated items from a second list. Please see Remarks.
        /// </summary>
        /// <typeparam name="T">
        /// All three lists (both inputs, paMasterList and paNewItems, and the
        /// returned list) must contain objects of the same type, and that type
        /// must implement the IComparable interface and have a parameterless
        /// default constructor.
        /// </typeparam>
        /// <param name="paMasterList">
        /// This array is the master list. Items without matching items in list
        /// paNewItems are preserved. Please see Remarks.
        /// </param>
        /// <param name="paNewItems">
        /// An item that matches an item in list paMasterList replaces it. An
        /// item that doesn't match any existing item in list paMasterList is
        /// merged into it. Please see Remarks.
        /// </param>
        /// <returns>
        /// The returned list contains everything in list paNewItems, and
        /// everything in list paMasterList that has no matching item in list
        /// paMasterList. Please see Remarks. Since both input lists are sorted,
        /// the new list is also sorted.
        /// </returns>
        /// <remarks>
        /// The goal of this routine is to merge two lists, the first of which
        /// is treated as a master list, into which new and updated items from
        /// from the second list are merged.
        /// 
        /// Merging is based on comparing items from both lists based on the
        /// values returned by their respective CompareTo methods. Values that
        /// return zero (equality) are merged by replacing the value from the
        /// first list, represented by the first argument (paMasterList) with
        /// that from the second list, represented by the second argument
        /// (paNewItems).
        /// 
        /// This algorithm imposes four requirements on its inputs.
        /// 
        /// 1) Both input arrays must be composed of objects of the same type.
        /// 
        /// 2) That type must implement the IComparable interface.
        /// 
        /// 3) That type must have a default constructor.
        /// 
        /// 4) Both input arrays must be sorted.
        /// 
        /// In return, it makes the following four guarantees.
        /// 
        /// 1) Every item in array paNewItems will become part of the new list.
        /// 
        /// 2) Every item in array paMasterList that has no matching value in
        /// array paNewItems will become part of the new list.
        /// 
        /// 3) Every item in array paNewItems that matches an item in array
        /// paMasterList replaces that matching item.
        /// 
        /// 4) Every item in array paNewItems that doesn't match any item in
        /// paMasterList is added to the list.
        /// 
        /// On input, both lists must be sorted, which is the first reason that
        /// the objects in the arrays must implement IComparable. The second
        /// reason is that this routine must compare the two lists in order to
        /// merge them correctly. The comparison happens in CompareTwoOfAKind, a
        /// companion routine that also takes generics meeting the first of the
        /// two specified constraints.
        /// </remarks>
        public static T [ ] MergeNewItemsIntoArray<T> (
            T [ ] paMasterList ,
            T [ ] paNewItems )
            where T : IComparable , new ( )
        {
            const string ARG_NAME_OLD = @"paMasterList";
            const string ARG_NAME_NEW = @"paNewItems";

            const long EMPTY = MagicNumbers.ZERO;

            //  ----------------------------------------------------------------
            //  First things first: Sanity check both inputs.
            //  ----------------------------------------------------------------

            if ( paMasterList == null )
            {
                throw new ArgumentNullException (
                    ARG_NAME_OLD ,
                    WizardWrx.DLLServices2.Properties.Resources.ERRMSG_ARG_IS_NULL );
			}   // if ( paMasterList == null )

            if ( paNewItems == null )
            {
                throw new ArgumentNullException (
                    ARG_NAME_NEW ,
					WizardWrx.DLLServices2.Properties.Resources.ERRMSG_ARG_IS_NULL );
			}   // if ( paNewItems == null )

            long lngMasterItemsCount = paMasterList.LongLength;
            long lngNewItemsCount = paNewItems.LongLength;

            ArrayList alMerged = new ArrayList ( );

            //  ----------------------------------------------------------------
            //  Next, address the three degenerate cases of one or both arrays
            //  being empty.
            //  ----------------------------------------------------------------

            if ( lngMasterItemsCount == EMPTY || lngNewItemsCount == EMPTY )
            {   // One or both arrays are empty.
                if ( lngMasterItemsCount == EMPTY )
                {   // Old array is empty. Use new array, unless it is also empty.
                    if ( lngNewItemsCount > EMPTY )
                    {   // New array is populated. Fill the output array from it.
                        alMerged.AddRange ( paNewItems );
                    }   // if ( panew.Length > EMPTY )
                }   // TRUE block, if ( paold.Length == EMPTY )
                else
                {   // Fill the output array from the old array. The new one is, a priori, empty.
                    alMerged.AddRange ( paMasterList );
                }   // FALSE block, if ( paold.Length == EMPTY )
            }   // if ( paold.Length == EMPTY || panew.Length == EMPTY )

            //  ----------------------------------------------------------------
            //  The general case prevails; both arrays contain data.
            //  ----------------------------------------------------------------

            bool fMoreData = true;
            long lngIndexMaster = ArrayInfo.ARRAY_FIRST_ELEMENT;
            long lngIndexNewItems = ArrayInfo.ARRAY_FIRST_ELEMENT;

            MergeSource enmMergeSource = MergeSource.Undetermined;

            while ( fMoreData )
            {
                switch ( enmMergeSource )
                {
                    case MergeSource.FinishFromNewItemsList:
                        while ( lngIndexNewItems < lngNewItemsCount )
                        {
                            alMerged.Add ( paNewItems [ lngIndexNewItems ] );
                            lngIndexNewItems++;
                        }   // while ( lngIndexNewItems < lngNewItemsCount )

                        fMoreData = false;
                        break;  // case MergeSource.FinishFronNew

                    case MergeSource.FinishFromMasterList:
                        while ( lngIndexMaster < lngMasterItemsCount )
                        {
                            alMerged.Add ( paMasterList [ lngIndexMaster ] );
                            lngIndexMaster++;
                        }   // while ( lngIndexMaster < lngMasterItemsCount )

                        fMoreData = false;
                        break;  // case MergeSource.FinishFromOld

                    default:

                        //  ----------------------------------------------------
                        //  The designs of this routine and CompareTwoOfAKind
                        //  ensure that CompareTwoOfAKind succeeds, and that its
                        //  return value is always one of the three cases
                        //  written into this switch block.
                        //  ----------------------------------------------------

                        switch ( CompareTwoOfAKind ( paMasterList [ lngIndexMaster ] , paNewItems [ lngIndexNewItems ] ) )
                        {
                            case CompareResult.EqualTo:
                                enmMergeSource = MergeSource.AddItemFromNewList;
                                alMerged.Add ( paNewItems [ lngIndexNewItems ] );
                                lngIndexNewItems++;
                                lngIndexMaster++;
                                break;  // case CompareResult.EqualTo

                            case CompareResult.LessThan:
                                enmMergeSource = MergeSource.AddItemFromMasterList;
                                alMerged.Add ( paMasterList [ lngIndexMaster ] );
                                lngIndexMaster++;
                                break;  // case CompareResult.LessThan

                            case CompareResult.GreaterThan:
                                enmMergeSource = MergeSource.AddItemFromNewList;
                                alMerged.Add ( paNewItems [ lngIndexNewItems ] );
                                lngIndexNewItems++;
                                break;  // case CompareResult.GreaterThan
                        }   // switch ( CompareTwoOfAKind ( panew [ lngIndexNewItems ] , paold [ lngIndexMaster ] ) )

                        //  ----------------------------------------------------
                        //  After each iteration, see whether either or both
                        //  lists are exhausted.
                        //  ----------------------------------------------------

                        if ( lngIndexNewItems >= lngNewItemsCount && lngIndexMaster >= lngMasterItemsCount )
                        {   // The merge is finished when both lists are exhausted.
                            fMoreData = false;
                        }
                        else
                        {   // Check for the special case of one list being exhausted.
                            if ( lngIndexNewItems >= lngNewItemsCount )
                            {
                                enmMergeSource = MergeSource.FinishFromMasterList;
                            }   // if ( lngIndexNewItems > panew.Length )
                            else if ( lngIndexMaster >= lngMasterItemsCount )
                            {
                                enmMergeSource = MergeSource.FinishFromNewItemsList;
                            }   // else if ( lngIndexMaster >= lngMasterItemsCount )
                        }   // if ( lngIndexNewItems > panew.Length && lngIndexMaster > paold.Length )

                        break;  // Default case
                }   // switch ( enmMergeSource )
            }   // while ( fMoreData )

            T [ ] raMerged = ( T [ ] ) alMerged.ToArray ( typeof ( T ) );
            return raMerged;
        }   // public static T [] MergeNewItemsIntoArray<T>