ide: refactoring version control issues

git-svn-id: svn://ultimatepp.org/upp/trunk@11356 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2017-10-08 20:26:03 +00:00
parent e871a17613
commit 1f95d4c13c
21 changed files with 942 additions and 44 deletions

View file

@ -274,7 +274,7 @@ void ArrayCtrl::SetCtrl(int i, int j, Ctrl& ctrl, bool value)
SyncLineCtrls(i);
}
Ctrl * ArrayCtrl::GetCtrl(int i, int col)
Ctrl *ArrayCtrl::GetCtrl(int i, int col)
{
SyncLineCtrls(i);
if(IsCtrl(i, col))

View file

@ -315,13 +315,13 @@ Vector<String> SelectPackageDlg::GetSvnDirs()
void SelectPackageDlg::SyncSvnDir(const String& dir)
{
SvnSyncDirs(Vector<String>() << dir);
RepoSyncDirs(Vector<String>() << dir);
Load();
}
void SelectPackageDlg::SyncSvnDirs()
{
SvnSyncDirs(GetSvnDirs());
RepoSyncDirs(GetSvnDirs());
Load();
}

View file

@ -1,8 +1,7 @@
description "TheIDE - Source codes management\377B";
uses
CtrlLib,
usvn;
CtrlLib;
file
SrcUpdater.h,

View file

@ -259,7 +259,7 @@ struct WorkspaceWork {
int actualfileindex;
Package actual;
bool editormode;
bool svn_dirs;
bool repo_dirs;
struct Sepfo : Moveable<Sepfo> {
String package;
@ -306,7 +306,7 @@ struct WorkspaceWork {
void RestoreBackup();
void SyncErrorPackages();
Vector<String> SvnDirs(bool actual = false);
Vector<String> RepoDirs(bool actual = false);
void SerializeFileSetup(Stream& s) { s % filelist % package; }

View file

@ -273,7 +273,7 @@ void WorkspaceWork::PackageCursor()
InvalidatePackageCache();
filelist.WhenBar.Clear();
actualpackage = GetActivePackage();
svn_dirs = false;
repo_dirs = false;
if(actualpackage.IsEmpty()) return;
if(actualpackage == METAPACKAGE) {
actual.file.Clear();
@ -292,18 +292,17 @@ void WorkspaceWork::PackageCursor()
filelist.Enable();
if(actualpackage != METAPACKAGE)
filelist.WhenBar = THISBACK(FileMenu);
svn_dirs = SvnDirs(true).GetCount();
repo_dirs = RepoDirs(true).GetCount();
}
Vector<String> WorkspaceWork::SvnDirs(bool actual)
Vector<String> WorkspaceWork::RepoDirs(bool actual)
{
Vector<String> d = GetUppDirs();
if (actual && !IsAux())
d.Insert(0, GetFileFolder(PackagePath(actualpackage)));
Vector<String> r;
for(int i = 0; i < d.GetCount(); i++)
if(IsSvnDir(d[i]))
r.Add(d[i]);
r.Add(d[i]);
return r;
}
@ -1123,7 +1122,7 @@ WorkspaceWork::WorkspaceWork()
filelist.WhenDropInsert = THISBACK(DnDInsert);
showtime = false;
sort = true;
svn_dirs = false;
repo_dirs = false;
}
void WorkspaceWork::SerializeClosed(Stream& s)

View file

@ -9,6 +9,7 @@
#include <TabBar/TabBar.h>
#include <CodeEditor/CodeEditor.h>
#include <usvn/usvn.h>
#include <urepo/urepo.h>
#include <ide/IconDes/IconDes.h>
#include <ide/Java/Java.h>
#include <ide/LayDes/LayDes.h>
@ -309,7 +310,7 @@ void DlSpellerLangs(DropList& dl);
void DirSel(EditField& f, FrameRight<Button>& b);
bool CopyFolder(const char *dst, const char *src, Progress *pi);
void SvnSyncDirs(const Vector<String>& working);
void RepoSyncDirs(const Vector<String>& working);
struct FindInFilesDlg : WithFindInFilesLayout<TopWindow> {
WString itext;
@ -333,7 +334,7 @@ public:
virtual void PackageCursor();
virtual void SyncWorkspace();
virtual void BuildFileMenu(Bar& menu);
virtual void ProjectSvn(Bar& bar);
virtual void ProjectRepo(Bar& bar);
virtual void FilePropertiesMenu(Bar& menu);
virtual String GetOutputDir();
virtual String GetConfigDir();
@ -850,9 +851,9 @@ public:
void ConvertST();
void ExportMakefile(const String& ep);
void ExportProject(const String& ep, bool all, bool gui, bool deletedir = true);
void SyncSvnDirs(const Vector<String>& working);
void SyncSvnDir(const String& working);
void SyncSvn();
void SyncRepoDirs(const Vector<String>& working);
void SyncRepoDir(const String& working);
void SyncRepo();
void BuildMenu(Bar& menu);
void BuildPackageMenu(Bar& menu);

View file

@ -14,13 +14,14 @@ uses
HexView,
art\BlueBar,
plugin/astyle,
usvn,
TextDiffCtrl,
TabBar,
ide/Designers,
ide/Android,
ide/Java,
ide/MacroManager;
ide/MacroManager,
urepo,
usvn;
uses(POSIX) ide\SrcUpdater;

View file

@ -403,12 +403,12 @@ void Ide::SetupAndroidMobilePlatform(Bar& menu, const AndroidSDK& androidSDK)
menu.Add("Device monitor", THISBACK1(LauchAndroidDeviceMonitor, androidSDK));
}
void Ide::ProjectSvn(Bar& menu)
void Ide::ProjectRepo(Bar& menu)
{
Vector<String> w = SvnDirs(true);
Vector<String> w = RepoDirs(true);
for(int i = 0; i < w.GetCount(); i++)
menu.Add("Synchronize " + w[i], IdeImg::svn_dir(), THISBACK1(SyncSvnDir, w[i]));
menu.Add("Synchronize everything..", IdeImg::svn(), THISBACK(SyncSvn));
menu.Add("Synchronize " + w[i], IdeImg::svn_dir(), THISBACK1(SyncRepoDir, w[i]));
menu.Add("Synchronize everything..", IdeImg::svn(), THISBACK(SyncRepo));
}
void Ide::Project(Bar& menu)
@ -444,11 +444,11 @@ void Ide::Project(Bar& menu)
}
FilePropertiesMenu(menu);
if(!IsEditorMode()) {
if(svn_dirs) {
if(repo_dirs) {
if(menu.IsMenuBar())
menu.Add("SVN", THISBACK(ProjectSvn));
menu.Add("Repo", THISBACK(ProjectRepo));
else
menu.Add("SVN Synchronize everything..", IdeImg::svn(), THISBACK(SyncSvn));
menu.Add("Synchronize all repositories..", IdeImg::svn(), THISBACK(SyncRepo));
}
}
}

View file

@ -382,7 +382,7 @@ void Ide::FlushFile() {
Filedata(editfile).undodata = editor.PickUndoData();
editfile.Clear();
editfile_svn = editfile_isfolder = false;
svn_dirs = SvnDirs(true).GetCount(); // Perhaps not the best place, but should be ok
repo_dirs = RepoDirs(true).GetCount(); // Perhaps not the best place, but should be ok
editor.Clear();
editor.Disable();
editorsplit.Ctrl::Remove();
@ -437,7 +437,7 @@ void Ide::EditFile0(const String& path, byte charset, int spellcheck_comments, c
AddLru();
editfile_isfolder = IsFolder(editfile) || IsHelpName(editfile);
svn_dirs = SvnDirs(true).GetCount(); // Perhaps not the best place, but should be ok
repo_dirs = RepoDirs(true).GetCount(); // Perhaps not the best place, but should be ok
bool candesigner = !(debugger && !editfile_isfolder && (PathIsEqual(path, posfile[0]) || PathIsEqual(path, posfile[0])))
&& editastext.Find(path) < 0 && editashex.Find(path) < 0 && !IsNestReadOnly(editfile);

View file

@ -415,44 +415,43 @@ INITBLOCK {
RegisterGlobalConfig("svn-msgs");
}
void SvnSyncDirs(const Vector<String>& working)
void RepoSyncDirs(const Vector<String>& working)
{
if(!CheckSvn())
return;
Ptr<Ctrl> f = Ctrl::GetFocusCtrl();
SvnSync svn;
RepoSync repo;
String msgs;
LoadFromGlobal(msgs, "svn-msgs");
svn.SetMsgs(msgs);
repo.SetMsgs(msgs);
for(int i = 0; i < working.GetCount(); i++)
svn.Dir(working[i]);
svn.DoSync();
msgs = svn.GetMsgs();
repo.Dir(working[i]);
repo.DoSync();
msgs = repo.GetMsgs();
StoreToGlobal(msgs, "svn-msgs");
if(f)
f->SetFocus();
}
void Ide::SyncSvnDirs(const Vector<String>& working)
void Ide::SyncRepoDirs(const Vector<String>& working)
{
SaveFile();
SvnSyncDirs(working);
RepoSyncDirs(working);
ScanWorkspace();
SyncWorkspace();
}
void Ide::SyncSvn()
{
Vector<String> d = SvnDirs();
void Ide::SyncRepo(){
Vector<String> d = RepoDirs();
if(d.GetCount())
SyncSvnDirs(d);
SyncRepoDirs(d);
else
SyncSvnDirs(SvnDirs(true));
SyncRepoDirs(RepoDirs(true));
}
void Ide::SyncSvnDir(const String& working)
void Ide::SyncRepoDir(const String& working)
{
SyncSvnDirs(Vector<String>() << working);
SyncRepoDirs(Vector<String>() << working);
}
void Ide::GotoDirDiffLeft(int line, DirDiffDlg *df)

74
uppsrc/urepo/Console.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "urepo.h"
UrepoConsole::UrepoConsole()
{
CtrlLayoutExit(*this, "System Console");
list.NoHeader().NoGrid().NoCursor().AddColumn();
font = Courier(Ctrl::VertLayoutZoom(12));
list.SetLineCy(font.Info().GetHeight());
exit.Hide();
}
void UrepoConsole::AddResult(const String& out)
{
Vector<String> h = Split(out, CharFilterCrLf);
for(int i = 0; i < h.GetCount(); i++) {
String s = " " + h[i];
list.Add(AttrText(s).SetFont(font), s);
}
list.GoEnd();
}
int UrepoConsole::System(const char *cmd)
{
if(!IsOpen())
Open();
list.Add(AttrText(cmd).SetFont(font().Bold()).Ink(LtBlue));
int ii = list.GetCount();
LocalProcess p;
if(!p.Start(cmd))
return -1;
String out;
while(p.IsRunning()) {
String h = p.Get();
out.Cat(h);
int lf = out.ReverseFind('\n');
if(lf >= 0) {
AddResult(out.Mid(0, lf + 1));
out = out.Mid(lf + 1);
}
ProcessEvents();
Sleep(h.GetCount() == 0); // p.Wait would be much better here!
}
out.Cat(p.Get());
AddResult(out);
ProcessEvents();
int code = p.GetExitCode();
if(code)
while(ii < list.GetCount()) {
list.Set(ii, 0, AttrText((String)list.Get(ii, 1)).SetFont(font).Ink(LtRed));
ii++;
}
return code;
}
int UrepoConsole::CheckSystem(const char *s)
{
int exitcode = System(s);
if(exitcode) {
if(exitcode < 0)
AddResult("Error running " + String(s));
else
AddResult("exitcode = " + FormatInt(exitcode));
}
return exitcode;
}
int UrepoConsole::Git(const char *dir, const char *command)
{
String h = GetCurrentDirectory();
SetCurrentDirectory(dir);
int code = CheckSystem(String() << "git " << command);
SetCurrentDirectory(h);
return code;
}

22
uppsrc/urepo/Copying Normal file
View file

@ -0,0 +1,22 @@
Copyright (c) 1998, 2014, The U++ Project
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

130
uppsrc/urepo/Diff.cpp Normal file
View file

@ -0,0 +1,130 @@
#include "urepo.h"
#define IMAGECLASS UrepoImg
#define IMAGEFILE <urepo/urepo.iml>
#include <Draw/iml.h>
struct RepoDiff : DiffDlg {
FrameTop<DropList> r;
int kind;
void Load();
void Execute(const String& f);
typedef RepoDiff CLASSNAME;
RepoDiff();
};
void RepoDiff::Execute(const String& f)
{
kind = GetRepoKind(f);
editfile = f;
if(kind == SVN_DIR) {
WaitCursor wait;
String log = Sys("svn log " + f);
if(log.IsVoid()) {
Exclamation("Error executing 'svn log'");
return;
}
StringStream ss(log);
while(!ss.IsEof()) {
String l = ss.GetLine();
if(l[0] == 'r') {
Vector<String> h = Split(l, '|');
if(h.GetCount() > 3) {
String rev = TrimBoth(h[0]);
String s = rev;
Vector<String> t = Split(h[2], ' ');
if(t.GetCount() > 1)
s << ' ' << t[0];
s << ' ' << TrimBoth(h[1]);
while(!ss.IsEof()) {
l = ss.GetLine();
if(l.GetCount()) {
if(l[0] != '-')
s << ": " << l;
break;
}
}
r.Add(rev, s);
}
}
}
}
if(kind == GIT_DIR) {
String log = GitCmd(GetFileFolder(f), "log --format=medium --date=short " + GetFileName(f));
StringStream ss(log);
String author, date, commit;
while(!ss.IsEof()) {
String l = ss.GetLine();
Vector<String> s = Split(l, CharFilterWhitespace);
if(s.GetCount() == 0) {
while(!ss.IsEof()) {
l = ss.GetLine();
if(l.GetCount())
break;
}
String msg = l;
while(!ss.IsEof()) {
l = ss.GetLine();
if(l.GetCount() == 0)
break;
msg << l;
}
if(commit.GetCount())
r.Add(commit, date + ' ' + author + ": " + Join(Split(msg, CharFilterWhitespace), " "));
date = commit = author = Null;
}
else
if(s.GetCount() >= 2) {
String k = ToLower(s[0]);
if(k == "author:")
author = s[1];
if(k == "date:")
date = s[1];
if(k == "commit")
commit = s[1];
}
}
Load();
}
if(r.GetCount() == 0) {
Exclamation("No parsable history for the file");
return;
}
r.SetIndex(0);
Load();
DiffDlg::Execute(f);
}
void RepoDiff::Load()
{
if(kind == SVN_DIR)
extfile = Sys("svn cat " + editfile + '@' + AsString(~r), false);
if(kind == GIT_DIR)
extfile = GitCmd(GetFileFolder(editfile), "show " + ~~r + ":./" + GetFileName(editfile));
diff.Set(LoadFile(editfile), extfile);
}
RepoDiff::RepoDiff()
{
r.Height(EditField::GetStdHeight());
r.SetDropLines(32);
Icon(UrepoImg::RepoDiff());
diff.InsertFrameRight(r);
r <<= THISBACK(Load);
}
void RunRepoDiff(const String& filepath)
{
if(IsNull(filepath))
return;
RepoDiff dlg;
dlg.Execute(filepath);
}

476
uppsrc/urepo/RepoSync.cpp Normal file
View file

@ -0,0 +1,476 @@
#include "urepo.h"
String SvnCmd(const char *cmd)
{
return String() << "svn " << cmd << " --non-interactive ";
}
RepoSync::RepoSync()
{
CtrlLayoutOKCancel(*this, "Version control repository synchronize");
list.AddIndex();
list.AddIndex();
list.AddColumn("Action");
list.AddColumn("Path");
list.AddColumn("Changes");
list.ColumnWidths("220 500 100");
list.NoCursor().EvenRowColor();
list.SetLineCy(max(Draw::GetStdFontCy(), 20));
Sizeable().Zoomable();
BackPaint();
}
int CharFilterSvnMsgRepo(int c)
{
return c >= 32 && c < 128 && c != '\"' ? c : 0;
}
bool RepoSync::ListSvn(const String& path)
{
Vector<String> ln = Split(Sys("svn status " + path), CharFilterCrLf);
bool actions = false;
for(int pass = 0; pass < 2; pass++)
for(int i = 0; i < ln.GetCount(); i++) {
String h = ln[i];
if(h.GetCount() > 7) {
String file = GetFullPath(TrimLeft(h.Mid(7)));
if(IsFullPath(file)) {
actions = true;
h.Trim(7);
bool simple = h.Mid(1, 6) == " ";
int action = simple ? String("MC?!~").Find(h[0]) : SVN_IGNORE;
if(h == " S ")
action = REPLACE;
String an;
Color color;
if(action == SVN_IGNORE) {
color = Black;
if(simple && h[0] == 'A') {
an = "svn add";
action = SVN_ACTION;
}
else
if(simple && h[0] == 'D') {
an = "svn delete";
action = SVN_ACTION;
}
else {
an = h.Mid(0, 7);
color = Gray;
}
}
else {
int q = file.ReverseFind('.');
if(action == ADD && q >= 0 && (file.Mid(q + 1) == "mine" ||
file[q + 1] == 'r' && IsDigit(file[q + 2]))
&& FileExists(file.Mid(0, q))) {
action = DELETEC;
an = "Delete (conflict resolved)";
color = Black;
}
else {
static const char *as[] = {
"Modify", "Resolved", "Add", "Remove", "Replace"
};
static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta };
an = as[action];
color = c[action];
}
}
if(pass == action < 0) {
int ii = list.GetCount();
list.Add(action, file, Null,
AttrText(action < 0 ? ln[i] : " " + file.Mid(path.GetCount() + 1)).Ink(color));
if(action >= 0) {
list.SetCtrl(ii, 0, revert.Add().SetLabel(an + (action == ADD ? "\nSkip" : "\nRevert")).NoWantFocus());
revert.Top() <<= 0;
Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus();
b <<= THISBACK1(DoDiff, ii);
list.SetCtrl(ii, 2, b);
}
}
}
}
}
return actions;
}
String GitCmd(const char *dir, const char *command)
{
DDUMP(dir);
DDUMP(command);
String h = GetCurrentDirectory();
SetCurrentDirectory(dir);
String r = Sys(String() << "git " << command);
SetCurrentDirectory(h);
DDUMP(r);
return r;
}
bool RepoSync::ListGit(const String& path)
{
Vector<String> ln = Split(GitCmd(path, "status --porcelain ."), CharFilterCrLf);
bool actions = false;
for(int i = 0; i < ln.GetCount(); i++) {
String h = ln[i];
if(h.GetCount() > 3) {
String file = AppendFileName(path, h.Mid(3));
actions = true;
int action = String("M.?DR").Find(h[1]);
if(action < 0 || h[0] != '?' && h[0] != ' ')
action = SVN_IGNORE;
String an;
Color color;
if(action == SVN_IGNORE) {
an = h;
color = Gray;
}
else {
int q = file.ReverseFind('.');
static const char *as[] = {
"Modify", "Resolved", "Add", "Remove", "Rename"
};
static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta };
an = as[action];
color = c[action];
}
int ii = list.GetCount();
list.Add(action, file, Null, AttrText(action < 0 ? h : file).Ink(color));
if(action >= 0) {
list.SetCtrl(ii, 0, revert.Add().SetLabel(an + (action == ADD ? "\nSkip" : "\nRevert")).NoWantFocus());
revert.Top() <<= 0;
Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus();
b <<= THISBACK1(DoDiff, ii);
list.SetCtrl(ii, 2, b);
}
}
}
return actions;
}
void RepoSync::SyncCommits()
{
bool commit = true;
for(int i = 0; i < list.GetCount(); i++) {
if(SvnOptions *o = dynamic_cast<SvnOptions *>(list.GetCtrl(i, 0)))
commit = o->commit;
else
if(GitOptions *o = dynamic_cast<GitOptions *>(list.GetCtrl(i, 0)))
commit = o->commit;
else {
for(int j = 0; j < 2; j++) {
Ctrl *ctrl = list.GetCtrl(i, j);
if(ctrl)
ctrl->Enable(commit);
}
}
}
}
void RepoSync::SyncList()
{
list.Clear();
for(const auto& w : work) {
String path = GetFullPath(w.dir);
int hi = list.GetCount();
list.Add(REPOSITORY, path,
AttrText().Paper(SColorInfo),
AttrText(path).SetFont(ArialZ(20).Bold()).Paper(SColorInfo).Ink(Black),
AttrText().Paper(SColorInfo));
list.SetLineCy(hi, Zy(26));
bool actions;
if(w.kind == SVN_DIR) {
auto& o = list.CreateCtrl<SvnOptions>(hi, 0, false);
o.SizePos();
o.commit = true;
o.commit << [=] { SyncCommits(); };
o.update = true;
actions = ListSvn(path);
if(!actions) {
o.commit = false;
o.commit.Disable();
}
}
if(w.kind == GIT_DIR) {
auto& o = list.CreateCtrl<GitOptions>(hi, 0, false);
o.SizePos();
o.commit = true;
o.commit << [=] { SyncCommits(); };
o.push = true;
o.pull = true;
actions = ListGit(path);
if(!actions) {
o.commit = false;
o.commit.Disable();
}
}
if(actions) {
list.Add(MESSAGE, Null, AttrText("Commit message:").SetFont(StdFont().Bold()));
list.SetLineCy(list.GetCount() - 1, (3 * EditField::GetStdHeight()) + 4);
list.SetCtrl(list.GetCount() - 1, 1, message.Add().SetFilter(CharFilterSvnMsgRepo).VSizePos(2, 2).HSizePos());
int q = msgmap.Find(w.dir);
if(q >= 0) {
message.Top() <<= msgmap[q];
msgmap.Unlink(q);
}
}
else
list.Add(-1, Null, "", AttrText("Nothing to do").SetFont(StdFont().Italic()));
}
}
void RepoSync::DoDiff(int ii)
{
String f = list.Get(ii, 1);
if(!IsNull(f))
RunRepoDiff(f);
}
#ifdef PLATFORM_WIN32
void sRepoDeleteFolderDeep(const char *dir)
{
{
FindFile ff(AppendFileName(dir, "*.*"));
while(ff) {
String name = ff.GetName();
String p = AppendFileName(dir, name);
if(ff.IsFile()) {
SetFileAttributes(p, GetFileAttributes(p) & ~FILE_ATTRIBUTE_READONLY);
FileDelete(p);
}
else
if(ff.IsFolder())
sRepoDeleteFolderDeep(p);
ff.Next();
}
}
DirectoryDelete(dir);
}
#else
void sRepoDeleteFolderDeep(const char *path)
{
DeleteFolderDeep(path);
}
#endif
void RepoSvnDel(const char *path)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
if(ff.IsFolder()) {
String dir = AppendFileName(path, ff.GetName());
if(ff.GetName() == ".svn")
sRepoDeleteFolderDeep(dir);
else
RepoSvnDel(dir);
}
ff.Next();
}
}
void RepoSync::Dir(const char *dir, int kind)
{
Work& d = work.Add();
d.dir = dir;
d.kind = kind;
}
void RepoSync::Dir(const char *dir)
{
int kind = GetRepoKind(dir);
if(kind)
Dir(dir, kind);
}
void RepoMoveSvn(const String& path, const String& tp)
{
FindFile ff(AppendFileName(path, "*.*"));
while(ff) {
String nm = ff.GetName();
String s = AppendFileName(path, nm);
String t = AppendFileName(tp, nm);
if(ff.IsFolder()) {
if(nm == ".svn")
FileMove(s, t);
else
RepoMoveSvn(s, t);
}
ff.Next();
}
}
void RepoSync::DoSync()
{
SyncList();
msgmap.Sweep();
again:
Enable();
if(Run() != IDOK || list.GetCount() == 0) {
int repoi = 0;
for(int i = 0; i < list.GetCount(); i++)
if(list.Get(i, 0) == MESSAGE)
msgmap.GetAdd(work[repoi++].dir) = list.Get(i, 3);
return;
}
Disable();
bool changes = false;
for(int i = 0; i < list.GetCount(); i++) {
int action = list.Get(i, 0);
if(action == MESSAGE) {
if(changes && IsNull(list.Get(i, 3)) && list.GetCtrl(i, 1)->IsEnabled()
&& !PromptYesNo("Commit message is empty.&Do you want to continue?"))
goto again;
changes = false;
}
else if(action != REPOSITORY && list.Get(i, 2) == 0)
changes = true;
}
UrepoConsole sys;
int repoi = 0;
int l = 0;
String repo_dir;
while(l < list.GetCount()) {
SvnOptions *svn = dynamic_cast<SvnOptions *>(list.GetCtrl(l, 0));
GitOptions *git = dynamic_cast<GitOptions *>(list.GetCtrl(l, 0));
String repo_dir = work[repoi++].dir;
l++;
String message;
String filelist; // <-- list of files to update
bool commit = false;
while(l < list.GetCount()) {
int action = list.Get(l, 0);
if(action == REPOSITORY)
break;
String path = list.Get(l, 1);
bool revert = list.Get(l, 2) == 1;
if(svn && svn->commit) {
if(action == MESSAGE && commit) {
String msg = list.Get(l, 3);
if(sys.CheckSystem(SvnCmd("commit") << filelist << " -m \"" << msg << "\""))
msgmap.GetAdd(repo_dir) = msg;
l++;
break;
}
if(SvnFile(sys, filelist, action, path, revert))
commit = true;
}
if(git && git->commit) {
if(action == MESSAGE && commit) {
String msg = list.Get(l, 3);
if(sys.Git(repo_dir, "commit -a -m \"" << msg << "\""))
msgmap.GetAdd(repo_dir) = msg;
l++;
break;
}
if(GitFile(sys, action, path, revert))
commit = true;
}
l++;
}
if(svn && svn->update)
sys.CheckSystem(SvnCmd("update").Cat() << repo_dir);
if(git && git->push)
sys.Git(repo_dir, "push");
if(git && git->pull)
sys.Git(repo_dir, "pull");
}
sys.Perform();
}
bool RepoSync::GitFile(UrepoConsole& sys, int action, const String& path, bool revert)
{
String repo_dir = GetFileFolder(path);
String file = GetFileName(path);
if(revert) {
if(action != ADD)
sys.Git(repo_dir, "checkout \"" + file + "\"");
return false;
}
if(action == ADD)
sys.Git(repo_dir, "add \"" + file + "\"");
return true;
}
bool RepoSync::SvnFile(UrepoConsole& sys, String& filelist, int action, const String& path, bool revert)
{
if(revert) {
if(action == REPLACE)
DeleteFolderDeep(path);
if(action != ADD)
sys.CheckSystem("svn revert \"" + path + "\"");
return false;
}
if(action != DELETEC)
filelist << " \"" << path << "\""; // <-- add the file to the list
switch(action) {
case ADD:
RepoSvnDel(path);
sys.CheckSystem("svn add --force \"" + path + "\"");
break;
case REMOVE:
sys.CheckSystem("svn delete \"" + path + "\"");
break;
case CONFLICT:
sys.CheckSystem("svn resolved \"" + path + "\"");
break;
case REPLACE: {
RepoSvnDel(path);
String tp = AppendFileName(GetFileFolder(path), Format(Uuid::Create()));
FileMove(path, tp);
sys.CheckSystem(SvnCmd("update") << " \"" << path << "\"");
RepoMoveSvn(path, tp);
sRepoDeleteFolderDeep(path);
FileMove(tp, path);
Vector<String> ln = Split(Sys("svn status \"" + path + "\""), CharFilterCrLf);
for(int l = 0; l < ln.GetCount(); l++) {
String h = ln[l];
if(h.GetCount() > 7) {
String file = h.Mid(7);
if(IsFullPath(file)) {
h.Trim(7);
if(h == "? ")
sys.CheckSystem("svn add --force \"" + file + "\"");
if(h == "! ")
sys.CheckSystem("svn delete \"" + file + "\"");
}
}
}
}
break;
case DELETEC:
FileDelete(path);
break;
}
return findarg(action, SVN_IGNORE, DELETEC) < 0;
}
void RepoSync::SetMsgs(const String& s)
{
LoadFromString(msgmap, s);
}
String RepoSync::GetMsgs()
{
return StoreAsString(msgmap);
}
int GetRepoKind(const String& p)
{
if(IsNull(p))
return NOT_REPO_DIR;
if(DirectoryExists(AppendFileName(p, ".svn")) || DirectoryExists(AppendFileName(p, "_svn")))
return SVN_DIR;
String path = p;
String path0;
while(path != path0) {
path0 = path;
if(DirectoryExists(AppendFileName(path, ".git")))
return GIT_DIR;
DirectoryUp(path);
if(DirectoryExists(AppendFileName(path, ".svn")))
return SVN_DIR;
}
return NOT_REPO_DIR;
}

22
uppsrc/urepo/main.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "urepo.h"
#ifdef flagMAIN
GUI_APP_MAIN
{
DDUMP(GetRepoKind("c:/u/sandbox/se"));
DDUMP(GetRepoKind("c:/u/foamiemaker"));
/*
RunRepoDiff("c:\\u\\foamiemaker\\foamiemaker\\View.cpp");
return;
*/
RepoSync ss;
String mp = ConfigFile("usvn.msg");
ss.SetMsgs(LoadFile(mp));
ss.Dir("c:/u/foamiemaker");
ss.Dir("C:\\u\\sandbox\\se");
// ss.Dir("C:\\u\\sandbox\\arduino");
// ss.Dir("C:\\u\\sandbox\\uppdev");
ss.DoSync();
SaveFile(mp, ss.GetMsgs());
}
#endif

94
uppsrc/urepo/urepo.h Normal file
View file

@ -0,0 +1,94 @@
#ifndef _urepo_urepo_h_
#define _urepo_urepo_h_
#include <TextDiffCtrl/TextDiffCtrl.h>
using namespace Upp;
#define LAYOUTFILE <urepo/urepo.lay>
#include <CtrlCore/lay.h>
class UrepoConsole : public WithUrepoConsoleLayout<TopWindow> {
typedef UrepoConsole CLASSNAME;
Font font;
void AddResult(const String& out);
public:
int System(const char *s);
int CheckSystem(const char *s);
int Git(const char *dir, const char *command);
void Perform() { exit.Show(); Execute(); }
UrepoConsole();
};
String SvnCmd(const char *cmd);
enum { NOT_REPO_DIR, SVN_DIR, GIT_DIR };
int GetRepoKind(const String& p);
String GitCmd(const char *dir, const char *command);
struct RepoSync : WithRepoSyncLayout<TopWindow> {
enum {
MODIFY,
CONFLICT,
ADD,
REMOVE,
REPLACE,
REPOSITORY,
MESSAGE,
SVN_IGNORE = -1,
DELETEC = -2,
SVN_ACTION = -3,
};
Array<Switch> revert;
Array<DocEdit> message;
Array<Button> diff;
ArrayMap<String, String> msgmap;
struct SvnOptions : WithSvnOptionsLayout<ParentCtrl> {
SvnOptions() { CtrlLayout(*this); }
};
struct GitOptions : WithGitOptionsLayout<ParentCtrl> {
GitOptions() { CtrlLayout(*this); }
};
struct Work {
int kind;
String dir;
};
Array<Work> work;
bool ListGit(const String& path);
bool ListSvn(const String& path);
bool GitFile(UrepoConsole& sys, int action, const String& path, bool revert);
bool SvnFile(UrepoConsole& sys, String& filelist, int action, const String& path, bool revert);
void SyncCommits();
void SyncList();
void DoDiff(int ii);
typedef RepoSync CLASSNAME;
public:
void SetMsgs(const String& s);
String GetMsgs();
void Dir(const char *dir, int kind);
void Dir(const char *dir);
void DoSync();
RepoSync();
};
void RunRepoDiff(const String& filepath);
#endif

9
uppsrc/urepo/urepo.iml Normal file
View file

@ -0,0 +1,9 @@
PREMULTIPLIED
IMAGE_ID(RepoDiff)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,99,16,96,16,96,24,68,224,63,62,44,16,33,128,23,131,212,60,120,240,0,43,134,233,103,192,1,105,161,31)
IMAGE_DATA(153,143,162,159,129,176,126,108,102,161,216,207,128,91,63,161,112,68,193,52,176,159,26,254,71,55,7,111,248,51,224,214)
IMAGE_DATA(15,18,59,112,224,0,110,253,64,113,16,192,229,126,144,94,156,250,161,122,145,245,83,152,126,7,20,0,0,49,101,131)
IMAGE_DATA(129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(128, 1)

22
uppsrc/urepo/urepo.lay Normal file
View file

@ -0,0 +1,22 @@
LAYOUT(RepoSyncLayout, 680, 400)
ITEM(ArrayCtrl, list, AutoHideSb(true).HSizePosZ(4, 4).VSizePosZ(4, 36))
ITEM(Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(4, 64).BottomPosZ(4, 24))
ITEM(Button, ok, SetLabel(t_("Synchronize!")).RightPosZ(4, 84).BottomPosZ(4, 24))
END_LAYOUT
LAYOUT(UrepoConsoleLayout, 680, 660)
ITEM(ArrayCtrl, list, HSizePosZ(4, 4).VSizePosZ(4, 40))
ITEM(Button, exit, SetLabel(t_("Close")).RightPosZ(4, 64).BottomPosZ(8, 24))
END_LAYOUT
LAYOUT(SvnOptionsLayout, 140, 16)
ITEM(Option, commit, SetLabel(t_("Commit")).LeftPosZ(0, 68).VCenterPosZ(16, 0))
ITEM(Option, update, SetLabel(t_("Update")).LeftPosZ(72, 68).VCenterPosZ(16, 0))
END_LAYOUT
LAYOUT(GitOptionsLayout, 164, 16)
ITEM(Option, commit, SetLabel(t_("Commit")).LeftPosZ(0, 68).VCenterPosZ(16, 0))
ITEM(Option, push, SetLabel(t_("Push")).LeftPosZ(68, 48).VCenterPosZ(16, 0))
ITEM(Option, pull, SetLabel(t_("Pull")).LeftPosZ(116, 48).VCenterPosZ(16, 0))
END_LAYOUT

19
uppsrc/urepo/urepo.upp Normal file
View file

@ -0,0 +1,19 @@
description "Simple svn GUI frontend, also a module that can be used in other applications\377";
uses
TextDiffCtrl;
file
urepo.h options(BUILDER_OPTION) PCH,
Console.cpp,
RepoSync.cpp,
Diff.cpp,
main.cpp,
urepo.iml,
urepo.lay,
Info readonly separator,
Copying;
mainconfig
"" = "GUI";

9
uppsrc/urepo/usvn.iml Normal file
View file

@ -0,0 +1,9 @@
PREMULTIPLIED
IMAGE_ID(RepoDiff)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,99,16,96,16,96,24,68,224,63,62,44,16,33,128,23,131,212,60,120,240,0,43,134,233,103,192,1,105,161,31)
IMAGE_DATA(153,143,162,159,129,176,126,108,102,161,216,207,128,91,63,161,112,68,193,52,176,159,26,254,71,55,7,111,248,51,224,214)
IMAGE_DATA(15,18,59,112,224,0,110,253,64,113,16,192,229,126,144,94,156,250,161,122,145,245,83,152,126,7,20,0,0,49,101,131)
IMAGE_DATA(129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(128, 1)

22
uppsrc/urepo/usvn.lay Normal file
View file

@ -0,0 +1,22 @@
LAYOUT(RepoSyncLayout, 680, 400)
ITEM(ArrayCtrl, list, AutoHideSb(true).HSizePosZ(4, 4).VSizePosZ(4, 36))
ITEM(Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(4, 64).BottomPosZ(4, 24))
ITEM(Button, ok, SetLabel(t_("Synchronize!")).RightPosZ(4, 84).BottomPosZ(4, 24))
END_LAYOUT
LAYOUT(ConsoleLayout, 680, 660)
ITEM(ArrayCtrl, list, HSizePosZ(4, 4).VSizePosZ(4, 40))
ITEM(Button, exit, SetLabel(t_("Close")).RightPosZ(4, 64).BottomPosZ(8, 24))
END_LAYOUT
LAYOUT(SvnOptionsLayout, 140, 16)
ITEM(Option, commit, SetLabel(t_("Commit")).LeftPosZ(0, 68).VCenterPosZ(16, 0))
ITEM(Option, update, SetLabel(t_("Update")).LeftPosZ(72, 68).VCenterPosZ(16, 0))
END_LAYOUT
LAYOUT(GitOptionsLayout, 164, 16)
ITEM(Option, commit, SetLabel(t_("Commit")).LeftPosZ(0, 68).VCenterPosZ(16, 0))
ITEM(Option, push, SetLabel(t_("Push")).LeftPosZ(68, 48).VCenterPosZ(16, 0))
ITEM(Option, pull, SetLabel(t_("Pull")).LeftPosZ(116, 48).VCenterPosZ(16, 0))
END_LAYOUT