mirror of
https://gitlab.gnome.org/GNOME/gitg
synced 2024-08-27 11:59:17 +00:00
232 lines
4.2 KiB
Vala
232 lines
4.2 KiB
Vala
/*
|
|
* This file is part of gitg
|
|
*
|
|
* Copyright (C) 2013 - 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 class Hook : Object
|
|
{
|
|
public Gee.HashMap<string, string> environment { get; set; }
|
|
public string name { get; set; }
|
|
private string[] d_arguments;
|
|
public File? working_directory { get; set; }
|
|
|
|
private string[] d_output;
|
|
|
|
public string[] output
|
|
{
|
|
owned get { return d_output; }
|
|
}
|
|
|
|
construct
|
|
{
|
|
environment = new Gee.HashMap<string, string>();
|
|
}
|
|
|
|
public Hook(string name)
|
|
{
|
|
Object(name: name);
|
|
}
|
|
|
|
public void add_argument(string arg)
|
|
{
|
|
d_arguments += arg;
|
|
}
|
|
|
|
private string[]? flat_environment()
|
|
{
|
|
if (environment.size == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var env = Environment.list_variables();
|
|
|
|
var ret = new string[env.length + environment.size];
|
|
ret.length = 0;
|
|
|
|
foreach (var e in env)
|
|
{
|
|
if (!environment.has_key(e))
|
|
{
|
|
ret += "%s=%s".printf(e, Environment.get_variable(e));
|
|
}
|
|
}
|
|
|
|
foreach (var e in environment.keys)
|
|
{
|
|
ret += "%s=%s".printf(e, environment[e]);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private void stream_read_async(DataInputStream stream)
|
|
{
|
|
stream.read_line_async.begin(Priority.HIGH_IDLE, null, (obj, res) => {
|
|
try
|
|
{
|
|
var s = stream.read_line_async.end(res);
|
|
|
|
if (s != null)
|
|
{
|
|
if (s.validate())
|
|
{
|
|
d_output += s;
|
|
}
|
|
|
|
// Continue reading
|
|
stream_read_async(stream);
|
|
}
|
|
}
|
|
catch {}
|
|
});
|
|
}
|
|
|
|
private void read_from_fd(int fd)
|
|
{
|
|
var stream = new UnixInputStream(fd, true);
|
|
var dstream = new DataInputStream(stream);
|
|
|
|
stream_read_async(dstream);
|
|
}
|
|
|
|
private File hook_file(Ggit.Repository repository)
|
|
{
|
|
var hooksdir = repository.get_location().get_child("hooks");
|
|
var script = hooksdir.resolve_relative_path(name);
|
|
|
|
return script;
|
|
}
|
|
|
|
public bool exists_in(Ggit.Repository repository)
|
|
{
|
|
var script = hook_file(repository);
|
|
|
|
try
|
|
{
|
|
var info = script.query_info(FileAttribute.ACCESS_CAN_EXECUTE,
|
|
FileQueryInfoFlags.NONE);
|
|
|
|
return info.get_attribute_boolean(FileAttribute.ACCESS_CAN_EXECUTE);
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int run_sync(Ggit.Repository repository) throws SpawnError
|
|
{
|
|
var m = new MainLoop();
|
|
SpawnError? e = null;
|
|
int status = 0;
|
|
|
|
run.begin(repository, (obj, res) => {
|
|
try
|
|
{
|
|
status = run.end(res);
|
|
}
|
|
catch (SpawnError err)
|
|
{
|
|
e = err;
|
|
}
|
|
|
|
m.quit();
|
|
});
|
|
|
|
m.run();
|
|
|
|
if (e != null)
|
|
{
|
|
throw e;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
public async int run(Ggit.Repository repository) throws SpawnError
|
|
{
|
|
SourceFunc callback = run.callback;
|
|
|
|
d_output = new string[256];
|
|
d_output.length = 0;
|
|
|
|
File wd;
|
|
|
|
if (working_directory == null)
|
|
{
|
|
wd = working_directory;
|
|
}
|
|
else
|
|
{
|
|
wd = repository.get_workdir();
|
|
}
|
|
|
|
var script = hook_file(repository);
|
|
var args = new string[d_arguments.length + 1];
|
|
|
|
args.length = 0;
|
|
|
|
args += script.get_path();
|
|
|
|
foreach (var a in d_arguments)
|
|
{
|
|
args += a;
|
|
}
|
|
|
|
var env = flat_environment();
|
|
|
|
Pid pid;
|
|
|
|
int pstdout;
|
|
int pstderr;
|
|
|
|
Process.spawn_async_with_pipes(wd.get_path(),
|
|
args,
|
|
env,
|
|
SpawnFlags.DO_NOT_REAP_CHILD,
|
|
null,
|
|
out pid,
|
|
null,
|
|
out pstdout,
|
|
out pstderr);
|
|
|
|
read_from_fd(pstdout);
|
|
read_from_fd(pstderr);
|
|
|
|
int status = 0;
|
|
|
|
ChildWatch.add(pid, (p, st) => {
|
|
status = st;
|
|
|
|
Process.close_pid(p);
|
|
callback();
|
|
}, Priority.LOW);
|
|
|
|
yield;
|
|
|
|
return status;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ex: ts=4 noet
|