-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpull.js
200 lines (165 loc) · 6.54 KB
/
pull.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
const AQ = require('./gofish/aquarium.js');
const Connection = require("./connect.js");
var fs = require('fs');
class Puller {
constructor(instance_name, operation_type) {
this.instance_name = instance_name;
this.op_types = [];
if (operation_type !== "") {
this.op_types.push(operation_type);
}
this.libs = [];
this.connection = new Connection(this.instance_name);
}
// Pull all libraries and operation_types from the instance. Also
// create all directories to organize everything. Can take a long time.
async pull() {
this.mkdir(this.instance_name);
await this.connection.connect();
let success = true;
if (this.op_types.length === 0) {
this.op_types = await AQ.OperationType.all();
this.libs = await AQ.Library.all();
} else {
let ot = this.op_types[0];
this.op_types = await AQ.OperationType.where({name: ot});
if (this.op_types.length === 0) {
console.log(ot + " does not exist. Please try again and check spelling and case.");
success = false;
}
}
if (success) {
let objects = this.libs.concat(this.op_types);
for ( let i=0; i<objects.length; i++ ) {
this.fix_name(objects[i]);
this.make_category_directory(objects[i]);
await this.save_object_code(objects[i]);
this.save_object_info(objects[i]);
this.show_progress(i,objects.length, objects[i].name);
}
console.log("\ndone!");
}
}
// Makes a directory for the object's catagory. For example,
// if the instance is "stagin" and the category is "Cloning",
// then the following directory is set up:
// staging/
// Cloning/
// lib/
// op/
// Operations in this category will be put in op/ and libraries
// in lib/
make_category_directory(object) {
let path = this.instance_name + "/" + object.category + "/";
this.mkdir(path);
this.mkdir(path + "lib/");
this.mkdir(path + "op/");
}
// A convenience wrapper around the fs method by the same name that
// checks to see if the directory already exists.
mkdir(path) {
if (!fs.existsSync(path)) {
fs.mkdirSync(path);
}
}
// Remove any forward slashes in the name of the object, which would confuse
// thei filesystem.
// - object should be an operation_type or library
fix_name(object) {
if ( !object.name ) {
console.log("oops");
console.log(typeof object);
}
object.name = object.name.replace(/\//g, '-');
}
// Returns the path to the directory for the operation_type. For example,
// if the instance is called "staging", if the op_type has category "Cloning",
// and name "Run PCR" then this method would return staging/Cloning/op/Run \PCR/
op_type_path(op_type) {
return this.instance_name + "/" + op_type.category + "/op/" + op_type.name + "/";
}
// Similar to op_type_path but for libraries.
lib_path(lib) {
return this.instance_name + "/" + lib.category + "/lib/" + lib.name + "/";
}
// Retrieves and saves all source code for the given object
async save_object_code(object) {
if ( object.model.model == "OperationType" ) {
await this.save_op_type_code(object);
} else if ( object.model.model == "Library" ) {
await this.save_library_code(object);
}
}
// Retrives and saves the source code for the given operation_type including
// the protocol, precondition, documentation, and test files.
async save_op_type_code(op_type) {
let protocol = await this.get_code(op_type, "protocol"),
precondition = await this.get_code(op_type, "precondition"),
docs = await this.get_code(op_type, "documentation"),
test = await this.get_code(op_type, "test");
let path = this.op_type_path(op_type);
this.mkdir(path);
fs.writeFileSync(path+"protocol.rb", protocol.content);
fs.writeFileSync(path+"precondition.rb", precondition.content);
fs.writeFileSync(path+"documentation.md", docs.content);
fs.writeFileSync(path+"test.rb", test.content);
}
// Retrieves and saves the library source code.
async save_library_code(lib) {
let source = await this.get_code(lib, "source");
let path = this.lib_path(lib);
this.mkdir(path);
fs.writeFileSync(path+"source.rb", source.content);
}
// Saves a json file describing the object, and in particular noting
// the object's id, which can be used to find it in an Aquarium instance
// or to resave it's code.
save_object_info(object) {
let info = {
id: object.id,
name: object.name,
category: object.category,
type: object.model.model
}
let path = object.model.model == "OperationType"
? this.op_type_path(object)
: this.lib_path(object);
fs.writeFileSync(
path + "info.json",
JSON.stringify(info)
);
}
// Get code for a protocol or library from Aquarium instance.
// - object is either an OperationType or a Library
// - type is a string that Aquarium uses in a jnaky way to distinguish
// code types and is either "source", "protocol", "precondition", "test",
// or "documentation"
async get_code(object, type) {
let codes = await AQ.Code.where({
parent_class: object.model.model,
parent_id: object.id,
name: type
});
if ( codes.length > 0 ) {
let latest = 0;
for ( var i=0; i<codes.length; i++ ) {
if ( codes[i].id > latest ) {
latest = i;
}
}
return codes[latest];
} else {
return { content: "# Your code here" };
}
}
// Show progress for a loop. TODO: Put this in a utils module
// - i is the iteration through the loop
// - n is the total number of iterations in the loop
// - msg is a message to display
show_progress(i,n, msg) {
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write(Math.floor(100*(i + 1)/n) + "%: " + msg);
}
}
module.exports = Puller;