[gnome-ostree] subtask.js: Redo of task.js API
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-ostree] subtask.js: Redo of task.js API
- Date: Mon, 21 Jan 2013 22:57:39 +0000 (UTC)
commit 629a3c973127ffdbe124fc249186af755d0817ac
Author: Colin Walters <walters verbum org>
Date: Mon Jan 21 16:31:55 2013 -0500
subtask.js: Redo of task.js API
This is a bit cleaner.
Makefile-ostbuild.am | 2 +-
src/ostbuild/js/builtins/autobuilder.js | 86 +++++++++++++------------------
src/ostbuild/js/builtins/build.js | 44 +++++++++-------
src/ostbuild/js/jsonutil.js | 8 ++-
src/ostbuild/js/{task.js => subtask.js} | 70 ++++++++++++++++---------
5 files changed, 113 insertions(+), 97 deletions(-)
---
diff --git a/Makefile-ostbuild.am b/Makefile-ostbuild.am
index 6ccf5be..5d5c2bf 100644
--- a/Makefile-ostbuild.am
+++ b/Makefile-ostbuild.am
@@ -52,7 +52,7 @@ jsostbuild_DATA= \
src/ostbuild/js/procutil.js \
src/ostbuild/js/snapshot.js \
src/ostbuild/js/streamutil.js \
- src/ostbuild/js/task.js \
+ src/ostbuild/js/subtask.js \
src/ostbuild/js/vcs.js \
$(NULL)
diff --git a/src/ostbuild/js/builtins/autobuilder.js b/src/ostbuild/js/builtins/autobuilder.js
index f178c71..6ad6f33 100644
--- a/src/ostbuild/js/builtins/autobuilder.js
+++ b/src/ostbuild/js/builtins/autobuilder.js
@@ -22,7 +22,7 @@ const Format = imports.format;
const GSystem = imports.gi.GSystem;
-const Task = imports.task;
+const SubTask = imports.subtask;
const JsonDB = imports.jsondb;
const ProcUtil = imports.procutil;
const JsonUtil = imports.jsonutil;
@@ -45,15 +45,14 @@ const AutoBuilder = new Lang.Class({
Name: 'AutoBuilder',
_init: function() {
- this._resolve_proc = null;
- this._build_proc = null;
-
this.config = Config.get();
this.workdir = Gio.File.new_for_path(this.config.getGlobal('workdir'));
this.prefix = this.config.getPrefix();
this._snapshot_dir = this.workdir.get_child('snapshots');
this._status_path = this.workdir.get_child('autobuilder-' + this.prefix + '.json');
+ this._manifestPath = Gio.File.new_for_path('manifest.json');
+
this._build_needed = true;
this._full_resolve_needed = true;
this._queued_force_builds = [];
@@ -70,9 +69,9 @@ const AutoBuilder = new Lang.Class({
GSystem.file_ensure_directory(snapshotdir, true, null);
this._src_db = new JsonDB.JsonDB(snapshotdir, this.prefix + '-src-snapshot');
- let taskdir = new Task.TaskDir(this.workdir.get_child('tasks'));
- this._resolve_taskset = taskdir.get(this.prefix + '-resolve');
- this._build_taskset = taskdir.get(this.prefix + '-build');
+ let taskdir = this.workdir.get_child('tasks');
+ this._resolve_taskset = new SubTask.TaskSet(taskdir.get_child(this.prefix + '-resolve'));
+ this._build_taskset = new SubTask.TaskSet(taskdir.get_child(this.prefix + '-build'));
this._source_snapshot_path = this._src_db.getLatestPath();
@@ -89,12 +88,12 @@ const AutoBuilder = new Lang.Class({
_updateStatus: function() {
let newStatus = "";
- if (this._resolve_proc == null && this._build_proc == null) {
+ if (!this._resolve_taskset.isRunning() && !this._build_taskset.isRunning()) {
newStatus = "idle";
} else {
- if (this._resolve_proc != null)
+ if (this._resolve_taskset.isRunning())
newStatus += "[resolving] ";
- if (this._build_proc != null)
+ if (this._build_taskset.isRunning())
newStatus += "[building] ";
}
if (newStatus != this._status) {
@@ -121,22 +120,19 @@ const AutoBuilder = new Lang.Class({
queueResolve: function(components) {
this._queued_force_resolve.push.apply(this._queued_force_resolve, components);
print("queued resolves: " + this._queued_force_resolve);
- if (this._resolve_proc == null)
+ if (!this._resolve_taskset.isRunning())
this._fetch();
},
_fetchAll: function() {
this._full_resolve_needed = true;
- if (this._resolve_proc == null)
+ if (!this._resolve_taskset.isRunning())
this._fetch();
return true;
},
_fetch: function() {
let cancellable = null;
- if (this._resolve_proc != null) throw new Error("Attempted multiple fetch");
- let t = this._resolve_taskset.start();
- let taskWorkdir = t.path;
if (this._autoupdate_self)
ProcUtil.runSync(['git', 'pull', '-r'], cancellable)
@@ -155,25 +151,22 @@ const AutoBuilder = new Lang.Class({
}
this._queued_force_resolve = [];
let context = new GSystem.SubprocessContext({ argv: args });
- context.set_stdout_file_path(t.logfile_path.get_path());
- context.set_stderr_disposition(GSystem.SubprocessStreamDisposition.STDERR_MERGE);
- this._resolve_proc = new GSystem.Subprocess({context: context});
- this._resolve_proc.init(null);
- print(Format.vprintf("Resolve task %s.%s started (%s), pid=%s", [t.major, t.minor,
- isFull ? "full" : "incremental",
- this._resolve_proc.get_pid()]));
- this._resolve_proc.wait(null, Lang.bind(this, this._onResolveExited));
+ let workdir = this._resolve_taskset.prepare();
+ let tmpManifest = workdir.get_child(this._manifestPath.get_basename());
+ GSystem.file_linkcopy(this._manifestPath, tmpManifest, Gio.FileCopyFlags.OVERWRITE, cancellable);
+ let t = this._resolve_taskset.start(context,
+ cancellable,
+ Lang.bind(this, this._onResolveExited));
+ print(Format.vprintf("Resolve task %s.%s started (%s)", [t.major, t.minor,
+ isFull ? "full" : "incremental"]));
this._updateStatus();
return false;
},
- _onResolveExited: function(process, result) {
- this._resolve_proc = null;
- let [success, msg] = ProcUtil.asyncWaitCheckFinish(process, result);
+ _onResolveExited: function(resolveTask, success, msg) {
print(Format.vprintf("resolve exited; success=%s msg=%s", [success, msg]))
- this._resolve_taskset.finish(success);
this._prev_source_snapshot_path = this._source_snapshot_path;
this._source_snapshot_path = this._src_db.getLatestPath();
let changed = (this._prev_source_snapshot_path == null ||
@@ -182,7 +175,7 @@ const AutoBuilder = new Lang.Class({
print(Format.vprintf("New version is %s", [this._source_snapshot_path.get_path()]))
if (!this._build_needed)
this._build_needed = changed;
- if (this._build_needed && this._build_proc == null)
+ if (this._build_needed && !this._build_taskset.isRunning())
this._run_build();
if (this._full_resolve_needed || this._queued_force_resolve.length > 0) {
@@ -194,42 +187,33 @@ const AutoBuilder = new Lang.Class({
_run_build: function() {
let cancellable = null;
- if (this._build_proc != null) throw new Error();
+ if (this._build_taskset.isRunning()) throw new Error();
if (!this._build_needed) throw new Error();
this._build_needed = false;
- let task = this._build_taskset.start();
- let workdir = task.path;
- let transientSnapshotPath = workdir.get_child(this._source_snapshot_path.get_basename());
- GSystem.file_linkcopy(this._source_snapshot_path, transientSnapshotPath, Gio.FileCopyFlags.OVERWRITE, null);
- let args = ['ostbuild', 'build', '--snapshot=' + transientSnapshotPath.get_path()];
+ let snapshotName = this._source_snapshot_path.get_basename();
+
+ let workdir = this._build_taskset.prepare();
+ let tmpSnapshotPath = workdir.get_child(snapshotName);
+ GSystem.file_linkcopy(this._source_snapshot_path, tmpSnapshotPath,
+ Gio.FileCopyFlags.OVERWRITE, cancellable);
+
+ let args = ['ostbuild', 'build', '--snapshot=' + snapshotName];
args.push.apply(args, this._queued_force_builds);
this._queued_force_builds = [];
- let version = this._src_db.parseVersionStr(this._source_snapshot_path.get_basename());
- let meta = {'version': version,
- 'version-path': this._snapshot_dir.get_relative_path(this._source_snapshot_path)};
- let metaPath = workdir.get_child('meta.json');
- JsonUtil.writeJsonFileAtomic(metaPath, meta, cancellable);
-
let context = new GSystem.SubprocessContext({ argv: args });
- context.set_stdout_file_path(task.logfile_path.get_path());
- context.set_stderr_disposition(GSystem.SubprocessStreamDisposition.STDERR_MERGE);
- this._build_proc = new GSystem.Subprocess({context: context});
- this._build_proc.init(null);
- print(Format.vprintf("Build task %s.%s started, pid=%s", [task.major, task.minor, this._build_proc.get_pid()]));
- this._build_proc.wait(null, Lang.bind(this, this._onBuildExited));
+ let task = this._build_taskset.start(context,
+ cancellable,
+ Lang.bind(this, this._onBuildExited));
+ print(Format.vprintf("Build task %s.%s started", [task.major, task.minor]));
this._updateStatus();
},
- _onBuildExited: function(process, result) {
- if (this._build_proc == null) throw new Error();
- this._build_proc = null;
- let [success, msg] = ProcUtil.asyncWaitCheckFinish(process, result);
+ _onBuildExited: function(buildTaskset, success, msg) {
print(Format.vprintf("build exited; success=%s msg=%s", [success, msg]))
- this._build_taskset.finish(success);
if (this._build_needed)
this._run_build()
diff --git a/src/ostbuild/js/builtins/build.js b/src/ostbuild/js/builtins/build.js
index 70cc2f6..fa707ae 100644
--- a/src/ostbuild/js/builtins/build.js
+++ b/src/ostbuild/js/builtins/build.js
@@ -22,7 +22,7 @@ const Format = imports.format;
const GSystem = imports.gi.GSystem;
-const Task = imports.task;
+const SubTask = imports.subtask;
const JsonDB = imports.jsondb;
const ProcUtil = imports.procutil;
const StreamUtil = imports.streamutil;
@@ -277,6 +277,12 @@ const Build = new Lang.Class({
return cachedata['ostree'];
},
+ _onBuildComplete: function(taskset, success, msg, loop) {
+ this._currentBuildSucceded = success;
+ this._currentBuildSuccessMsg = msg;
+ loop.quit();
+ },
+
_buildOneComponent: function(component, architecture, cancellable) {
let basename = component['name'];
@@ -358,17 +364,15 @@ const Build = new Lang.Class({
}
}
- let taskdir = new Task.TaskDir(this.workdir.get_child('tasks'));
- let buildTaskset = taskdir.get(buildname);
- let t = buildTaskset.start()
- let workdir = t.path;
+ let taskdir = this.workdir.get_child('tasks');
+ let buildTaskset = new SubTask.TaskSet(taskdir.get_child(buildname));
+
+ let workdir = buildTaskset.prepare();
let tempMetadataPath = workdir.get_child('_ostbuild-meta.json');
JsonUtil.writeJsonFileAtomic(tempMetadataPath, expandedComponent, cancellable);
- let checkoutdir = this.workdir.get_child('checkouts');
- let componentSrc = checkoutdir.get_child(buildname);
- GSystem.file_ensure_directory(componentSrc.get_parent(), true, cancellable);
+ let componentSrc = workdir.get_child(basename);
let childArgs = ['ostbuild', 'checkout', '--snapshot=' + this._snapshot.path.get_path(),
'--checkoutdir=' + componentSrc.get_path(),
'--metadata-path=' + tempMetadataPath.get_path(),
@@ -417,16 +421,22 @@ const Build = new Lang.Class({
envCopy['CXXFLAGS'] = OPT_COMMON_CFLAGS[architecture];
let context = new GSystem.SubprocessContext({ argv: childArgs });
- context.set_stdout_file_path(t.logfile_path.get_path());
- context.set_stderr_disposition(GSystem.SubprocessStreamDisposition.STDERR_MERGE);
context.set_environment(ProcUtil.objectToEnvironment(envCopy));
- let proc = new GSystem.Subprocess({ context: context });
- proc.init(cancellable);
- print(Format.vprintf("Started child process %s: pid=%s", [JSON.stringify(proc.context.argv), proc.get_pid()]));
- let [res, estatus] = proc.wait_sync(cancellable);
- let [buildSuccess, msg] = ProcUtil.getExitStatusAndString(estatus);
+
+ let mainContext = new GLib.MainContext();
+ mainContext.push_thread_default();
+ let loop = GLib.MainLoop.new(mainContext, true);
+ let t;
+ try {
+ t = buildTaskset.start(context, cancellable, Lang.bind(this, this._onBuildComplete, loop));
+ loop.run();
+ } finally {
+ mainContext.pop_thread_default();
+ }
+ let buildSuccess = this._currentBuildSucceded;
+ let msg = this._currentBuildSuccessMsg;
+
if (!buildSuccess) {
- buildTaskset.finish(false);
this._analyzeBuildFailure(t, architecture, component, componentSrc,
currentVcsVersion, previousVcsVersion, cancellable);
throw new Error("Build failure in component " + buildname + " : " + msg);
@@ -463,8 +473,6 @@ const Build = new Lang.Class({
let ostreeRevision = this._saveComponentBuild(buildname, expandedComponent, cancellable);
- buildTaskset.finish(true);
-
return ostreeRevision;
},
diff --git a/src/ostbuild/js/jsonutil.js b/src/ostbuild/js/jsonutil.js
index 03431a0..04a82ca 100644
--- a/src/ostbuild/js/jsonutil.js
+++ b/src/ostbuild/js/jsonutil.js
@@ -22,10 +22,14 @@ const Gio = imports.gi.Gio;
* Read/write JSON to/from GFile paths, very inefficiently.
*/
-function writeJsonFileAtomic(path, data, cancellable) {
+function writeJsonToStream(stream, data, cancellable) {
let buf = JSON.stringify(data, null, " ");
+ stream.write_bytes(new GLib.Bytes(buf), cancellable);
+}
+
+function writeJsonFileAtomic(path, data, cancellable) {
let s = path.replace(null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, cancellable);
- s.write_bytes(new GLib.Bytes(buf), cancellable);
+ writeJsonToStream(s, data, cancellable);
s.close(cancellable);
}
diff --git a/src/ostbuild/js/task.js b/src/ostbuild/js/subtask.js
similarity index 78%
rename from src/ostbuild/js/task.js
rename to src/ostbuild/js/subtask.js
index c374a8f..d97968c 100644
--- a/src/ostbuild/js/task.js
+++ b/src/ostbuild/js/subtask.js
@@ -22,22 +22,9 @@ const Lang = imports.lang;
const GSystem = imports.gi.GSystem;
-const VERSION_RE = /(\d+)\.(\d+)/;
-
-const TaskDir = new Lang.Class({
- Name: 'TaskDir',
+const ProcUtil = imports.procutil;
- _init: function(path) {
- this.path = path;
- },
-
- get: function(name) {
- let child = this.path.get_child(name);
- GSystem.file_ensure_directory(child, true, null);
-
- return new TaskSet(child);
- }
-});
+const VERSION_RE = /(\d+)\.(\d+)/;
const TaskHistoryEntry = new Lang.Class({
Name: 'TaskHistoryEntry',
@@ -91,11 +78,13 @@ const TaskHistoryEntry = new Lang.Class({
const TaskSet = new Lang.Class({
Name: 'TaskSet',
- _init: function(path, prefix) {
+ _init: function(path) {
this.path = path;
+ GSystem.file_ensure_directory(this.path, true, null);
this._history = [];
this._running = false;
+ this._prepared = false;
this._running_version = null;
this._maxVersions = 10;
@@ -126,9 +115,25 @@ const TaskSet = new Lang.Class({
this._cleanOldEntries();
},
- start: function() {
+ _onProcessComplete: function(proc, result) {
+ if (!this._running) throw new Error();
+
+ let [success, msg] = ProcUtil.asyncWaitCheckFinish(proc, result);
+
+ let last = this._history[this._history.length-1];
+ last.finish(success);
+ this._running = false;
+ this._process = null;
+
+ this._cleanOldEntries();
+
+ this._processCallback(this, success, msg);
+ },
+
+ prepare: function() {
if (this._running) throw new Error();
- this._running = true;
+ if (this._prepared) throw new Error();
+ this._prepared = true;
let yearver = new Date().getFullYear();
let lastversion = -1;
if (this._history.length > 0) {
@@ -140,18 +145,33 @@ const TaskSet = new Lang.Class({
}
let historyPath = this.path.get_child(format.vprintf('%d.%d', [yearver, lastversion + 1]));
GSystem.file_ensure_directory(historyPath, true, null);
+
let entry = new TaskHistoryEntry(historyPath, 'running');
- this._history.push(entry);
entry.logfile_path = historyPath.get_child('log');
- return entry;
+ this._history.push(entry);
+
+ return historyPath;
},
- finish: function(success) {
- if (!this._running) throw new Error();
+ start: function(processContext, cancellable, callback) {
+ if (this._running) throw new Error();
+ if (!this._prepared)
+ this.prepare();
+ this._running = true;
+ this._prepared = false;
let last = this._history[this._history.length-1];
- last.finish(success);
- this._running = false;
- this._cleanOldEntries();
+ processContext.set_cwd(last.path.get_path());
+ processContext.set_stdout_file_path(last.logfile_path.get_path());
+ processContext.set_stderr_disposition(GSystem.SubprocessStreamDisposition.STDERR_MERGE);
+ this._process = new GSystem.Subprocess({ context: processContext });
+ this._processCallback = callback;
+ this._process.init(cancellable);
+ this._process.wait(cancellable, Lang.bind(this, this._onProcessComplete));
+ return last;
+ },
+
+ isRunning: function() {
+ return this._running;
},
getHistory: function() {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]