From 9a4b91d15d0377eed7b4148d14c0a0d3bffc840b Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:00:42 +0100 Subject: [PATCH 1/9] initial attempt --- src/JobsDataBase.ts | 9 +++-- src/action_worker.ts | 79 ++++++++++++++++++++++++++++++++++++++------ src/deps.ts | 2 +- src/main.ts | 2 +- 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/JobsDataBase.ts b/src/JobsDataBase.ts index 0d90660..c17eb60 100644 --- a/src/JobsDataBase.ts +++ b/src/JobsDataBase.ts @@ -5,12 +5,17 @@ import * as path from "https://deno.land/std@0.209.0/path/mod.ts"; export type Job = { id: string; - from: string; - till: string; + from?: string; + till?: string; author: { "name": string; "email": string; }; + files?: { + // only used for transform_all + modified?: string[]; + removed?: string[]; + }; }; export type JobStatus = { diff --git a/src/action_worker.ts b/src/action_worker.ts index f669ff2..44700bf 100644 --- a/src/action_worker.ts +++ b/src/action_worker.ts @@ -4,7 +4,7 @@ * The jobs are accepted as messages and stored on disk, when the worker is started uncompleted jobs are picked up and exxecuted. */ -import { path } from "./deps.ts"; +import { path, walk } from "./deps.ts"; import { config } from "../config/config.ts"; import { createBadge } from "./log.ts"; import { type Job, JobsDataBase } from "./JobsDataBase.ts"; @@ -20,10 +20,14 @@ let isRunning = false; await startTask(); self.onmessage = (evt) => { - const job = evt.data as Job; - queue.addJob(job); - if (!isRunning) startTask(); - else console.log("Already running"); + const job = evt.data as Job | "FULLUPDATE"; + if (job === "FULLUPDATE") { + gatherJobsForFullUpdate(); + } else { + queue.addJob(job); + if (!isRunning) startTask(); + else console.log("Already running"); + } }; async function startTask() { @@ -35,6 +39,45 @@ async function startTask() { } } +async function gatherJobsForFullUpdate() { + isRunning = true; + try { + updateLocalData("source", console.log); + const date = (new Date()).toISOString(); + let block = 0; + let files: string[] = []; + for await ( + const walkEntry of walk(Deno.cwd(), { + exts: ["xml"], + includeDirs: false, + includeSymlinks: false, + }) + ) { + if (walkEntry.isFile && walkEntry.path.endsWith(".xml")) { + files.push(walkEntry.path); + if (files.length >= 100) { + queue.addJob({ + author: { + name: "GG2RDF Service", + email: "gg2rdf@plazi.org", + }, + id: `full update ${date} [${block++}]`, + files: { + modified: files, + }, + }); + files = []; + } + } + } + } catch (error) { + console.error("Could not create full-update jobs\n" + error); + } finally { + isRunning = false; + startTask(); + } +} + async function run() { while (queue.pendingJobs().length > 0) { const jobStatus = queue.pendingJobs()[0]; @@ -47,10 +90,26 @@ async function run() { try { log("Starting transformation" + JSON.stringify(job, undefined, 2)); - const files = getModifiedAfter(job.from, job.till, log); - - const modified = [...files.added, ...files.modified]; - const removed = files.removed; + let modified: string[] = []; + let removed: string[] = []; + let message = ""; + + if (job.files) { + modified = job.files.modified || []; + removed = job.files.removed || []; + message = + `committed by action runner ${config.sourceRepository} ${job.id}`; + } else if (job.from) { + const files = getModifiedAfter(job.from, job.till, log); + modified = [...files.added, ...files.modified]; + removed = files.removed; + message = + `committed by action runner ${config.sourceRepository}@${job.id}`; + } else { + throw new Error( + "Could not start job, neither explicit file list nor from-commit specified", + ); + } updateLocalData("source", log); @@ -126,7 +185,7 @@ async function run() { const gitCommands = `git config --replace-all user.name ${job.author.name} git config --replace-all user.email ${job.author.email} git add -A - git commit --quiet -m "committed by action runner ${config.sourceRepository}@${job.id}" + git commit --quiet -m "${message}" git push --quiet ${ config.targetRepositoryUri.replace( "https://", diff --git a/src/deps.ts b/src/deps.ts index 3393791..a3c403b 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -9,7 +9,7 @@ export { serveFile, } from "https://deno.land/std@0.202.0/http/file_server.ts"; -export { existsSync } from "https://deno.land/std@0.202.0/fs/mod.ts"; +export { existsSync, walk } from "https://deno.land/std@0.202.0/fs/mod.ts"; export * as path from "https://deno.land/std@0.209.0/path/mod.ts"; export { parseArgs } from "https://deno.land/std@0.215.0/cli/parse_args.ts"; diff --git a/src/main.ts b/src/main.ts index 98ef7cc..dbedd22 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,7 +78,7 @@ const webhookHandler = async (request: Request) => { } if (pathname === "/full_update") { console.log("· got full_update request"); - // TODO + worker.postMessage("FULLUPDATE"); return new Response("Not Implemented", { status: Status.NotImplemented, statusText: STATUS_TEXT[Status.NotImplemented], From 30b65a0df36f2c6218253f35e2f7380916edea7f Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:02:11 +0100 Subject: [PATCH 2/9] cleanup --- src/action_worker.ts | 2 +- src/main.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/action_worker.ts b/src/action_worker.ts index 44700bf..8aaf0f5 100644 --- a/src/action_worker.ts +++ b/src/action_worker.ts @@ -78,7 +78,7 @@ async function gatherJobsForFullUpdate() { } } -async function run() { +function run() { while (queue.pendingJobs().length > 0) { const jobStatus = queue.pendingJobs()[0]; const job = jobStatus.job; diff --git a/src/main.ts b/src/main.ts index dbedd22..f14e2af 100644 --- a/src/main.ts +++ b/src/main.ts @@ -79,9 +79,9 @@ const webhookHandler = async (request: Request) => { if (pathname === "/full_update") { console.log("· got full_update request"); worker.postMessage("FULLUPDATE"); - return new Response("Not Implemented", { - status: Status.NotImplemented, - statusText: STATUS_TEXT[Status.NotImplemented], + return new Response(undefined, { + status: Status.Accepted, + statusText: STATUS_TEXT[Status.Accepted], }); } else { if (WEBHOOK_SECRET && !(await verifySignature(request))) { From 89ac68aec21d1fa67b8bd7c49e2fccf8c2b7e827 Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:10:20 +0100 Subject: [PATCH 3/9] changed to type import --- src/gg2rdf.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gg2rdf.ts b/src/gg2rdf.ts index ea6904b..20707f8 100644 --- a/src/gg2rdf.ts +++ b/src/gg2rdf.ts @@ -1,5 +1,5 @@ import { DOMParser, parseArgs } from "./deps.ts"; -import { Element } from "https://esm.sh/v135/linkedom@0.16.8/types/interface/element.d.ts"; +import type { Element } from "https://esm.sh/v135/linkedom@0.16.8/types/interface/element.d.ts"; class Subject { properties: { [key: string]: Set } = {}; From 94c10ace6d06dbe9ca7c7e2d24ce3b027ab2fed8 Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:21:41 +0100 Subject: [PATCH 4/9] various fixes --- src/action_worker.ts | 11 +++++++++-- src/repoActions.ts | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/action_worker.ts b/src/action_worker.ts index 8aaf0f5..17d94fc 100644 --- a/src/action_worker.ts +++ b/src/action_worker.ts @@ -42,12 +42,14 @@ async function startTask() { async function gatherJobsForFullUpdate() { isRunning = true; try { - updateLocalData("source", console.log); + console.log("gathering jobs for full update"); + updateLocalData("source"); + console.log("pull complete"); const date = (new Date()).toISOString(); let block = 0; let files: string[] = []; for await ( - const walkEntry of walk(Deno.cwd(), { + const walkEntry of walk(`${config.workDir}/repo/source/`, { exts: ["xml"], includeDirs: false, includeSymlinks: false, @@ -55,6 +57,7 @@ async function gatherJobsForFullUpdate() { ) { if (walkEntry.isFile && walkEntry.path.endsWith(".xml")) { files.push(walkEntry.path); + console.log("added", walkEntry.path); if (files.length >= 100) { queue.addJob({ author: { @@ -66,10 +69,14 @@ async function gatherJobsForFullUpdate() { modified: files, }, }); + console.log("added Job"); files = []; } + } else { + console.log("skipped", walkEntry.path); } } + console.log(`succesfully created full-update jobs (${block} jobs)`); } catch (error) { console.error("Could not create full-update jobs\n" + error); } finally { diff --git a/src/repoActions.ts b/src/repoActions.ts index 149e6f2..cabb059 100644 --- a/src/repoActions.ts +++ b/src/repoActions.ts @@ -49,8 +49,9 @@ const cloneRepo = (which: "source" | "target", log = console.log) => { // Function to update local data export function updateLocalData( which: "source" | "target", - log = console.log, + log: (msg: string) => void = console.log, ) { + log("starting git pull..."); Deno.mkdirSync(`${config.workDir}/repo/${which}/.git`, { recursive: true }); const p = new Deno.Command("git", { args: ["pull"], From 86967cbfd4e8fd80f6047f38f618ae2fa58ef411 Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 18:46:24 +0100 Subject: [PATCH 5/9] updated readme --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 75ff655..3bfbbab 100644 --- a/README.md +++ b/README.md @@ -12,31 +12,34 @@ This Docker Image exposes a server on port `4505` which: This webserver also exposes the follwing paths: - `/status`: Serves a Badge (svg) to show the current pipeline status -- `/logs`: List of logs of past runs -- `/logs/[id]`: Log of past run with that id. -- `/update?from=[from-commit-id]&till=[till-commit-id]`: send a `POST` here to update all files modified since from-commit-id up till-commit-id or HEAD if not specified -- `/full_update`: send a `POST` here to run the full_update script. (Not - implemented yet, continue using the scripts in the "manual run" directory) +- `/workdir/jobs/`: List of runs +- `/workdir/jobs/[id]/status.json`: Status of run with that id +- `/workdir/jobs/[id]/log.txt`: Log of run with that id +- `/update?from=[from-commit-id]&till=[till-commit-id]`: send a `POST` here to + update all files modified since from-commit-id up till-commit-id or HEAD if + not specified +- `/full_update`: send a `POST` here to run the full_update script. ## Usage Build as a docker container. + ```sh docker build . -t gg2rdf ``` -Requires a the environment-variable `GHTOKEN` as `username:` -to authenticate the pushing into the target-repo. +Requires a the environment-variable `GHTOKEN` as +`username:` to authenticate the pushing into the +target-repo. Then run using a volume + ```sh docker run --name gg2rdf --env GHTOKEN=username: -p 4505:4505 -v gg2rdf:/app/workdir gg2rdf ``` Exposes port `4505`. - - ### Docker-Compose ```yml @@ -57,7 +60,8 @@ Edit the file `config/config.ts`. Should be self-explanatory what goes where. ## Development -The repo comes with vscode devcontaioner configurations. Some tweaks to allow using git from inside the devcontainer. +The repo comes with vscode devcontaioner configurations. Some tweaks to allow +using git from inside the devcontainer. To start from the terminal in vscode: From 03161e0a697d550cbcc5e2d7155f707eb79950fd Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:02:27 +0100 Subject: [PATCH 6/9] should work --- src/JobsDataBase.ts | 6 +++--- src/action_worker.ts | 22 ++++++++++++++-------- src/main.ts | 10 ++++++++-- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/JobsDataBase.ts b/src/JobsDataBase.ts index c17eb60..b959394 100644 --- a/src/JobsDataBase.ts +++ b/src/JobsDataBase.ts @@ -60,13 +60,13 @@ export class JobsDataBase { ); } - allJobs(): JobStatus[] { + allJobs(oldestFirst = false): JobStatus[] { const jobDirs = []; for (const jobDir of Deno.readDirSync(this.jobsDir)) { jobDirs.push(jobDir); } return jobDirs.filter((entry) => entry.isDirectory).sort((a, b) => - b.name.localeCompare(a.name) + oldestFirst ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name) ).map((jobDir) => { const statusFile = path.join(this.jobsDir, jobDir.name, "status.json"); try { @@ -98,6 +98,6 @@ export class JobsDataBase { }).filter(notEmpty); } pendingJobs() { - return this.allJobs().filter((js) => js.status === "pending"); + return this.allJobs(true).filter((js) => js.status === "pending"); } } diff --git a/src/action_worker.ts b/src/action_worker.ts index 17d94fc..6d9df02 100644 --- a/src/action_worker.ts +++ b/src/action_worker.ts @@ -44,9 +44,9 @@ async function gatherJobsForFullUpdate() { try { console.log("gathering jobs for full update"); updateLocalData("source"); - console.log("pull complete"); const date = (new Date()).toISOString(); let block = 0; + const jobs: Job[] = []; let files: string[] = []; for await ( const walkEntry of walk(`${config.workDir}/repo/source/`, { @@ -56,26 +56,32 @@ async function gatherJobsForFullUpdate() { }) ) { if (walkEntry.isFile && walkEntry.path.endsWith(".xml")) { - files.push(walkEntry.path); - console.log("added", walkEntry.path); - if (files.length >= 100) { - queue.addJob({ + files.push( + walkEntry.path.replace(`${config.workDir}/repo/source/`, ""), + ); + if (files.length >= 500) { + jobs.push({ author: { name: "GG2RDF Service", email: "gg2rdf@plazi.org", }, - id: `full update ${date} [${block++}]`, + id: `full update ${date} [${ + (++block).toString(10).padStart(4, "0") + }`, files: { modified: files, }, }); - console.log("added Job"); files = []; } } else { console.log("skipped", walkEntry.path); } } + jobs.forEach((j) => { + j.id += ` of ${block.toString(10).padStart(4, "0")}]`; + queue.addJob(j); + }); console.log(`succesfully created full-update jobs (${block} jobs)`); } catch (error) { console.error("Could not create full-update jobs\n" + error); @@ -95,7 +101,7 @@ function run() { }); }; try { - log("Starting transformation" + JSON.stringify(job, undefined, 2)); + log("Starting transformation\n" + JSON.stringify(job, undefined, 2)); let modified: string[] = []; let removed: string[] = []; diff --git a/src/main.ts b/src/main.ts index f14e2af..f64ee5a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -33,7 +33,14 @@ const WEBHOOK_SECRET: string | undefined = Deno.env.get("WEBHOOK_SECRET"); await Deno.mkdir(`${config.workDir}/repo`, { recursive: true }); await Deno.mkdir(`${config.workDir}/tmprdf`, { recursive: true }); await Deno.mkdir(`${config.workDir}/tmpttl`, { recursive: true }); -await createBadge("Unknown"); + +const db = new JobsDataBase(`${config.workDir}/jobs`); +const latest = + db.allJobs().find((j) => j.status === "completed" || j.status === "failed") + ?.status || "Unknown"; +if (latest === "failed") createBadge("Failed"); +else if (latest === "completed") createBadge("OK"); +else createBadge("Unknown"); const worker = new Worker( new URL("./action_worker.ts", import.meta.url).href, @@ -136,7 +143,6 @@ const webhookHandler = async (request: Request) => { response.headers.set("Content-Type", "image/svg+xml"); return response; } else if (pathname === "/jobs.json") { - const db = new JobsDataBase(`${config.workDir}/jobs`); const json = JSON.stringify(db.allJobs(), undefined, 2); const response = new Response(json); response.headers.set("Content-Type", "application/json"); From 2e12f26d1b01bbd69c6f4df152f9475c530998f5 Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:10:43 +0100 Subject: [PATCH 7/9] moved datestamp to front for correct ordering of jobs --- src/action_worker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/action_worker.ts b/src/action_worker.ts index 6d9df02..2e0fe40 100644 --- a/src/action_worker.ts +++ b/src/action_worker.ts @@ -65,7 +65,7 @@ async function gatherJobsForFullUpdate() { name: "GG2RDF Service", email: "gg2rdf@plazi.org", }, - id: `full update ${date} [${ + id: `${date} full update [${ (++block).toString(10).padStart(4, "0") }`, files: { From 419459906c517ff70ee557a56e90fd69e83c9500 Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:16:23 +0100 Subject: [PATCH 8/9] added note about not removing files --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3bfbbab..735f682 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ This webserver also exposes the follwing paths: - `/update?from=[from-commit-id]&till=[till-commit-id]`: send a `POST` here to update all files modified since from-commit-id up till-commit-id or HEAD if not specified -- `/full_update`: send a `POST` here to run the full_update script. +- `/full_update`: send a `POST` here to run the full_update script. Note that + this will not delete any files (yet). ## Usage From 4bcec72334bebd7a2e9ebd56b6212761fad9aaac Mon Sep 17 00:00:00 2001 From: nleanba <25827850+nleanba@users.noreply.github.com> Date: Thu, 29 Feb 2024 19:20:33 +0100 Subject: [PATCH 9/9] removed obsolete manual run --- manual run/main-on-all-wrapper.sh | 28 ---------------- manual run/main-on-all.sh | 55 ------------------------------- manual run/readme | 7 ---- 3 files changed, 90 deletions(-) delete mode 100755 manual run/main-on-all-wrapper.sh delete mode 100755 manual run/main-on-all.sh delete mode 100644 manual run/readme diff --git a/manual run/main-on-all-wrapper.sh b/manual run/main-on-all-wrapper.sh deleted file mode 100755 index 32ebc6b..0000000 --- a/manual run/main-on-all-wrapper.sh +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -#TODO VARS -GITHUB_WORKSPACE=`pwd` -GITHUB_ACTION_PATH=`pwd` - -echo "GG-XML input : $GITHUB_WORKSPACE/xml" -echo "Turtle output: $GITHUB_WORKSPACE/ttl" -echo "xslt : $GITHUB_WORKSPACE/gg2rdf.xslt" -echo "saxon : $GITHUB_WORKSPACE/saxon-he-10.8.jar" -echo "script : $GITHUB_WORKSPACE/main-on-all.sh" - -[[ ! -d "$GITHUB_WORKSPACE/xml" ]] && echo -e "\e[1;31mno exists: $GITHUB_WORKSPACE/xml\e[0m" && exit 1 -[[ -d "$GITHUB_WORKSPACE/ttl" ]] && echo -e "\e[1;31mexists: $GITHUB_WORKSPACE/ttl\e[0m" && exit 1 -[[ ! -f "$GITHUB_WORKSPACE/gg2rdf.xslt" ]] && echo -e "\e[1;31mno exists: $GITHUB_WORKSPACE/gg2rdf.xslt\e[0m" && exit 1 -[[ ! -f "$GITHUB_WORKSPACE/saxon-he-10.8.jar" ]] && echo -e "\e[1;31mno exists: $GITHUB_WORKSPACE/saxon-he-10.8.jar\e[0m" && exit 1 -[[ ! -f "$GITHUB_WORKSPACE/main-on-all.sh" ]] && echo -e "\e[1;31mno exists: $GITHUB_WORKSPACE/main-on-all.sh\e[0m" && exit 1 - - -mkdir "$GITHUB_WORKSPACE/ttl" - -docker run\ - -v "$GITHUB_WORKSPACE"/xml:/workspace/xml\ - -v "$GITHUB_WORKSPACE"/ttl:/workspace/ttl\ - -v "$GITHUB_WORKSPACE"/gg2rdf.xslt:/workspace/gg2rdf.xslt\ - -v "$GITHUB_WORKSPACE"/saxon-he-10.8.jar:/workspace/saxon-he-10.8.jar\ - -v "$GITHUB_WORKSPACE"/main-on-all.sh:/workspace/main-on-all.sh\ - ubuntu /workspace/main-on-all.sh diff --git a/manual run/main-on-all.sh b/manual run/main-on-all.sh deleted file mode 100755 index ac18d36..0000000 --- a/manual run/main-on-all.sh +++ /dev/null @@ -1,55 +0,0 @@ -#! /bin/bash - -## ./xml ----> ./ttl - -#TODO VARS -GITHUB_WORKSPACE=/workspace/ -GITHUB_ACTION_PATH=/workspace/ -GITHUB_ACTOR=retog - -apt update -DEBIAN_FRONTEND=noninteractive apt install -y raptor2-utils openjdk-11-jdk git curl - # This is assuming that /usr/bin is in the path -ls -l $GITHUB_ACTION_PATH -ls -l $GITHUB_WORKSPACE - -#git clone --depth 1 git@github.com:plazi/treatments-xml.git $GITHUB_WORKSPACE/xml - -# Run saxon on all files -cd $GITHUB_WORKSPACE/xml -mkdir $GITHUB_WORKSPACE/rdf -for file in $(find . -type f); do - if [[ $file == *.xml ]]; then - echo "$file is xml, applying saxon" - mkdir -p $GITHUB_WORKSPACE/rdf/${file%/*} - java -jar $GITHUB_ACTION_PATH/saxon-he-10.8.jar -s:$file -o:$GITHUB_WORKSPACE/rdf/${file:0:-4}.rdf -xsl:$GITHUB_ACTION_PATH/gg2rdf.xslt - fi -done - -# Convert all generated RDF-XML files to TTL -cd $GITHUB_WORKSPACE/rdf -mkdir -p $GITHUB_WORKSPACE/ttl -for file in $(find . -type f); do - echo "$file in generated rdf-xml folder" - relative_file=`realpath -m --relative-to=$GITHUB_WORKSPACE/rdf $file` - mkdir -p $GITHUB_WORKSPACE/ttl/${relative_file%/*} - # $file → $GITHUB_WORKSPACE/ttl/${file:0:-4}.ttl - rapper -e -w -q $file --output turtle > $GITHUB_WORKSPACE/ttl/${file:0:-4}.ttl -done - -#git clone --depth 1 git@github.com:plazi/treatments-rdf.git $GITHUB_WORKSPACE/ttl-repo -# -## Remove -#cd $GITHUB_WORKSPACE/ttl-repo -#rm -rf data -# -## Move -#cd $GITHUB_WORKSPACE -#mv ttl ttl-repo -# -#cd $GITHUB_WORKSPACE/ttl-repo -#git config user.name $GITHUB_ACTOR -#git config user.email $GITHUB_ACTOR@users.noreply.github.com -#git add -A -#git commit -m "manual conversion of all files" -#git push origin main diff --git a/manual run/readme b/manual run/readme deleted file mode 100644 index bdc046f..0000000 --- a/manual run/readme +++ /dev/null @@ -1,7 +0,0 @@ -# this is outdated, do not use - -Run the ./main-on-all-wrapper.sh skript to convert everything in pwd/xml to ttl (placed into pwd/ttl) - -`pwd`/xml must exist & contain xml data -`pwd`/ttl must not exist -`pwd`/gg2rdf.xslt must exist \ No newline at end of file