gd_bam 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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')