[gnome-code-assistance/wip/vala: 17/20] [backends/vala] Fix makefile integration for vala
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-code-assistance/wip/vala: 17/20] [backends/vala] Fix makefile integration for vala
- Date: Wed, 4 Dec 2013 16:13:28 +0000 (UTC)
commit 7b0eb9df35c373a40e24976a201f4fb6a5cfa2e3
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Mon Nov 18 09:57:57 2013 +0100
[backends/vala] Fix makefile integration for vala
backends/vala/makefileintegration.vala | 716 ++++++++++++++++----------------
1 files changed, 359 insertions(+), 357 deletions(-)
---
diff --git a/backends/vala/makefileintegration.vala b/backends/vala/makefileintegration.vala
index 6e4ab3e..d69e67e 100644
--- a/backends/vala/makefileintegration.vala
+++ b/backends/vala/makefileintegration.vala
@@ -17,62 +17,37 @@
* along with gedit-code-assistant. If not, see <http://www.gnu.org/licenses/>.
*/
-namespace Gca.Backends.Vala
+class MakefileIntegration
{
-
-public errordomain MakefileIntegrationError
-{
- MISSING_MAKEFILE,
- MISSING_TARGET,
- MISSING_MAKE_OUTPUT
-}
-
-class MakefileIntegration : Object
-{
- private class Cache
+ static uint file_hash(File f)
{
- private File d_source;
- private File? d_makefile;
- private string[] d_args;
-
- public Cache(File source, File? makefile, string[] args)
- {
- d_source = source;
- d_makefile = makefile;
- d_args = args;
- }
-
- public File makefile
- {
- get { return d_makefile; }
- }
+ return f.hash();
+ }
- public File source
- {
- get { return d_source; }
- }
+ static bool file_equal(File f1, File f2)
+ {
+ return f1.equal(f2);
+ }
- public string[] args
+ class Makefile
+ {
+ class Source
{
- get { return d_args; }
- set { d_args = value; }
+ public TimeVal mtime;
+ public string[] flags;
}
- }
- private class Makefile
- {
private File d_file;
- private Gee.ArrayList<File> d_sources;
- private FileMonitor ?d_monitor;
- private uint d_timeoutid;
-
- public signal void changed();
+ private Gee.HashMap<File, Source> d_sources;
+ private TimeVal d_mtime;
+ private FileMonitor? d_monitor;
public Makefile(File file)
{
d_file = file;
- d_timeoutid = 0;
- d_monitor = null;
+ d_sources = new Gee.HashMap<File, Source>(file_hash, file_equal);
+
+ update_mtime();
try
{
@@ -83,471 +58,498 @@ class MakefileIntegration : Object
return;
}
- d_sources = new Gee.ArrayList<File>();
+ d_monitor.changed.connect(on_changed);
+ }
- d_monitor.changed.connect(on_makefile_changed);
+ public File file
+ {
+ get { return d_file; }
}
- public bool valid
+ private TimeVal file_mtime(File f)
{
- get
+ try
{
- return d_monitor != null;
+ var info = f.query_info(FileAttribute.TIME_MODIFIED, FileQueryInfoFlags.NONE);
+ return info.get_modification_time();
}
+ catch {}
+
+ return TimeVal() {
+ tv_sec = 0,
+ tv_usec = 0
+ };
}
- public void add(File source)
+ private void update_mtime()
{
- d_sources.add(source);
+ d_mtime = file_mtime(d_file);
}
- public bool remove(File source)
+ private void on_changed()
{
- d_sources.remove(source);
+ update_mtime();
+ }
+
+ private Source make_source(string[] flags)
+ {
+ var ret = new Source();
+
+ ret.flags = flags;
+ ret.mtime = d_mtime;
- return (d_sources.size == 0);
+ return ret;
}
- public Gee.ArrayList<File> sources
+ public void dispose()
{
- get { return d_sources; }
+ if (d_monitor != null)
+ {
+ d_monitor.cancel();
+ d_monitor = null;
+ }
}
- public File file
+ public void add(File source, string[] flags)
{
- get { return d_file; }
+ d_sources[file] = make_source(flags);
}
- private void on_makefile_changed(File file, File ?other, FileMonitorEvent event_type)
+ public bool remove(File source)
{
- if (event_type == FileMonitorEvent.CHANGED ||
- event_type == FileMonitorEvent.CREATED)
+ if (d_sources.unset(source) && d_sources.size == 0)
{
- if (d_timeoutid != 0)
- {
- Source.remove(d_timeoutid);
- }
+ dispose();
+ return true;
+ }
- d_timeoutid = Timeout.add(100, on_makefile_timeout);
+ return false;
+ }
+
+ private bool newer(TimeVal t1, TimeVal t2)
+ {
+ if (t1.tv_sec == t2.tv_sec)
+ {
+ return t1.tv_usec > t2.tv_usec;
+ }
+ else
+ {
+ return t1.tv_sec > t2.tv_sec;
}
}
- private bool on_makefile_timeout()
+ public bool up_to_date_for(File source)
{
- d_timeoutid = 0;
+ var s = d_sources[source];
+
+ if (s != null)
+ {
+ return !newer(d_mtime, s.mtime);
+ }
+ else
+ {
+ return false;
+ }
+ }
- changed();
+ public string[]? flags_for_file(File source)
+ {
+ var s = d_sources[source];
- return false;
+ if (s != null)
+ {
+ return s.flags;
+ }
+ else
+ {
+ return null;
+ }
}
-
}
- private Gee.HashMap<File, Cache> d_argsCache;
- private Gee.HashMap<File, Makefile> d_makefileCache;
-
- public signal void arguments_changed(File file);
+ private Gee.HashMap<File, Makefile> d_cache;
+ private Gee.HashMap<File, Makefile> d_file_to_makefile;
- construct
+ public MakefileIntegration()
{
- d_argsCache = new Gee.HashMap<File, Cache>();
- d_makefileCache = new Gee.HashMap<File, Makefile>();
+ d_cache = new Gee.HashMap<File, Makefile>(file_hash, file_equal);
+ d_file_to_makefile = new Gee.HashMap<File, Makefile>(file_hash, file_equal);
}
- private File ?makefile_for(File file,
- Cancellable ?cancellable = null) throws IOError,
- Error
+ public bool changed_for_file(File f)
{
- File ?ret = null;
+ var makefile = makefile_for(f);
- File? par = file.get_parent();
+ if (makefile == null)
+ {
+ return false;
+ }
- while (par != null && ret == null)
+ var m = d_cache[makefile];
+
+ if (m != null)
{
- File makefile = par.get_child("Makefile");
+ return m.up_to_date_for(f);
+ }
+
+ return true;
+ }
- if (makefile.query_exists(cancellable))
+ public void dispose(File f)
+ {
+ var m = d_file_to_makefile[f];
+
+ if (m != null)
+ {
+ if (m.remove(f))
{
- ret = makefile;
+ d_cache.unset(m.file);
}
- par = par.get_parent();
+ d_file_to_makefile.unset(f);
+ }
+ }
+
+ public string[]? flags_for_file(File f)
+ {
+ var makefile = makefile_for(f);
+
+ if (makefile == null)
+ {
+ return null;
}
- if (ret != null)
+ var m = d_cache[makefile];
+
+ if (m != null)
{
- log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
- "Resolved makefile for `%s': `%s'",
- file.get_path(),
- ret.get_path());
+ if (m.up_to_date_for(f))
+ {
+ return m.flags_for_file(f);
+ }
}
- return ret;
+ var targets = targets_from_make(makefile, f);
+ var flags = flags_from_targets(makefile, f, targets);
+
+ return update_cache(makefile, f, flags);
}
- private string[] targets_from_make(File makefile,
- File source) throws SpawnError,
- RegexError,
- MakefileIntegrationError
+ private string[]? update_cache(File makefile, File f, string[] flags)
{
- File wd = makefile.get_parent();
- string basen = wd.get_relative_path(source);
+ var m = d_cache[makefile];
- string[] args = new string[] {
- "make",
- "-p",
- "-n",
- null
- };
+ if (m == null)
+ {
+ m = new Makefile(makefile);
+ d_cache[makefile] = m;
+ }
- string outstr;
+ m.add(f, flags);
+ d_file_to_makefile[f] = m;
- /* Spawn make to find out which target has the source as a
- dependency */
- Process.spawn_sync(wd.get_path(),
- args,
- null,
- SpawnFlags.SEARCH_PATH |
- SpawnFlags.STDERR_TO_DEV_NULL,
- null,
- out outstr);
+ return flags;
+ }
- /* Scan the output to find the target */
- string reg = "^([^:\n]*?(\\.stamp:|:)).*%s".printf(Regex.escape_string(basen));
+ private File? find_subdir_with_path(File parent, string relpath)
+ {
+ // All dirs in parent, recursively
+ var dirs = new File[]{parent};
- Regex regex = new Regex(reg, RegexCompileFlags.MULTILINE);
- MatchInfo info;
+ while (dirs.length != 0)
+ {
+ var d = dirs[0];
+ dirs = dirs[1:dirs.length];
- var ret = new string[1];
+ FileEnumerator iter;
- if (regex.match(outstr, 0, out info))
- {
- while (true)
+ try
{
- var target = info.fetch(1);
- target = target.substring(0, target.length - 1);
+ var attrs = FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE;
+ iter = d.enumerate_children(attrs, FileQueryInfoFlags.NONE);
+ } catch {
+ continue;
+ }
- if (target.has_suffix(".stamp"))
- {
- ret[0] = target;
- }
- else
- {
- ret += target;
- }
+ FileInfo? info;
- if (!info.next())
+ try
+ {
+ while ((info = iter.next_file()) != null)
{
- break;
- }
- }
- }
+ if (info.get_file_type() == FileType.DIRECTORY)
+ {
+ File dir = iter.get_child(info);
+ File child = dir.get_child(relpath);
- if (ret[0] == null)
- {
- ret = ret[1:ret.length];
- }
+ if (child.query_exists())
+ {
+ var mf = makefile_for(child, false);
- if (ret.length != 0)
- {
- return ret;
+ if (mf != null)
+ {
+ return mf;
+ }
+ }
+
+ dirs += dir;
+ }
+ }
+ } catch { continue; }
}
- throw new MakefileIntegrationError.MISSING_TARGET(
- "Could not find make target for %s".printf(basen));
+ return null;
}
- private string[] ?flags_from_targets(File makefile,
- File source,
- string[] targets) throws SpawnError,
- MakefileIntegrationError,
- ShellError
+ private File? subdir_makefile_for(File parent, File f)
{
- /* Fake make to build the target and extract the flags */
- var wd = makefile.get_parent();
- string relsource = wd.get_relative_path(source);
-
- string fakecc = "__GCA_VALA_COMPILE_ARGS__";
+ var relpath = Path.get_dirname(parent.get_relative_path(f));
+ return find_subdir_with_path(parent, relpath);
+ }
- string?[] args = new string?[] {
- "make",
- "-s",
- "-i",
- "-n",
- "-W",
- relsource,
- "V=1",
- "VALAC=" + fakecc
- };
+ private File ?makefile_for(File f, bool tryac = true)
+ {
+ var fromcache = d_file_to_makefile[f];
- foreach (var target in targets)
+ if (fromcache != null)
{
- args += target;
+ return fromcache.file;
}
- args += null;
+ var parent = f.get_parent();
+ var tocheck = new string[] {"configure.ac", "configure.in", "configure"};
- log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
- "Running: %s",
- string.joinv(" ", args));
-
- string outstr;
+ while (parent != null)
+ {
+ var makefile = parent.get_child("Makefile");
- Process.spawn_sync(makefile.get_parent().get_path(),
- args,
- null,
- SpawnFlags.SEARCH_PATH |
- SpawnFlags.STDERR_TO_DEV_NULL,
- null,
- out outstr);
+ if (makefile.query_exists())
+ {
+ return makefile;
+ }
- /* Extract args */
- int idx = outstr.last_index_of(fakecc);
+ foreach (var c in tocheck)
+ {
+ var cc = parent.get_child(c);
- if (idx < 0)
- {
- throw new MakefileIntegrationError.MISSING_MAKE_OUTPUT("Make output did not contain
flags");
- }
+ if (cc.query_exists())
+ {
+ var ret = subdir_makefile_for(parent, f);
- string[] retargs;
- string[] parts = outstr.substring(idx).split("\n");
+ if (ret != null)
+ {
+ return ret;
+ }
- Shell.parse_argv(parts[0], out retargs);
+ break;
+ }
+ }
- log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
- "Parsed command: %s => '%s'\n",
- parts[0],
- string.joinv("', '", retargs));
+ parent = parent.get_parent();
+ }
- return retargs;
+ return null;
}
- private async void makefile_changed_async(Makefile makefile)
+ private string[] targets_from_make(File makefile, File source)
{
- ThreadFunc<void *> func = () => {
- foreach (File file in makefile.sources)
- {
- find_for_makefile(makefile.file, file);
- }
+ File wd = makefile.get_parent();
+ var relpath = wd.get_relative_path(source);
- return null;
+ var lookfor = new string[] {
+ wd.get_relative_path(source)
};
- try
- {
- new Thread<void *>.try("find makefile", func);
- yield;
- }
- catch
+ var bname = source.get_basename();
+
+ if (bname != relpath)
{
+ lookfor += bname;
}
- }
- private void on_makefile_changed(Makefile makefile)
- {
- makefile_changed_async.begin(makefile);
- }
+ string[] args = new string[] {
+ "make",
+ "-p",
+ "-n",
+ "-s",
+ null
+ };
- private void find_for_makefile(File makefile, File file)
- {
- string[] targets;
- string[] args = {};
+ string outstr;
+ /* Spawn make to find out which target has the source as a
+ dependency */
try
{
- targets = targets_from_make(makefile, file);
-
- log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
- "Makefile make targets for `%s': `%s'",
- file.get_path(),
- string.joinv(", ", targets));
-
- args = flags_from_targets(makefile, file, targets);
-
- log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
- "Compile flags for `%s': `%s`",
- file.get_path(),
- string.joinv("`, `", args));
+ Process.spawn_sync(wd.get_path(),
+ args,
+ null,
+ SpawnFlags.SEARCH_PATH |
+ SpawnFlags.STDERR_TO_DEV_NULL,
+ null,
+ out outstr);
}
- catch (Error e)
+ catch (SpawnError e)
{
- stderr.printf("Makefile error: %s\n", e.message);
+ return new string[0];
}
- lock(d_makefileCache)
+ var targets = new string[0];
+ var found = new Gee.HashSet<string>();
+
+ while (lookfor.length > 0)
{
- lock(d_argsCache)
+ for (var i = 0; i < lookfor.length; i++)
+ {
+ lookfor[i] = Regex.escape_string(lookfor[i]);
+ }
+
+ var relookfor = string.joinv("|", lookfor);
+ lookfor = new string[0];
+
+ Regex reg;
+
+ try
+ {
+ reg = new Regex("^([^:\n ]+):.*\\b(%s)\\b".printf(relookfor),
RegexCompileFlags.MULTILINE);
+ } catch (Error e) { stderr.printf("regex: %s\n", e.message); continue; }
+
+ MatchInfo info;
+
+ reg.match(outstr, 0, out info);
+
+ while (info.matches())
{
- if (d_argsCache.has_key(file))
+ var target = info.fetch(1);
+
+ try
{
- d_argsCache[file].args = args;
- }
- else
+ info.next();
+ } catch {};
+
+ if (target[0] == '#' || target[0] == '.' || target.has_suffix("-am"))
{
- Cache c = new Cache(file, makefile, args);
- d_argsCache[file] = c;
+ continue;
}
- if (!d_makefileCache.has_key(makefile))
+ if (found.contains(target))
{
- Makefile m = new Makefile(makefile);
- m.add(file);
-
- m.changed.connect(on_makefile_changed);
- d_makefileCache[makefile] = m;
+ continue;
}
+
+ targets += target;
+ found.add(target);
+ lookfor += target;
}
}
- changed_in_idle(file);
- }
+ var sorted = new Gee.ArrayList<string>.wrap(targets);
- private void changed_in_idle(File file)
- {
- Idle.add(() => {
- arguments_changed(file);
- return false;
+ sorted.sort((a, b) => {
+ var sa = a.has_suffix(".stamp");
+ var sb = b.has_suffix(".stamp");
+
+ if (sa == sb)
+ {
+ return 0;
+ }
+
+ return sa ? -1 : 1;
});
+
+ return sorted.to_array();
}
- private async void find_async(File file)
+ private string[] flags_from_targets(File makefile, File source, string[] targets)
{
- ThreadFunc<void *> func = () => {
- File ?makefile = null;
+ if (targets.length == 0)
+ {
+ return new string[0];
+ }
- try
- {
- makefile = makefile_for(file);
- }
- catch (Error e)
- {
- makefile = null;
- }
+ var fakevalac = "__GCA_VALA_COMPILE_ARGS__";
- if (makefile == null)
- {
- Cache c = new Cache(file, null, new string[] {});
- d_argsCache[file] = c;
+ var wd = makefile.get_parent();
+ var relsource = wd.get_relative_path(source);
- changed_in_idle(file);
- return null;
- }
+ var args = new string?[] {
+ "make",
+ "-s",
+ "-i",
+ "-n",
+ "-W",
+ relsource,
+ "V=1",
+ "VALAC=" + fakevalac
+ };
- find_for_makefile(makefile, file);
+ foreach (var target in targets)
+ {
+ args += target;
+ }
- lock(d_makefileCache)
- {
- if (d_makefileCache.has_key(file))
- {
- d_makefileCache[makefile].add(file);
- }
- }
+ args += null;
- return null;
- };
+ string outstr;
try
{
- new Thread<void *>.try("findasync", func);
- yield;
+ Process.spawn_sync(wd.get_path(),
+ args,
+ null,
+ SpawnFlags.SEARCH_PATH |
+ SpawnFlags.STDERR_TO_DEV_NULL,
+ null,
+ out outstr);
}
- catch
+ catch (SpawnError e)
{
+ return new string[0];
}
- }
- public new string[]? get(File file)
- {
- string[] ?ret = null;
+ /* Extract args */
+ int pos = outstr.index_of(fakevalac);
- lock(d_argsCache)
+ if (pos < 0)
{
- if (d_argsCache.has_key(file))
- {
- ret = d_argsCache[file].args;
- }
- else
- {
- monitor(file);
- }
+ return new string[0];
}
- return ret;
- }
+ int epos = outstr.index_of("\n", pos);
- public async string[] args_for_file(File file) throws MakefileIntegrationError {
- lock(d_argsCache)
+ if (epos < 0)
{
- if (d_argsCache.has_key(file))
- {
- return d_argsCache[file].;
-
- lock(d_makefileCache)
- {
- return
- }
- }
+ epos = outstr.length;
}
- }
-
- public void monitor(File file)
- {
- bool hascache;
- lock(d_argsCache)
- {
- hascache = d_argsCache.has_key(file);
- }
+ string[] retargs;
+ var sargs = outstr[pos+fakevalac.length:epos-pos];
- if (hascache)
+ try
{
- arguments_changed(file);
+ Shell.parse_argv(sargs, out retargs);
}
- else
+ catch (ShellError e)
{
- find_async.begin(file, (source, res) => find_async.end(res));
+ return new string[0];
}
- }
- public void remove_monitor(File file)
- {
- lock(d_argsCache)
- {
- if (d_argsCache.has_key(file))
- {
- Cache c = d_argsCache[file];
-
- lock (d_makefileCache)
- {
- if (d_makefileCache.has_key(c.makefile))
- {
- Makefile m = d_makefileCache[c.makefile];
-
- if (m.remove(file))
- {
- d_makefileCache.unset(c.makefile);
- }
- }
- }
+ log("GcaVala", LogLevelFlags.LEVEL_DEBUG,
+ "Parsed command: %s => '%s'\n",
+ sargs,
+ string.joinv("', '", retargs));
- d_argsCache.unset(file);
- }
- }
+ return retargs;
}
}
+#if MAIN
public static int main(string[] a){
- var ml = new MainLoop();
-
MakefileIntegration it = new MakefileIntegration();
- it.monitor(File.new_for_commandline_arg("dbus.vala"));
-
- ml.run();
-
+ stdout.printf("Flags: %s\n", string.joinv(", ",
it.flags_for_file(File.new_for_commandline_arg(a[1]))));
return 0;
}
-
-}
+#endif
/* vi:ex:ts=4 */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]