예제 #1
0
        public void Dispatch(IAction action)
        {
            if (action == null)
            {
                throw new ArgumentNullException(nameof(action));
            }

            SetState(_rootReducer.Reduce(State, action));
            _storage.Save(State);
            _devToolsInterop.Send(action, State);
        }
예제 #2
0
        private void VisitedPage(object sender, CriterionEventArgs e)
        {
            var page = _contentLoader.Get <IContent>(e.GetPageLink());

            if (!(page is ICategorizableContent categorizable))
            {
                return;
            }
            var pageCatIds = categorizable.Categories?.Select(x => x.ID);

            if (_stateStorage.IsAvailable && pageCatIds != null && pageCatIds.Contains(int.Parse(Model.CategoryId)))
            {
                var times = GetVisitedTimes() + 1;
                _stateStorage.Save(_STORAGEKEY, times);
            }
        }
예제 #3
0
        public string Convert()
        {
            string result = null;

            if (_state == null)
            {
                _state = _storage.Load();
            }
            if (_state.StartBranch == null)
            {
                _state.StartBranch = _root;// rdr.GetStartBranch(trunk);
                _state.Branches    = new List <string>()
                {
                    _state.StartBranch
                };
                if (!_ignoreBranches)
                {
                    _state.Revision = _reader.GetFirstRevision(_state.StartBranch, null);
                }
            }

            List <long> revs      = null;
            var         revsIndex = 0;

            if (_ignoreBranches)
            {
                revs = _reader.GetRevisions(_root, null);
                if (_state.Revision == 0)
                {
                    _state.Revision = revs[0];
                }
                else
                {
                    revsIndex = revs.IndexOf(_state.Revision);
                }
            }

            bool anyData = false;

            while (true)
            {
                var data = _reader.Read(_state.Branches, _state.Revision);
                if (data == null)
                {
                    var sha = _state.Commits.OrderByDescending(a => a.Key).SelectMany(a => a.Value).First(a => a.Item1 == _root).Item2;
                    //var sha = _state.Commits[_root][_state.Commits[_root].Keys.Max()];
                    result = sha;
                    break;
                }

                anyData = false;
                foreach (var branch in data.Data)
                {
                    var           mergeString = "";
                    string        sha         = null;
                    List <string> shas        = new List <String>();
                    if (false && branch.Value.Merges.Count > 0)
                    {
                        foreach (var newMerge in branch.Value.Merges)
                        {
                            var toMerge   = newMerge.Value.Item1;
                            var notMerged = newMerge.Value.Item2;
                            for (int i = notMerged.Count - 1; i >= 0; i--)
                            {
                                if (_writer.IsEmpty(_state.Commits[notMerged[i]].Single().Item2))
                                {
                                    //if (_writer.IsEmpty(_state.Commits[newMerge.Key][notMerged[i]]))
                                    notMerged.RemoveAt(i);
                                }
                            }

                            //Console.WriteLine($"processing merge\n{string.Join(", ", toMerge)}\nwithout\n{string.Join(", ", notMerged.Where(a=>a<toMerge[toMerge.Count-1]))}\nfrom {newMerge.Key} to {branch.Key}");

                            if (notMerged.Count == 0)
                            {
                                shas.Add(_state.Commits.OrderByDescending(a => a.Key).SelectMany(a => a.Value).First(a => a.Item1 == newMerge.Key).Item2);
                                //shas.Add(_state.Commits[newMerge.Key][_state.Commits[newMerge.Key].Max(a=>a.Key)]);
                                continue;
                            }

                            if (toMerge[toMerge.Count - 1] < notMerged[0])
                            {
                                shas.Add(_state.Commits.Where(a => a.Key < notMerged[0]).OrderByDescending(a => a.Key).SelectMany(a => a.Value).First(a => a.Item1 == newMerge.Key).Item2);
                                //shas.Add(_state.Commits[newMerge.Key][_state.Commits[newMerge.Key].Where(a=>a.Key<notMerged[0]).Max(a=>a.Key)]);
                                continue;
                            }
                            continue;

                            for (int i = 0; i < toMerge.Count; i++)
                            {
                                if (toMerge[i] > notMerged[0])
                                {
                                    if (i == 0)
                                    {
                                        break;
                                    }
                                    shas.Add(_state.Commits[toMerge[i - 1]].Single().Item2);
                                    //shas.Add(_state.Commits[newMerge.Key][toMerge[i-1]]);
                                    toMerge.RemoveRange(0, i);
                                    break;
                                }
                            }

                            try
                            {
                                var commitsNeeded = toMerge.Union(notMerged).OrderBy(a => a)
                                                    .Select(a => _state.Commits[a]).Select(a => a.Single().Item2).ToList();

                                /*var q = _state.Commits
                                 *  .Where(a => a.Key < Math.Min(toMerge[0], notMerged[0]))
                                 *  .OrderByDescending(a => a.Key).SelectMany(a => a.Value)
                                 *  .Where(a => a.Item1 == newMerge.Key).Select(a => a.Item2).Take(1);
                                 * var commitsNeeded = q.Concat(toMerge.Union(notMerged).OrderBy(a => a)
                                 *      .Select(a => _state.Commits[a]).Select(a => a.Single().Item2)).ToList();*/

                                var commit = _state.Commits.OrderByDescending(a => a.Key).SelectMany(a => a.Value)
                                             .First(a => a.Item1 == newMerge.Key).Item2;
                                //var commit = _state.Commits[newMerge.Key][_state.Commits[newMerge.Key].Max(a => a.Key)];
                                var ba = _writer.Base(
                                    _state.Commits.OrderByDescending(a => a.Key).SelectMany(a => a.Value)
                                    .First(a => a.Item1 == branch.Key).Item2, commit);
                                commitsNeeded.Insert(0, ba);
                                //var ba = _writer.Base(_state.Commits[branch.Key][_state.Commits[branch.Key].Max(a => a.Key)],commit);

                                /*var allowed = _state.Commits.SelectMany(a => a.Value)
                                 *  .Where(a => a.Item1 == newMerge.Key).Select(a => a.Item2).ToList();*/
                                //var allowed = _state.Commits[newMerge.Key].Select(a => a.Value).ToList();
                                var commits = _writer.CommitsToBase(commit, ba, _state, newMerge.Key /*branch.Key*/ /*null*/, commitsNeeded);
                                commits.Reverse();
                                commits.Add(commit);
                                //var commitsAndAllowed = allowed.Union(commits).ToList();
                                //var merged = 0;

                                List <Tuple <string, Task <string> > > tasks = new List <Tuple <string, Task <string> > >();

                                for (int i = 0; i < commits.Count; i++)
                                {
                                    var rev = _state.Commits.Single(a => a.Value.Any(b => b.Item2 == commits[i])).Key;

                                    /*var arr = _state.Commits[newMerge.Key].Where(a => a.Value == commits[i]).ToArray();
                                     * var rev = arr.Single().Key;*/
                                    if (toMerge.Contains(rev))
                                    {
                                        var           i1 = i;
                                        Func <string> f  = () =>
                                        {
                                            var s = commits[i1];
                                            for (int j = i1 - 1; j >= 0; j--)
                                            {
                                                var rev2 = _state.Commits
                                                           .Single(a => a.Value.Any(b => b.Item2 == commits[j])).Key;
                                                //var rev2 = _state.Commits[newMerge.Key].Where(a => a.Value == commits[j]).Single().Key;
                                                if (!toMerge.Contains(rev2))
                                                {
                                                    //s = _writer.Revert(commits[j], s, commits);
                                                    s = _writer.Revert(commits[j], s, _state, newMerge.Key, commitsNeeded);
                                                }
                                            }

                                            return(s);
                                        };
                                        tasks.Add(Tuple.Create(commit, Task.Run(f)));

                                        /*ba = _writer.AddCommit(commits[i], s, ba,
                                         *  $"partial merge from {newMerge.Key} {rev} to {branch.Key}");
                                         * if (!CheckPartial(newMerge.Key, rev, ba))
                                         * {
                                         *  _writer.CreateBranch("LastError", ba);
                                         *  throw new InvalidOperationException();
                                         * }
                                         *
                                         * merged++;*/
                                        /*if (toMerge.Count == merged)
                                         *  break;*/
                                    }
                                }

                                ;

                                foreach (var task in tasks)
                                {
                                    var rev = _state.Commits.Single(a => a.Value.Any(b => b.Item2 == task.Item1)).Key;
                                    ba = _writer.AddCommit(task.Item1, task.Item2.Result, ba,
                                                           $"partial merge from {newMerge.Key} {rev} to {branch.Key}");
                                    if (!CheckPartial(newMerge.Key, rev, ba))
                                    {
                                        _writer.CreateBranch("LastError", ba);
                                        throw new InvalidOperationException();
                                    }
                                }

                                shas.Add(ba);
                            }
                            catch (RevertErrorException)
                            {
                                mergeString = $"merge {string.Join(", ", toMerge)} from {newMerge.Key}\n";
                            }
                            catch (AggregateException e)
                            {
                                if (e.InnerExceptions.First() is RevertErrorException)
                                {
                                    mergeString = $"merge {string.Join(", ", toMerge)} from {newMerge.Key}\n";
                                }
                                else
                                {
                                    throw;
                                }
                            }

                            /*List<long> oldMerges;
                             * if (!_state.Merges.TryGetValue(branch.Key, out var oldMergesRoot))
                             * {
                             *  oldMergesRoot = new Dictionary<string, List<long>>();
                             *  _state.Merges[branch.Key] = oldMergesRoot;
                             * }
                             * if (!oldMergesRoot.TryGetValue(newMerge.Key, out oldMerges))
                             * {
                             *  oldMerges = new List<long>();
                             *  oldMergesRoot[newMerge.Key] = oldMerges;
                             * }
                             *
                             * List<KeyValuePair<long, string>> notMerged = new List<KeyValuePair<long, string>>();
                             * if (_state.Commits.TryGetValue(newMerge.Key, out var com))
                             * {
                             *  var min = _state.Commits[branch.Key].Min(a => a.Key);
                             *  com = com.Where(a => a.Key > min).ToDictionary(a => a.Key, a => a.Value);
                             *  notMerged = com.Where(a => !oldMerges.Contains(a.Key))
                             *      .OrderBy(a => a.Key).ToList();
                             * }
                             *
                             * List<long> toMerge = new List<long>();
                             * foreach (var tuple in newMerge.Value)
                             * {
                             *      var s = notMerged.Where(a => a.Key >= tuple.Item1 && a.Key <= tuple.Item2)
                             *          .Select(a => a.Key).ToList();
                             *
                             *      toMerge.AddRange(s);
                             * }
                             * if (toMerge.Count == notMerged.Count && toMerge.Count > 0)
                             * {
                             *  shas.Add(com[com.Max(a=>a.Key)]);
                             * }
                             * else if(toMerge.Count>0)
                             * {
                             *  try
                             *  {
                             *      var commit =
                             *          _state.Commits[newMerge.Key][_state.Commits[newMerge.Key].Max(a => a.Key)];
                             *      var ba = _writer.Base(
                             *          _state.Commits[branch.Key][_state.Commits[branch.Key].Max(a => a.Key)],
                             *          commit);
                             *      var allowed = _state.Commits[newMerge.Key].Select(a => a.Value).ToList();
                             *      var commits = _writer.CommitsToBase(commit, ba,
                             *          allowed);
                             *      commits.Reverse();
                             *      commits.Add(commit);
                             *      var merged = 0;
                             *      for (int i = 0; i < commits.Count; i++)
                             *      {
                             *          var rev = _state.Commits[newMerge.Key].Where(a => a.Value == commits[i])
                             *              .Single().Key;
                             *          if (toMerge.Contains(rev))
                             *          {
                             *              var s = commits[i];
                             *              for (int j = i - 1; j >= 0; j--)
                             *              {
                             *                  var rev2 = _state.Commits[newMerge.Key]
                             *                      .Where(a => a.Value == commits[j]).Single().Key;
                             *                  if (!toMerge.Contains(rev2))
                             *                  {
                             *                      s = _writer.Revert(commits[j], s, allowed);
                             *                  }
                             *              }
                             *
                             *              ba = _writer.AddCommit(commits[i], s, ba,
                             *                  $"partial merge from {newMerge.Key} {rev} to {branch.Key}");
                             *              if (!CheckPartial(newMerge.Key, rev, ba))
                             *              {
                             *                  _writer.CreateBranch("LastError", ba);
                             *                  throw new InvalidOperationException();
                             *              }
                             *
                             *              merged++;
                             *              if (toMerge.Count == merged)
                             *                  break;
                             *          }
                             *      }
                             *
                             *      shas.Add(ba);
                             *  }
                             *  catch (RevertErrorException)
                             *  {
                             *      mergeString = $"merge {string.Join(", ", toMerge)} from {newMerge.Key}\n";
                             *      shas.Clear();
                             *  }
                             *
                             * }
                             * oldMerges.AddRange(toMerge);*/
                        }
                    }
                    if (branch.Value.CreateBranchFrom != null)
                    {
                        if (_state.Commits.SelectMany(a => a.Value).All(a => a.Item1 != branch.Value.CreateBranchFrom))
                        //if (!_state.Commits.TryGetValue(branch.Value.CreateBranchFrom, out var cc))
                        {
                            var storage = _storage;
                            var key     = branch.Value.CreateBranchFrom + "|" + branch.Value.CreateBranchFromRevision;
                            if (!_state.SubStates.TryGetValue(key, out var s))
                            {
                                s = new State();
                                _state.SubStates[key] = s;
                            }

                            using (var converter = new Converter(branch.Value.CreateBranchFrom,
                                                                 new LimitedReader(branch.Value.CreateBranchFromRevision, _reader), new GitWriter(),
                                                                 storage, s, _prefix,
                                                                 $"create branch \"{branch.Key}\" from \"{branch.Value.CreateBranchFrom}\" revision \"{branch.Value.CreateBranchFromRevision}\"\n" +
                                                                 _descriptionSuffix, _ignoreBranches, _master && branch.Key == _root))
                            {
                                sha = converter.Convert();
                            }

                            /*foreach (var commit in storage.State.Commits)
                             * {
                             *  if (!_state.Commits.ContainsKey(commit.Key))
                             *      _state.Commits[commit.Key] = new Dictionary<long, string>();
                             *  foreach (var commit1 in commit.Value)
                             *  {
                             *      if (!_state.Commits[commit.Key].ContainsKey(commit1.Key))
                             *          _state.Commits[commit.Key][commit1.Key] = commit1.Value;
                             *  }
                             * }*/
                        }
                        else
                        {
                            sha = _state.Commits.OrderByDescending(a => a.Key)
                                  .Where(a => a.Key <= branch.Value.CreateBranchFromRevision).SelectMany(a => a.Value)
                                  .First(a => a.Item1 == branch.Value.CreateBranchFrom).Item2;
                            //sha = cc[cc.Keys.Where(a => a <= branch.Value.CreateBranchFromRevision).Max()];

                            /*if (branch.Value.Data.Count() == 0)
                             * {
                             *  _state.Merges[branch.Key] = new Dictionary<string, List<long>>()
                             *      {{branch.Value.CreateBranchFrom, new List<long>() {_state.Revision}}};
                             * }*/
                        }

                        _state.BranchParents[branch.Key] = branch.Value.CreateBranchFrom;

                        if (!_state.Branches.Contains(branch.Key))
                        {
                            _state.Branches.Add(branch.Key);
                        }

                        /*if(_state.Commits.ContainsKey(branch.Key))
                         *  throw new InvalidOperationException();
                         * if (_state.Commits.ContainsKey(branch.Value.CreateBranchFrom))
                         *  _state.Commits[branch.Key] = _state.Commits[branch.Value.CreateBranchFrom]
                         *      .ToDictionary(a => a.Key, a => a.Value);*/
                    }
                    else if (branch.Value.ParentRenameFrom != null)
                    {
                        var exists = _reader.Exists(branch.Key, _state.Revision);
                        if (exists)
                        {
                            var storage = _storage;
                            var b       = branch.Value.ParentRenameFrom +
                                          branch.Key.Remove(0, branch.Value.ParentRenameTo.Length);
                            var key = b + "|" + branch.Value.ParentRenameFromRevision;
                            if (!_state.SubStates.TryGetValue(key, out var s))
                            {
                                s = new State();
                                _state.SubStates[key] = s;
                            }

                            using (var converter = new Converter(b,
                                                                 new LimitedReader(branch.Value.ParentRenameFromRevision, _reader), new GitWriter(),
                                                                 storage, s, _prefix,
                                                                 $"create branch \"{branch.Key}\" by renaming directory \"{branch.Value.ParentRenameFrom}\" revision \"{branch.Value.CreateBranchFromRevision}\" to branch parent \"{branch.Value.ParentRenameTo}\"\n" +
                                                                 _descriptionSuffix, _ignoreBranches, _master && branch.Key == _root))
                            {
                                sha = converter.Convert();
                            }

                            /*foreach (var commit in storage.State.Commits)
                             * {
                             *  if (!_state.Commits.ContainsKey(commit.Key))
                             *      _state.Commits[commit.Key] = new Dictionary<long, string>();
                             *  foreach (var commit1 in commit.Value)
                             *  {
                             *      if (!_state.Commits[commit.Key].ContainsKey(commit1.Key))
                             *          _state.Commits[commit.Key][commit1.Key] = commit1.Value;
                             *  }
                             * }*/
                        }
                    }
                    else
                    {
                        sha = _state.Commits.OrderByDescending(a => a.Key).SelectMany(a => a.Value)
                              .Where(a => a.Item1 == branch.Key).Select(a => a.Item2).FirstOrDefault();

                        /*if (_state.Commits.TryGetValue(branch.Key, out var a))
                         * {
                         *  if (a.Count > 0)
                         *      sha = a[a.Keys.Max()];
                         * }*/
                    }

                    //if (branch.Value.Data.Any() || branch.Value.CreateBranchFrom != null)
                    {
                        var n = branch.Key;
                        if (_prefix != null)
                        {
                            n = _prefix + "/" + n;
                        }
                        if (_ignoreBranches)
                        {
                            n = null;
                        }
                        Console.WriteLine("branch " + branch.Key + " " + _state.Revision);
                        _writer.StartCommit(_master && branch.Key == _root ? "master" : n, sha);
                        foreach (var action in branch.Value.Data)
                        {
                            action.GitPath = ApplyPrefix(action.GitPath);
                            switch (action.Type)
                            {
                            case ActionType.AddFile:
                            case ActionType.EditFile:
                                _writer.AddFile(action.GitPath, () => _reader.GetObject(action.SvnPath, _state.Revision));

                                var t = action.Type == ActionType.AddFile ? "A" : "M";
                                Console.WriteLine($"{t} {action.GitPath}");
                                break;

                            case ActionType.RemoveFile:
                                _writer.RemoveFile(action.GitPath);
                                Console.WriteLine($"D {action.GitPath}");
                                break;

                            case ActionType.RemoveDir:
                                _writer.RemoveDir(action.GitPath);
                                Console.WriteLine($"D {action.GitPath}");
                                break;

                            case ActionType.CopyDir:
                                _writer.RemoveDir(action.GitPath);
                                var sha1 = GetSha(action.Branch, action.FromRevision);
                                var pp   = action.FromPath;
                                if (_prefix != null)
                                {
                                    pp = _prefix + "/" + action.FromPath;
                                }
                                var files = _writer.GetFiles(sha1, pp);    //todo: change to tree
                                foreach (var file in files)
                                {
                                    var p = file.Item1.Remove(0, pp.Length + 1);
                                    _writer.AddFile(action.GitPath + "/" + p, file.Item2);
                                    Console.WriteLine($"A {file.Item1}");
                                }
                                break;

                            case ActionType.CopyDirFromExternal:
                                var key = action.FromPath + "|" + action.FromRevision;
                                if (!_state.SubStates.TryGetValue(key, out var s))
                                {
                                    s = new State();
                                    _state.SubStates[key] = s;
                                }

                                using (var converter = new Converter(action.FromPath,
                                                                     new LimitedReader(action.FromRevision, _reader), new GitWriter(),
                                                                     _storage, s, action.GitPath,
                                                                     $"copy external directory \"{action.FromPath}\" revision {action.FromRevision} to path \"{action.GitPath}\" of branch \"{branch.Key}\"\n" +
                                                                     _descriptionSuffix, true, false))
                                {
                                    sha1 = converter.Convert();
                                }

                                files = _writer.GetFiles(sha1, action.GitPath);
                                foreach (var file in files)
                                {
                                    _writer.AddFile(file.Item1, file.Item2);
                                    Console.WriteLine($"A {file.Item1}");
                                }

                                shas.Add(sha1);
                                break;

                            default:
                                throw new NotImplementedException();
                            }
                        }//);

                        sha = _writer.EndCommit(data.Author,
                                                data.Message + $"\n\nbranch {branch.Key} revision {_state.Revision}\n{mergeString}{_descriptionSuffix}",
                                                data.Time, shas);
                    }

                    if (branch.Value.RemoveBranch)
                    {
                        _state.Branches.Remove(branch.Key);
                        var n = "/" + branch.Key;
                        if (_prefix != null)
                        {
                            n = "/" + _prefix + n;
                        }
                        _writer.RenameBranch(n, "removed" + n + "_" + _state.Revision);
                        continue;
                    }

                    /*if (!_state.Commits.TryGetValue(branch.Key, out var c))
                     * {
                     *  c = new Dictionary<long, string>();
                     *  _state.Commits[branch.Key] = c;
                     * }*/

                    if (sha != null)
                    {
                        if (!_state.Commits.TryGetValue(_state.Revision, out var v))
                        {
                            v = new List <Tuple <string, string> >();
                            _state.Commits[_state.Revision] = v;
                        }
                        v.Add(Tuple.Create(branch.Key, sha));
                        //c[_state.Revision] = sha;
                        if (!Check(branch.Key, _state.Revision, sha))
                        {
                            _writer.CreateBranch("LastError", sha);
                            throw new InvalidOperationException();
                        }

                        anyData = true;
                    }
                }

                if (anyData)
                {
                    Console.WriteLine("end " + _state.Revision);
                }
                if (_ignoreBranches)
                {
                    if (revsIndex >= revs.Count - 1)
                    {
                        _state.Revision++;
                    }
                    else
                    {
                        _state.Revision = revs[++revsIndex];
                    }
                }
                else
                {
                    _state.Revision++;
                }

                //_writer.Pack();
                if (anyData)
                {
                    _storage.Save("revision: " + (_state.Revision - 1) + "\n" + _descriptionSuffix);
                }
                if (anyData && _random.Next(100) == 0)
                {
                    throw new NeedGcException();
                }
            }
            if (!anyData)
            {
                _storage.Save("revision: " + _state.Revision + "\n" + _descriptionSuffix);
            }
            return(result);
        }