gd_bam 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/bam CHANGED
@@ -30,14 +30,13 @@ command :generate do |c|
30
30
  c.flag :only
31
31
 
32
32
  c.action do |global_options,options,args|
33
- GoodData::Bam::Commands::clobber_etl_project('.')
34
- GoodData::Bam::Commands::setup_etl_project('.', PARAMS.merge(options).merge({:project_name => "etl-#{PARAMS[:project_name]}"}))
35
- GoodData::Bam::Commands::generate('.', PARAMS.merge(options).merge({
33
+ params = PARAMS.merge(options).merge({
36
34
  :project_name => "etl-#{PARAMS[:project_name]}",
37
35
  :graph_repos => [
38
36
  GoodData::Bam::Repository.create(:type => :file, :base => Pathname('./local_graphs').expand_path),
39
37
  GoodData::Bam::Repository.create(:type => :file, :base => GoodData::CloverGenerator::BAM_DEFINED_GRAPHS_ROOT)
40
- ]}))
38
+ ]})
39
+ GoodData::Bam::Commands::generate('.', params)
41
40
  end
42
41
  end
43
42
 
@@ -292,8 +291,8 @@ command :deploy do |c|
292
291
  fail "Specified directory does not exist" unless File.exist?(dir)
293
292
 
294
293
  GoodData::Bam::Commands::connect_to_gd()
295
- options = global_options.merge(options)
296
- response = GoodData::Bam::Commands::deploy(dir, options)
294
+ params = PARAMS.merge(global_options.merge(options))
295
+ response = GoodData::Bam::Commands::deploy(dir, params)
297
296
  end
298
297
  end
299
298
 
@@ -310,9 +309,9 @@ command :run do |c|
310
309
  fail "You have to specify directory to deploy as an argument" if dir.nil?
311
310
  fail "Specified directory does not exist" unless File.exist?(dir)
312
311
 
313
- options = global_options.merge(options)
312
+ params = PARAMS.merge(global_options.merge(options))
314
313
  GoodData::Bam::Commands::connect_to_gd()
315
- GoodData::Bam::Commands::run(dir, options)
314
+ GoodData::Bam::Commands::run(dir, params)
316
315
  end
317
316
  end
318
317
 
data/lib/bam/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Bam
2
- VERSION = '0.1.1'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -96,13 +96,10 @@ module GoodData
96
96
  end
97
97
 
98
98
  def self.generate(home, params)
99
- project = GoodData::Bam::Project.build_project(params)
100
-
101
99
  # fail "The flow you specified was not found" if flows.empty? && !only_flow.nil?
102
- fail "There are no flows to generate from" if project[:flows].empty?
103
-
104
- v = Compiler::EtlVisitor.new
105
- v.visit(project, params)
100
+ GoodData::Bam::Commands::clobber_etl_project('.')
101
+ GoodData::Bam::Commands::setup_etl_project('.', params)
102
+ GoodData::Bam::Generators::Etl.generate('.', params)
106
103
  end
107
104
 
108
105
  end
@@ -32,7 +32,7 @@ module GoodData
32
32
  end
33
33
  end
34
34
 
35
- def self.execute_process(link, dir)
35
+ def self.execute_process(link, dir, options={})
36
36
  dir = Pathname(dir)
37
37
  result = GoodData.post(link, {
38
38
  :execution => {
@@ -59,10 +59,10 @@ module GoodData
59
59
 
60
60
  dir = Pathname(dir)
61
61
 
62
- deploy(dir, options.merge(:name => "Temporary deploy[#{dir}][#{PARAMS[:project_name]}]")) do |deploy_response|
62
+ deploy(dir, options.merge(:name => "Temporary deploy[#{dir}][#{options[:project_name]}]")) do |deploy_response|
63
63
  puts HighLine::color("Executing", HighLine::BOLD) if verbose
64
64
  if email.nil?
65
- result = execute_process(deploy_response["process"]["links"]["executions"], dir)
65
+ result = execute_process(deploy_response["process"]["links"]["executions"], dir, options)
66
66
  else
67
67
  create_email_channel(options) do |channel_response|
68
68
  subscribe_on_finish(:success, channel_response, deploy_response, options)
@@ -128,7 +128,7 @@ module GoodData
128
128
  }
129
129
  }
130
130
  profile_id = GoodData.connection.user["profile"].split("/").last
131
- GoodData.post("/gdc/projects/#{PARAMS[:project_pid]}/users/#{profile_id}/subscriptions", data)
131
+ GoodData.post("/gdc/projects/#{options[:project_pid]}/users/#{profile_id}/subscriptions", data)
132
132
  end
133
133
 
134
134
  def self.deploy(dir, options={}, &block)
@@ -148,8 +148,10 @@ module GoodData
148
148
 
149
149
  def self.deploy_graph(dir, options={})
150
150
  dir = Pathname(dir)
151
- deploy_name = options[:name] || "#{PARAMS[:project_name]}"
151
+ deploy_name = options[:name] || options[:project_name]
152
152
  verbose = options[:verbose] || false
153
+ project_pid = options[:project_pid]
154
+
153
155
  puts HighLine::color("Deploying #{dir}", HighLine::BOLD) if verbose
154
156
  res = nil
155
157
 
@@ -174,9 +176,9 @@ module GoodData
174
176
  }
175
177
  }
176
178
  res = if process_id.nil?
177
- GoodData.post("/gdc/projects/#{PARAMS[:project_pid]}/dataload/processes", data)
179
+ GoodData.post("/gdc/projects/#{project_pid}/dataload/processes", data)
178
180
  else
179
- GoodData.put("/gdc/projects/#{PARAMS[:project_pid]}/dataload/processes/#{process_id}", data)
181
+ GoodData.put("/gdc/projects/#{project_pid}/dataload/processes/#{process_id}", data)
180
182
  end
181
183
  end
182
184
  puts HighLine::color("Deploy DONE #{dir}", HighLine::BOLD) if verbose
@@ -7,6 +7,16 @@ module GoodData
7
7
  include GoodData::CloudConnect
8
8
 
9
9
 
10
+ def self.generate(home, params={})
11
+
12
+ project = GoodData::Bam::Project.build_project(params)
13
+ fail "There are no flows to generate from" if project[:flows].empty?
14
+
15
+ v = Compiler::EtlVisitor.new
16
+ v.visit(project, params)
17
+
18
+ end
19
+
10
20
  def self.create_es_readmap(metadata, tap)
11
21
  e = Es::Entity.new("x", {
12
22
  :file => "none",
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <Graph author="gdc-defectivedisplay" created="Thu Mar 07 20:20:14 PST 2013" guiVersion="3.3.2" id="1362726965567" licenseType="Commercial" modified="Tue Jun 25 17:05:18 PDT 2013" modifiedBy="tomassvarovsky" name="process_opportunity_line_item" revision="1.36" showComponentDetails="true">
2
+ <Graph author="gdc-defectivedisplay" created="Thu Mar 07 20:20:14 PST 2013" guiVersion="3.3.2" id="1362726965567" licenseCode="CLP1DGOODD71636137BY" licenseType="Commercial" modified="Tue Jun 25 17:05:18 PDT 2013" modifiedBy="tomassvarovsky" name="process_opportunity_line_item" revision="1.36" showComponentDetails="true">
3
3
  <Global>
4
4
  <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_in.xml" id="Metadata0"/>
5
5
  <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata1"/>
@@ -58,8 +58,12 @@ function integer transform() {
58
58
 
59
59
  $out.0.* = $in.0.*;
60
60
 
61
- $out.0.Amount = nvl($in.1.TotalPrice, $in.0.Amount);
62
- $out.0.ProductId = $in.1.PricebookEntryId;
61
+ $out.0.Amount = nvl2($in.1.TotalPrice, $in.1.TotalPrice, $in.0.Amount);
62
+ $out.0.OpportunityId = $in.0.Id;
63
+ $out.0.LineItemId = nvl2($in.1.Id, $in.1.Id, null);
64
+ $out.0.Id = nvl2($in.1.Id, $in.1.Id, $in.0.Id);
65
+
66
+ $out.0.ProductId = nvl2($in.1.PricebookEntryId, $in.1.PricebookEntryId, null);
63
67
 
64
68
  return ALL;
65
69
  }
@@ -1,15 +1,32 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <Graph author="gdc-defectivedisplay" created="Sat Mar 16 12:07:29 PDT 2013" guiVersion="3.3.2" id="1363463772522" licenseCode="CLP1DGOODD71636137BY" licenseType="Commercial" modified="Mon Mar 18 14:06:35 PDT 2013" modifiedBy="gdc-defectivedisplay" name="velocity" revision="1.44" showComponentDetails="true">
2
+ <Graph author="fluke" created="Tue Feb 05 15:38:24 PST 2013" guiVersion="3.3.2" id="1360179808937" licenseType="Commercial" modified="Sat Jun 29 15:50:00 PDT 2013" modifiedBy="tomassvarovsky" name="process_name" revision="1.75" showComponentDetails="true">
3
3
  <Global>
4
4
  <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_in.xml" id="Metadata0"/>
5
- <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata2"/>
6
- <Metadata id="Metadata1" previewAttachmentCharset="ISO-8859-1">
7
- <Record fieldDelimiter="," name="recordName2" previewAttachmentCharset="ISO-8859-1" recordDelimiter="\n" type="delimited">
8
- <Field containerType="list" name="dates" nullable="false" type="string"/>
5
+ <Metadata fileURL="${PROJECT}/metadata/${FLOW}/${NAME}/1_out.xml" id="Metadata1"/>
6
+ <MetadataGroup id="ComponentGroup0" name="metadata"/>
7
+ <Metadata id="Metadata2">
8
+ <Record fieldDelimiter="," name="InItem" recordDelimiter="\n" type="delimited">
9
9
  <Field name="Id" type="string"/>
10
- <Field name="size" type="number"/>
11
- <Field containerType="list" name="stages" nullable="false" type="string"/>
12
- <Field containerType="list" name="sortOrders" nullable="false" type="string"/>
10
+ <Field name="Stage" type="string"/>
11
+ <Field name="Date" type="long"/>
12
+ </Record>
13
+ </Metadata>
14
+ <Metadata id="Metadata3">
15
+ <Record fieldDelimiter="," name="OutItem" recordDelimiter="\n" type="delimited">
16
+ <Field name="Id" type="string"/>
17
+ <Field name="Stage" type="string"/>
18
+ <Field name="Date" type="long"/>
19
+ <Field name="Duration" type="long"/>
20
+ <Field name="Velocity" type="long"/>
21
+ </Record>
22
+ </Metadata>
23
+ <Metadata id="Metadata4" previewAttachmentCharset="ISO-8859-1">
24
+ <Record fieldDelimiter="," name="Output" previewAttachmentCharset="ISO-8859-1" recordDelimiter="\n" type="delimited">
25
+ <Field name="Id" type="string"/>
26
+ <Field name="Stage" type="string"/>
27
+ <Field name="Date" type="string"/>
28
+ <Field name="Duration" type="string"/>
29
+ <Field name="Velocity" type="string"/>
13
30
  </Record>
14
31
  </Metadata>
15
32
  <Property fileURL="params.prm" id="GraphParameter0"/>
@@ -17,113 +34,120 @@
17
34
  <Dictionary/>
18
35
  </Global>
19
36
  <Phase number="0">
20
- <Node enabled="enabled" fileURL="${PROJECT}/data/1_in.csv" guiHeight="89" guiName="CSV Reader" guiWidth="128" guiX="13" guiY="119" id="DATA_READER0" quotedStrings="true" skipRows="1" type="DATA_READER"/>
21
- <Node enabled="enabled" fileURL="${PROJECT}/data/out.csv" guiHeight="89" guiName="CSV Writer" guiWidth="128" guiX="649" guiY="119" id="DATA_WRITER0" outputFieldNames="true" quotedStrings="true" type="DATA_WRITER"/>
22
- <Node enabled="enabled" guiHeight="77" guiName="ExtSort" guiWidth="128" guiX="211" guiY="119" id="EXT_SORT0" sortKey="Id(a);Snapshot(a)" type="EXT_SORT"/>
23
- <Node enabled="enabled" groupAccumulatorMetadataId="Metadata1" groupKeyFields="Id" guiHeight="65" guiName="Rollup" guiWidth="128" guiX="390" guiY="119" id="ROLLUP0" inputSorted="true" type="ROLLUP">
37
+ <Node aggregateKey="OpportunityId;StageName;ForecastCategoryName;AccountId;OwnerId;CreatedDate;CloseDate;ProductId" enabled="enabled" equalNULL="true" guiHeight="65" guiName="Aggregate" guiWidth="128" guiX="966" guiY="137" id="AGGREGATE0" mapping="$ForecastCategoryName:=$ForecastCategoryName;$AccountId:=$AccountId;$OwnerId:=$OwnerId;$StageName:=$StageName;$CreatedDate:=$CreatedDate;$CloseDate:=$CloseDate;$OpportunityId:=$OpportunityId;$ProductId:=$ProductId;$Velocity:=first($Velocity);$Duration:=sum($Duration);" sorted="true" type="AGGREGATE"/>
38
+ <Node enabled="enabled" fileURL="data/1_in.csv" guiHeight="77" guiName="CSV Reader" guiWidth="128" guiX="-184" guiY="122" id="DATA_READER0" quoteCharacter="&quot;" quotedStrings="true" skipRows="1" type="DATA_READER"/>
39
+ <Node enabled="enabled" fileURL="data/out.csv" guiHeight="77" guiName="CSV Writer" guiWidth="128" guiX="1518" guiY="116" id="DATA_WRITER0" outputFieldNames="true" quoteCharacter="&quot;" quotedStrings="true" type="DATA_WRITER"/>
40
+ <Node enabled="enabled" guiHeight="77" guiName="ExtSort" guiWidth="128" guiX="417" guiY="116" id="EXT_SORT0" sortKey="Id(a);Snapshot(a)" type="EXT_SORT"/>
41
+ <Node enabled="enabled" guiHeight="89" guiName="ExtSort" guiWidth="128" guiX="787" guiY="113" id="EXT_SORT1" sortKey="OpportunityId(a);ForecastCategoryName(a);AccountId(a);OwnerId(a);StageName(a);CreatedDate(a);CloseDate(a);ProductId(a)" type="EXT_SORT"/>
42
+ <Node enabled="passThrough" guiHeight="77" guiName="ExtSort" guiWidth="128" guiX="1341" guiY="116" id="EXT_SORT3" sortKey="Id(a);Stage(a)" type="EXT_SORT"/>
43
+ <Node enabled="passThrough" guiHeight="65" guiName="Reformat" guiWidth="128" guiX="248" guiY="122" id="REFORMAT0" type="REFORMAT">
24
44
  <attr name="transform"><![CDATA[//#CTL2
25
45
 
26
- //string date_template = "joda:yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
27
- string date_template = "joda:yyyy-MM-dd";
28
-
29
- // Called for the first data record in a new group. Starts the parsing of the new group.
30
- function void initGroup(recordName2 groupAccumulator) {
31
- groupAccumulator.Id = $0.Id;
32
- groupAccumulator.size = 0;
46
+ // Transforms input record into output record.
47
+ function integer transform() {
48
+ $out.0.* = $in.0.*;
49
+ $out.0.Stage = $in.0.StageName;
50
+ $out.0.Date = date2long(str2date($in.0.Snapshot, 'yyyy-MM-dd'));
51
+ return ALL;
33
52
  }
34
53
 
35
- // Called for each data record in the group (including the first one and the last one).
36
- // Implicitly returns false => updateTransform() is not called. When returns true, calls updateTransform().
37
- function boolean updateGroup(recordName2 groupAccumulator) {
38
- append(groupAccumulator.dates, $0.Snapshot);
39
- append(groupAccumulator.stages, $0.StageName);
40
- groupAccumulator.size++;
41
- return false;
42
- }
54
+ // Called during component initialization.
55
+ // function boolean init() {}
43
56
 
44
- // Called for the last data records in all groups sequentially, but only after all incoming data records have been parsed.
45
- // Implicitly returns true => transform() is called for the whole group.
46
- function boolean finishGroup(recordName2 groupAccumulator) {
47
- return true;
48
- }
57
+ // Called during each graph run before the transform is executed. May be used to allocate and initialize resources
58
+ // required by the transform. All resources allocated within this method should be released
59
+ // by the postExecute() method.
60
+ // function void preExecute() {}
49
61
 
50
- // Called to transform data records that have been parsed so far into user-specified number of output data record(s).
51
- // Counter (incremented by 1 starting from 0) stores the number of previous calls to this method for the current group update.
52
- // Group accumulator can optionally be used.
53
- // Function implicitly returns SKIP to skip sending any data records to output.
54
- // Returning ALL causes each data record to be sent to all output port(s).
55
- // Can also return a number of the output port to which individual data record should be sent.
56
- function integer updateTransform(integer counter, VoidMetadata groupAccumulator) {
57
- raiseError("Function not implemented!");
58
- }
62
+ // Called only if transform() throws an exception.
63
+ // function integer transformOnError(string errorMessage, string stackTrace) {}
64
+
65
+ // Called during each graph run after the entire transform was executed. Should be used to free any resources
66
+ // allocated within the preExecute() method.
67
+ // function void postExecute() {}
68
+
69
+ // Called to return a user-defined error message when an error occurs.
70
+ // function string getMessage() {}
71
+ ]]></attr>
72
+ </Node>
73
+ <Node enabled="enabled" guiHeight="65" guiName="Reformat" guiWidth="128" guiX="610" guiY="122" id="REFORMAT1" type="REFORMAT">
74
+ <attr name="transform"><![CDATA[//#CTL2
75
+
76
+ // Transforms input record into output record.
77
+ //InItem inItem = null;
78
+ //OutItem outItem;
79
+
80
+ out_1 previous;
81
+ boolean init = true;
59
82
 
60
- // Called to transform the whole group of incoming data record(s) into user-specified number of output data record(s).
61
- // Counter (incremented by 1 starting from 0) stores the number of previous calls to this method for the current group update.
62
- // Group accumulator can optionally be used.
63
- // Function implicitly returns SKIP to skip sending any data records to output.
64
- // Returning ALL causes each data record to be sent to all output port(s).
65
- // Can also return a number of the output port to which individual data record should be sent.
66
- function integer transform(integer counter, recordName2 groupAccumulator) {
83
+ function integer transform() {
67
84
 
68
- if (counter >= length(groupAccumulator.dates)) {
69
- return SKIP;
85
+ if (init) {
86
+ init = false;
87
+ previous.Velocity = 0;
88
+ previous.Duration = 0;
89
+ }
90
+
91
+ if (previous.Id == $in.0.Id) {
92
+ previous.Duration = (date2long(str2date($in.0.Snapshot, 'yyyy-MM-dd')) - date2long(str2date(previous.Snapshot, 'yyyy-MM-dd'))) / 3600 / 24 / 1000;
93
+
94
+
95
+ previous.Velocity = previous.Velocity + ((date2long(str2date($in.0.Snapshot, 'yyyy-MM-dd')) - date2long(str2date(previous.Snapshot, 'yyyy-MM-dd')))/ 3600 / 24 / 1000);
96
+ copyByName(previous.*,$in.0.*);
97
+ } else {
98
+ copyByName(previous.*,$in.0.*);
99
+ previous.Duration = 0;
70
100
  }
71
101
 
72
- string stage = groupAccumulator.stages[counter];
73
- date date0 = str2date(groupAccumulator.dates[0], date_template);
74
- date date1 = str2date(groupAccumulator.dates[counter], date_template);
75
- string velocity;
76
- string duration;
77
- date date2;
78
-
79
- if(counter == (length(groupAccumulator.dates) - 1)) {
80
- velocity = num2str(dateDiff(date1, date0, day));
81
- duration = "0";
82
- } else {
83
- date2 = str2date(groupAccumulator.dates[counter + 1], date_template);
84
- duration = num2str(dateDiff(date2, date1, day));
85
- velocity = num2str(dateDiff(date1, date0, day));
86
- }
87
-
88
-
89
- //printErr([groupAccumulator.Id, stage, duration, velocity]);
90
- $out.0.* = $in.0.*;
91
- $out.0.Id = groupAccumulator.Id;
92
- $out.0.StageName = stage;
93
- $out.0.Duration = duration;
94
- $out.0.Velocity = velocity;
95
-
96
- return ALL;
102
+ printErr(previous);
97
103
 
104
+ copyByName($out.0.*, previous.*);
105
+ return ALL;
98
106
  }
99
107
 
100
108
  // Called during component initialization.
101
- // function void init() {}
109
+ // function boolean init() {}
102
110
 
103
111
  // Called during each graph run before the transform is executed. May be used to allocate and initialize resources
104
112
  // required by the transform. All resources allocated within this method should be released
105
113
  // by the postExecute() method.
106
114
  // function void preExecute() {}
107
115
 
108
- // Called only if initGroup(DataRecord) throws an exception.
109
- //function void initGroupOnError(string errorMessage, string stackTrace, VoidMetadata groupAccumulator) {
110
- //}
116
+ // Called only if transform() throws an exception.
117
+ // function integer transformOnError(string errorMessage, string stackTrace) {}
118
+
119
+ // Called during each graph run after the entire transform was executed. Should be used to free any resources
120
+ // allocated within the preExecute() method.
121
+ // function void postExecute() {}
122
+
123
+ // Called to return a user-defined error message when an error occurs.
124
+ // function string getMessage() {}
125
+ ]]></attr>
126
+ </Node>
127
+ <Node enabled="passThrough" guiHeight="65" guiName="Reformat" guiWidth="128" guiX="1137" guiY="122" id="REFORMAT2" type="REFORMAT">
128
+ <attr name="transform"><![CDATA[//#CTL2
129
+
130
+ // Transforms input record into output record.
111
131
 
112
- // Called only if updateGroup(DataRecord) throws an exception.
113
- //function boolean updateGroupOnError(string errorMessage, string stackTrace, VoidMetadata groupAccumulator) {
114
- //}
132
+ // Transforms input record into output record.
133
+ function integer transform() {
134
+ $out.0.* = $in.0.*;
135
+ $out.0.Date = date2str(long2date($in.0.Date), 'yyyy-MM-dd');
136
+ $out.0.Velocity = toString($in.0.Velocity);
137
+ $out.0.Duration = toString($in.0.Duration);
138
+ return ALL;
139
+ }
115
140
 
116
- // Called only if finishGroup(DataRecord) throws an exception.
117
- //function boolean finishGroupOnError(string errorMessage, string stackTrace, VoidMetadata groupAccumulator) {
118
- //}
141
+ // Called during component initialization.
142
+ // function boolean init() {}
119
143
 
120
- // Called only if updateTransform(integer, DataRecord) throws an exception.
121
- //function integer updateTransformOnError(string errorMessage, string stackTrace, integer counter, VoidMetadata groupAccumulator) {
122
- //}
144
+ // Called during each graph run before the transform is executed. May be used to allocate and initialize resources
145
+ // required by the transform. All resources allocated within this method should be released
146
+ // by the postExecute() method.
147
+ // function void preExecute() {}
123
148
 
124
- // Called only if transform(integer, DataRecord) throws an exception.
125
- //function integer transformOnError(string errorMessage, string stackTrace, integer counter, VoidMetadata groupAccumulator) {
126
- //}
149
+ // Called only if transform() throws an exception.
150
+ // function integer transformOnError(string errorMessage, string stackTrace) {}
127
151
 
128
152
  // Called during each graph run after the entire transform was executed. Should be used to free any resources
129
153
  // allocated within the preExecute() method.
@@ -133,8 +157,15 @@ function integer transform(integer counter, recordName2 groupAccumulator) {
133
157
  // function string getMessage() {}
134
158
  ]]></attr>
135
159
  </Node>
136
- <Edge fromNode="DATA_READER0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge0" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (output)" toNode="EXT_SORT0:0"/>
137
- <Edge fromNode="EXT_SORT0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge2" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (out)" toNode="ROLLUP0:0"/>
138
- <Edge fromNode="ROLLUP0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge1" inPort="Port 0 (in)" metadata="Metadata2" outPort="Port 0 (out)" toNode="DATA_WRITER0:0"/>
160
+ <Node enabled="enabled" guiHeight="65" guiName="SimpleCopy" guiWidth="128" guiX="47" guiY="122" id="SIMPLE_COPY0" type="SIMPLE_COPY"/>
161
+ <Edge fromNode="AGGREGATE0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge6" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="REFORMAT2:0"/>
162
+ <Edge fromNode="DATA_READER0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge0" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (output)" toNode="SIMPLE_COPY0:0"/>
163
+ <Edge fromNode="EXT_SORT0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge4" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (out)" toNode="REFORMAT1:0"/>
164
+ <Edge debugMode="true" fromNode="EXT_SORT1:0" guiBendpoints="" guiRouter="Manhattan" id="Edge5" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="AGGREGATE0:0"/>
165
+ <Edge fromNode="EXT_SORT3:0" guiBendpoints="" guiRouter="Manhattan" id="Edge13" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="DATA_WRITER0:0"/>
166
+ <Edge fromNode="REFORMAT0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge1" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (out)" toNode="EXT_SORT0:0"/>
167
+ <Edge fromNode="REFORMAT1:0" guiBendpoints="" guiRouter="Manhattan" id="Edge3" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="EXT_SORT1:0"/>
168
+ <Edge fromNode="REFORMAT2:0" guiBendpoints="" guiRouter="Manhattan" id="Edge11" inPort="Port 0 (in)" metadata="Metadata1" outPort="Port 0 (out)" toNode="EXT_SORT3:0"/>
169
+ <Edge fromNode="SIMPLE_COPY0:0" guiBendpoints="" guiRouter="Manhattan" id="Edge7" inPort="Port 0 (in)" metadata="Metadata0" outPort="Port 0 (out)" toNode="REFORMAT0:0"/>
139
170
  </Phase>
140
171
  </Graph>
data/lib/utils/utils.rb CHANGED
@@ -47,7 +47,7 @@ module GoodData
47
47
  FileUtils::mkdir_p dir
48
48
  end
49
49
  File.open(home + 'params.prm', 'w') do |f|
50
- f << "TRASH=0"
50
+ f << "TRASH=0\n"
51
51
  end
52
52
  Utils::render_template("project.erb", options, :to_file => home + '.project')
53
53
  Utils::render_template("workspace.prm.erb", options, :to_file => home + 'workspace.prm')