mirror of
https://gitlab.gnome.org/GNOME/gitg
synced 2024-06-30 23:29:33 +00:00
Add remote management
This commit is contained in:
parent
0bdd143e50
commit
1a8960b3fc
|
@ -69,6 +69,7 @@ gitg_gitg_VALASOURCES = \
|
|||
gitg/gitg-commit-action-create-tag.vala \
|
||||
gitg/gitg-create-tag-dialog.vala \
|
||||
gitg/gitg-commit-action-create-patch.vala \
|
||||
gitg/gitg-remote-manager.vala \
|
||||
gitg/preferences/gitg-preferences-commit.vala \
|
||||
gitg/preferences/gitg-preferences-dialog.vala \
|
||||
gitg/preferences/gitg-preferences-interface.vala \
|
||||
|
|
214
gitg/gitg-remote-manager.vala
Normal file
214
gitg/gitg-remote-manager.vala
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2012 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Gitg
|
||||
{
|
||||
|
||||
class RemoteManager : Object, GitgExt.RemoteLookup
|
||||
{
|
||||
class CredSshInteractive : Ggit.CredSshInteractive
|
||||
{
|
||||
public CredSshInteractive(string username) throws Error
|
||||
{
|
||||
Object(username: username);
|
||||
|
||||
((Initable)this).init(null);
|
||||
}
|
||||
|
||||
protected override void prompt(Ggit.CredSshInteractivePrompt[] prompts)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
class Callbacks : Ggit.RemoteCallbacks
|
||||
{
|
||||
private weak Remote d_remote;
|
||||
private Window d_window;
|
||||
|
||||
public Callbacks(Remote remote, Window window)
|
||||
{
|
||||
d_remote = remote;
|
||||
d_window = window;
|
||||
}
|
||||
|
||||
protected override bool credentials(string url,
|
||||
string username,
|
||||
Ggit.Credtype allowed_types,
|
||||
out Ggit.Cred cred) throws Error
|
||||
{
|
||||
cred = null;
|
||||
|
||||
if ((allowed_types & Ggit.Credtype.SSH_KEY) != 0)
|
||||
{
|
||||
cred = new Ggit.CredSshKeyFromAgent(username);
|
||||
}
|
||||
else if ((allowed_types & Ggit.Credtype.SSH_INTERACTIVE) != 0)
|
||||
{
|
||||
cred = new CredSshInteractive(username);
|
||||
}
|
||||
else if ((allowed_types & Ggit.Credtype.USERPASS_PLAINTEXT) != 0)
|
||||
{
|
||||
// TODO: query for user + pass
|
||||
}
|
||||
|
||||
return cred != null;
|
||||
}
|
||||
}
|
||||
|
||||
struct InsteadOf
|
||||
{
|
||||
string prefix;
|
||||
string replacement;
|
||||
}
|
||||
|
||||
private Gee.HashMap<string, Gitg.Remote> d_remotes;
|
||||
private InsteadOf[] d_insteadof;
|
||||
private Window d_window;
|
||||
|
||||
public RemoteManager(Window window)
|
||||
{
|
||||
d_window = window;
|
||||
d_remotes = new Gee.HashMap<string, Gitg.Remote>();
|
||||
|
||||
extract_insteadof();
|
||||
}
|
||||
|
||||
private void extract_insteadof()
|
||||
{
|
||||
d_insteadof = new InsteadOf[10];
|
||||
d_insteadof.length = 0;
|
||||
|
||||
Ggit.Config config;
|
||||
|
||||
try
|
||||
{
|
||||
config = d_window.repository.get_config();
|
||||
} catch { return; }
|
||||
|
||||
Regex r;
|
||||
|
||||
try
|
||||
{
|
||||
r = new Regex("url\\.(.*)\\.insteadof");
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
stderr.printf("Failed to compile regex: %s\n", e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
config.match_foreach(r, (info, value) => {
|
||||
d_insteadof += InsteadOf() {
|
||||
prefix = value,
|
||||
replacement = info.fetch(1)
|
||||
};
|
||||
|
||||
return 0;
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
|
||||
public Gitg.Remote? lookup(string name)
|
||||
{
|
||||
if (d_window.repository == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (d_remotes == null)
|
||||
{
|
||||
d_remotes = new Gee.HashMap<string, Gitg.Remote>();
|
||||
}
|
||||
|
||||
if (d_remotes.has_key(name))
|
||||
{
|
||||
return d_remotes[name];
|
||||
}
|
||||
|
||||
Gitg.Remote remote;
|
||||
|
||||
try
|
||||
{
|
||||
remote = d_window.repository.get_remote(name) as Gitg.Remote;
|
||||
} catch { return null; }
|
||||
|
||||
var url = remote.get_url();
|
||||
|
||||
foreach (var io in d_insteadof)
|
||||
{
|
||||
if (url.has_prefix(io.prefix))
|
||||
{
|
||||
url = io.replacement + url.substring(io.prefix.length);
|
||||
|
||||
string[] fetch_specs;
|
||||
string[] push_specs;
|
||||
|
||||
try
|
||||
{
|
||||
fetch_specs = remote.get_fetch_specs();
|
||||
} catch { break; }
|
||||
|
||||
try
|
||||
{
|
||||
push_specs = remote.get_push_specs();
|
||||
} catch { break; }
|
||||
|
||||
var defspec = "+refs/heads/*:refs/remotes/" + name + "/*";
|
||||
Gitg.Remote? tmp = null;
|
||||
|
||||
try
|
||||
{
|
||||
tmp = (new Ggit.Remote.anonymous(d_window.repository, url, defspec)) as Gitg.Remote;
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
stderr.printf("Failed to create remote: %s\n", e.message);
|
||||
}
|
||||
|
||||
if (tmp == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
tmp.set_fetch_specs(fetch_specs);
|
||||
} catch { break; }
|
||||
|
||||
try
|
||||
{
|
||||
tmp.set_push_specs(push_specs);
|
||||
} catch { break; }
|
||||
|
||||
remote = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
remote.set_callbacks(new Callbacks(remote, d_window));
|
||||
|
||||
d_remotes[name] = remote;
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,8 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
|
|||
|
||||
private UIElements<GitgExt.Activity> d_activities;
|
||||
|
||||
private RemoteManager d_remote_manager;
|
||||
|
||||
// Widgets
|
||||
[GtkChild]
|
||||
private Gtk.HeaderBar d_header_bar;
|
||||
|
@ -333,6 +335,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
|
|||
set
|
||||
{
|
||||
d_repository = value;
|
||||
d_remote_manager = new RemoteManager(this);
|
||||
|
||||
notify_property("repository");
|
||||
repository_changed();
|
||||
|
@ -487,6 +490,8 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
|
|||
d_repository = new Gitg.Repository(this.repository.get_location(),
|
||||
null);
|
||||
|
||||
d_remote_manager = new RemoteManager(this);
|
||||
|
||||
notify_property("repository");
|
||||
update_title();
|
||||
}
|
||||
|
@ -698,6 +703,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
|
|||
{
|
||||
ret.application = app;
|
||||
ret.d_repository = repository;
|
||||
ret.d_remote_manager = new RemoteManager(ret);
|
||||
ret.d_action = action;
|
||||
}
|
||||
|
||||
|
@ -935,6 +941,11 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
|
|||
selectable_mode = GitgExt.SelectionMode.NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
public GitgExt.RemoteLookup remote_lookup
|
||||
{
|
||||
owned get { return d_remote_manager; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ libgitg_ext_libgitg_ext_1_0_la_VALASOURCES = \
|
|||
libgitg-ext/gitg-ext-history-panel.vala \
|
||||
libgitg-ext/gitg-ext-command-line.vala \
|
||||
libgitg-ext/gitg-ext-preferences.vala \
|
||||
libgitg-ext/gitg-ext-remote-lookup.vala \
|
||||
libgitg-ext/gitg-ext-searchable.vala \
|
||||
libgitg-ext/gitg-ext-selectable.vala \
|
||||
libgitg-ext/gitg-ext-ui.vala \
|
||||
|
|
|
@ -66,6 +66,8 @@ public interface Application : Object
|
|||
public abstract Gee.Map<string, string> environment { owned get; }
|
||||
|
||||
public abstract Application open_new(Ggit.Repository repository, string? hint = null);
|
||||
|
||||
public abstract RemoteLookup remote_lookup { owned get; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
30
libgitg-ext/gitg-ext-remote-lookup.vala
Normal file
30
libgitg-ext/gitg-ext-remote-lookup.vala
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2014 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace GitgExt
|
||||
{
|
||||
|
||||
public interface RemoteLookup : Object
|
||||
{
|
||||
public abstract Gitg.Remote? lookup(string name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ex:set ts=4 noet:
|
|
@ -72,7 +72,8 @@ libgitg_libgitg_1_0_la_VALASOURCES = \
|
|||
libgitg/gitg-hook.vala \
|
||||
libgitg/gitg-date.vala \
|
||||
libgitg/gitg-avatar-cache.vala \
|
||||
libgitg/gitg-diff-stat.vala
|
||||
libgitg/gitg-diff-stat.vala \
|
||||
libgitg/gitg-remote.vala
|
||||
|
||||
libgitg_libgitg_1_0_la_SOURCES = \
|
||||
$(libgitg_libgitg_1_0_la_VALASOURCES) \
|
||||
|
|
|
@ -65,6 +65,9 @@ public void init() throws Error
|
|||
|
||||
factory.register(typeof(Ggit.Commit),
|
||||
typeof(Gitg.Commit));
|
||||
|
||||
factory.register(typeof(Ggit.Remote),
|
||||
typeof(Gitg.Remote));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
183
libgitg/gitg-remote.vala
Normal file
183
libgitg/gitg-remote.vala
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2014 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Gitg
|
||||
{
|
||||
|
||||
public enum RemoteState
|
||||
{
|
||||
DISCONNECTED,
|
||||
CONNECTING,
|
||||
CONNECTED,
|
||||
TRANSFERRING
|
||||
}
|
||||
|
||||
public errordomain RemoteError
|
||||
{
|
||||
ALREADY_CONNECTED,
|
||||
ALREADY_CONNECTING,
|
||||
ALREADY_DISCONNECTED,
|
||||
STILL_CONNECTING
|
||||
}
|
||||
|
||||
public class Remote : Ggit.Remote
|
||||
{
|
||||
private RemoteState d_state;
|
||||
|
||||
public RemoteState state
|
||||
{
|
||||
get { return d_state; }
|
||||
private set
|
||||
{
|
||||
if (d_state != value)
|
||||
{
|
||||
d_state = value;
|
||||
notify_property("state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void update_state(bool force_disconnect = false)
|
||||
{
|
||||
if (get_connected())
|
||||
{
|
||||
if (force_disconnect)
|
||||
{
|
||||
disconnect.begin((obj, res) => {
|
||||
try
|
||||
{
|
||||
disconnect.end(res);
|
||||
} catch {}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
state = RemoteState.CONNECTED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state = RemoteState.DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
public new async void connect(Ggit.Direction direction) throws Error
|
||||
{
|
||||
if (get_connected())
|
||||
{
|
||||
if (state != RemoteState.CONNECTED)
|
||||
{
|
||||
state = RemoteState.CONNECTED;
|
||||
}
|
||||
|
||||
throw new RemoteError.ALREADY_CONNECTED("already connected");
|
||||
}
|
||||
else if (state == RemoteState.CONNECTING)
|
||||
{
|
||||
throw new RemoteError.ALREADY_CONNECTING("already connecting");
|
||||
}
|
||||
|
||||
state = RemoteState.CONNECTING;
|
||||
|
||||
try
|
||||
{
|
||||
yield Async.thread(() => {
|
||||
base.connect(direction);
|
||||
});
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
update_state();
|
||||
throw e;
|
||||
}
|
||||
|
||||
update_state();
|
||||
}
|
||||
|
||||
public new async void disconnect() throws Error
|
||||
{
|
||||
if (!get_connected())
|
||||
{
|
||||
if (state != RemoteState.DISCONNECTED)
|
||||
{
|
||||
state = RemoteState.DISCONNECTED;
|
||||
}
|
||||
|
||||
throw new RemoteError.ALREADY_DISCONNECTED("already disconnected");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
yield Async.thread(() => {
|
||||
base.disconnect();
|
||||
});
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
update_state();
|
||||
throw e;
|
||||
}
|
||||
|
||||
update_state();
|
||||
}
|
||||
|
||||
private async void download_intern(Ggit.Signature? signature, string? message) throws Error
|
||||
{
|
||||
bool dis = false;
|
||||
|
||||
if (!get_connected())
|
||||
{
|
||||
dis = true;
|
||||
yield connect(Ggit.Direction.FETCH);
|
||||
}
|
||||
|
||||
state = RemoteState.TRANSFERRING;
|
||||
|
||||
try
|
||||
{
|
||||
yield Async.thread(() => {
|
||||
base.download();
|
||||
|
||||
if (signature != null)
|
||||
{
|
||||
base.update_tips(signature, message);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
update_state(dis);
|
||||
throw e;
|
||||
}
|
||||
|
||||
update_state(dis);
|
||||
}
|
||||
|
||||
public new async void download() throws Error
|
||||
{
|
||||
yield download_intern(null, null);
|
||||
}
|
||||
|
||||
public new async void fetch(Ggit.Signature signature, string? message) throws Error
|
||||
{
|
||||
yield download_intern(signature, message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user