mortar 0.15.20 → 0.15.21

Sign up to get free protection for your applications and to get access to all the features.
@@ -461,19 +461,25 @@ protected
461
461
  end
462
462
 
463
463
  def load_defaults(section_name)
464
- if File.exists?('.mortar-defaults')
465
- default_options = ParseConfig.new('.mortar-defaults')
466
- if default_options.groups.include?(section_name)
467
- default_options[section_name].each do |k, v|
468
- unless @original_options.include? k.to_sym
469
- if v == 'true'
470
- v = true
471
- elsif v == 'false'
472
- v = false
473
- end
474
-
475
- @options[k.to_sym] = v
464
+ if File.exists?('project.properties')
465
+ load_defaults_from_file('project.properties', section_name)
466
+ elsif File.exists?('.mortar-defaults')
467
+ load_defaults_from_file('.mortar-defaults', section_name)
468
+ end
469
+ end
470
+
471
+ def load_defaults_from_file(file_name, section_name)
472
+ default_options = ParseConfig.new(file_name)
473
+ if default_options.groups.include?(section_name)
474
+ default_options[section_name].each do |k, v|
475
+ unless @original_options.include? k.to_sym
476
+ if v == 'true'
477
+ v = true
478
+ elsif v == 'false'
479
+ v = false
476
480
  end
481
+
482
+ @options[k.to_sym] = v
477
483
  end
478
484
  end
479
485
  end
@@ -249,7 +249,14 @@ class Mortar::Command::Local < Mortar::Command::Base
249
249
  error("No such directory #{project_root}")
250
250
  end
251
251
  Dir.chdir(project_root)
252
+
252
253
  script = validate_luigiscript!(script_name)
254
+
255
+ #Set git ref as environment variable for mortar-luigi to use when
256
+ #running a MortarTask
257
+ git_ref = sync_code_with_cloud()
258
+ ENV['MORTAR_LUIGI_GIT_REF'] = git_ref
259
+
253
260
  ctrl = Mortar::Local::Controller.new
254
261
  luigi_params = pig_parameters.sort_by { |p| p['name'] }
255
262
  luigi_params = luigi_params.map { |arg| ["--#{arg['name']}", "#{arg['value']}"] }.flatten
@@ -37,6 +37,13 @@ class Mortar::Command::Projects < Mortar::Command::Base
37
37
  display("You have no projects.")
38
38
  end
39
39
  end
40
+
41
+ # projects:list
42
+ #
43
+ # Display the available set of Mortar projects.
44
+ def list
45
+ index
46
+ end
40
47
 
41
48
  # projects:delete PROJECTNAME
42
49
  #
@@ -32,8 +32,11 @@ module Mortar
32
32
  @dest_path = File.join(@dest_path, project_name)
33
33
 
34
34
  copy_file "README.md", "README.md"
35
+ copy_file "project.properties", "project.properties"
36
+ copy_file "project.manifest", "project.manifest"
37
+ copy_file "requirements.txt", "requirements.txt"
35
38
  copy_file "gitignore", ".gitignore"
36
-
39
+
37
40
  mkdir "pigscripts"
38
41
 
39
42
  inside "pigscripts" do
@@ -65,9 +68,20 @@ module Mortar
65
68
  end
66
69
  end
67
70
 
71
+ mkdir "luigiscripts"
72
+
73
+ inside "luigiscripts" do
74
+ copy_file "README", "README"
75
+ end
76
+
68
77
  mkdir "lib"
69
78
  inside "lib" do
70
- copy_file "gitkeep", ".gitkeep"
79
+ copy_file "README", "README"
80
+ end
81
+
82
+ mkdir "params"
83
+ inside "params" do
84
+ copy_file "README", "README"
71
85
  end
72
86
 
73
87
  rescue => e
data/lib/mortar/git.rb CHANGED
@@ -102,7 +102,8 @@ module Mortar
102
102
  # Copy code into a temp directory so we don't confuse editors while snapshotting
103
103
  curdir = Dir.pwd
104
104
  tmpdir = Dir.mktmpdir
105
- FileUtils.cp_r(pathlist, tmpdir)
105
+
106
+ copy_files_to_dir(pathlist, tmpdir)
106
107
  Dir.chdir(tmpdir)
107
108
 
108
109
  if block
@@ -114,6 +115,23 @@ module Mortar
114
115
  end
115
116
  end
116
117
 
118
+ def copy_files_to_dir(pathlist, dest_dir)
119
+ #Used to copy the pathlist from the manifest to a separate directory
120
+ #before syncing.
121
+ pathlist.each do |path|
122
+ dir, file = File.split(path)
123
+
124
+ #For non-root files/directories we need to create the parent
125
+ #directories before copying.
126
+ unless dir == "."
127
+ FileUtils.mkdir_p(File.join(dest_dir, dir))
128
+ end
129
+
130
+ FileUtils.cp_r(path, File.join(dest_dir, dir))
131
+ end
132
+
133
+ end
134
+
117
135
  #
118
136
  # Only snapshot filesystem paths that are in a whitelist
119
137
  #
@@ -121,37 +139,56 @@ module Mortar
121
139
  def mortar_manifest_pathlist(include_dot_git = true)
122
140
  ensure_valid_mortar_project_manifest()
123
141
 
124
- manifest_pathlist = File.read(".mortar-project-manifest").split("\n")
142
+ manifest_pathlist = File.read(project_manifest_name).split("\n")
125
143
  if include_dot_git
126
144
  manifest_pathlist << ".git"
127
145
  end
128
146
 
147
+ #Strip out comments and empty lines
148
+ manifest_pathlist = manifest_pathlist.select do |path|
149
+ s_path = path.strip
150
+ !s_path.start_with?("#") && !s_path.empty?
151
+ end
152
+
129
153
  manifest_pathlist.each do |path|
130
154
  unless File.exists? path
131
- Helpers.error(".mortar-project-manifest includes file/dir \"#{path}\" that is not in the mortar project directory.")
155
+ Helpers.error("#{project_manifest_name} includes file/dir \"#{path}\" that is not in the mortar project directory.")
132
156
  end
133
157
  end
134
158
 
135
159
  manifest_pathlist
136
160
  end
137
161
 
162
+ def add_newline_to_file(path)
163
+ File.open(path, "r+") do |manifest|
164
+ contents = manifest.read()
165
+ manifest.seek(0, IO::SEEK_END)
166
+
167
+ # `contents` in ruby 1.8.7 is array with entries of the
168
+ # type Fixnum which isn't semantically comparable with
169
+ # the \n char, but the ascii code 10 is
170
+ unless (contents[-1] == "\n" or contents[-1] == 10)
171
+ manifest.puts "" # ensure file ends with a newline
172
+ end
173
+ end
174
+ end
175
+
176
+ def project_manifest_name()
177
+ if File.exists? "project.manifest"
178
+ "project.manifest"
179
+ elsif File.exists? ".mortar-project-manifest"
180
+ ".mortar-project-manifest"
181
+ else
182
+ "project.manifest"
183
+ end
184
+ end
185
+
138
186
  #
139
187
  # Create a snapshot whitelist file if it doesn't already exist
140
188
  #
141
189
  def ensure_valid_mortar_project_manifest()
142
- if File.exists? ".mortar-project-manifest"
143
- File.open(".mortar-project-manifest", "r+") do |manifest|
144
- contents = manifest.read()
145
- manifest.seek(0, IO::SEEK_END)
146
-
147
- # `contents` in ruby 1.8.7 is array with entries of the
148
- # type Fixnum which isn't semantically comparable with
149
- # the \n char, but the ascii code 10 is
150
- unless (contents[-1] == "\n" or contents[-1] == 10)
151
- manifest.puts "" # ensure file ends with a newline
152
- end
153
-
154
- end
190
+ if File.exists? project_manifest_name
191
+ add_newline_to_file(project_manifest_name)
155
192
  else
156
193
  create_mortar_project_manifest('.')
157
194
  end
@@ -161,10 +198,11 @@ module Mortar
161
198
  # Create a project manifest file
162
199
  #
163
200
  def create_mortar_project_manifest(path)
164
- File.open("#{path}/.mortar-project-manifest", 'w') do |manifest|
165
- manifest.puts "pigscripts"
201
+ File.open("#{path}/#{project_manifest_name}", 'w') do |manifest|
166
202
  manifest.puts "macros"
203
+ manifest.puts "pigscripts"
167
204
  manifest.puts "udfs"
205
+
168
206
  if File.directory? "#{path}/lib"
169
207
  manifest.puts "lib"
170
208
  end
@@ -240,7 +278,6 @@ module Mortar
240
278
  # the project is not a git repo, so we manage a mirror directory that is a git repo
241
279
  # branch is which branch to sync to. this will be master if the cloud repo
242
280
  # is being initialized, or a branch based on the user's name in any other circumstance
243
-
244
281
  project_dir = project.root_path
245
282
  mirror_dir = "#{mortar_mirrors_dir}/#{project.name}"
246
283
 
@@ -260,6 +297,7 @@ module Mortar
260
297
  end
261
298
 
262
299
  # clone mortar-code repo
300
+ ensure_valid_mortar_project_manifest()
263
301
  remote_path = File.open(".mortar-project-remote").read.strip
264
302
  clone(remote_path, mirror_dir)
265
303
 
@@ -322,7 +360,7 @@ module Mortar
322
360
  # mortar_manifest_pathlist(false) means don't copy .git
323
361
  FileUtils.rm_rf(Dir.glob("#{mirror_dir}/*"))
324
362
  Dir.chdir(project_dir)
325
- FileUtils.cp_r(mortar_manifest_pathlist(false), mirror_dir)
363
+ copy_files_to_dir(mortar_manifest_pathlist(false), mirror_dir)
326
364
 
327
365
  # update remote branch
328
366
  Dir.chdir(mirror_dir)
@@ -151,9 +151,32 @@ EOF
151
151
  sqoop.install_or_update()
152
152
  end
153
153
 
154
+ write_local_readme
155
+
154
156
  ensure_local_install_dirs_in_gitignore
155
157
  end
156
158
 
159
+ def write_local_readme()
160
+ readme_path = File.join(local_install_directory, "README")
161
+ unless File.exists? readme_path
162
+ file = File.new(readme_path, "w")
163
+ file.write(<<-README
164
+ This directory is used by Mortar to install all of the necessary dependencies for
165
+ running mortar local commands. You should not modify these files/directories as
166
+ they may be removed or updated at any time.
167
+
168
+ For additional Java dependencies you should place your jars in the root lib folder
169
+ of your project. These jars will be automatically registered and
170
+ available for use in your Pig scripts and UDFs.
171
+
172
+ You can specify additional Python dependencies in the requirements.txt file in
173
+ the root of your project.
174
+ README
175
+ )
176
+ file.close
177
+ end
178
+ end
179
+
157
180
  def ensure_local_install_dirs_in_gitignore()
158
181
  if File.exists? local_project_gitignore
159
182
  File.open(local_project_gitignore, 'r+') do |gitignore|
@@ -410,6 +410,14 @@ class Mortar::Local::Pig
410
410
  params['MORTAR_EMAIL_S3_ESCAPED'] = Mortar::Auth.user_s3_safe(true)
411
411
  end
412
412
 
413
+ if ENV['MORTAR_PROJECT_ROOT']
414
+ params['MORTAR_PROJECT_ROOT'] = ENV['MORTAR_PROJECT_ROOT']
415
+ else
416
+ params['MORTAR_PROJECT_ROOT'] = project_root
417
+ ENV['MORTAR_PROJECT_ROOT'] = params['MORTAR_PROJECT_ROOT']
418
+ end
419
+
420
+
413
421
  # Coerce into the same format as pig parameters that were
414
422
  # passed in via the command line or a parameter file
415
423
  param_list = []
@@ -0,0 +1 @@
1
+ To make it easy to bundle dependencies, you can include any needed jars in the lib folder of your project. Any jars in this folder will be automatically registered and available for use in your Pig scripts and UDFs.
@@ -0,0 +1 @@
1
+ The luigiscripts directory is where your luigi scripts should be stored. For more information about using Luigi with Mortar see: http://help.mortardata.com/technologies/luigi.
@@ -0,0 +1 @@
1
+ The params directory is a place to store various param files for your project. For more information about how you can use parameters with Mortar see http://help.mortardata.com/technologies/mortar/local_development.
@@ -0,0 +1,12 @@
1
+ # This file lists which files and directories the Mortar Development Framework
2
+ # should sync with the cloud. By default, it includes only the standard Mortar
3
+ # directories. If you have extra resources that your code depends on, you can
4
+ # add them to this file.
5
+ #
6
+ # See http://help.mortardata.com/technologies/mortar/how_mortar_projects_work
7
+ # for more information.
8
+
9
+ lib
10
+ macros
11
+ pigscripts
12
+ udfs
@@ -0,0 +1,11 @@
1
+ # This file allows you to set project level properties.
2
+
3
+
4
+ # The defaults section can be used to set the default value used for any
5
+ # Mortar parameter. For more details see:
6
+ #
7
+ # http://help.mortardata.com/data_apps/build_your_own/running_a_mortar_project#toc_7SettingProjectDefaults
8
+
9
+ [DEFAULTS]
10
+ # Default new projects to using Pig 0.12
11
+ pigversion=0.12
@@ -0,0 +1,17 @@
1
+ # Mortar comes with the Python standard libraries, NumPy, SciPy, and NLTK
2
+ # pre-installed. You can install additional Python packages by listing them out
3
+ # here in pip requirements (https://pip.pypa.io/en/latest/reference/pip_install.html#requirements-file-format) format.
4
+ #
5
+ # Examples:
6
+ #
7
+ # Version 2.1 of python-dateutil
8
+ # python-dateutil==2.1
9
+ #
10
+ # Version 2.1 or higher of python-dateutil
11
+ # python-dateutil>=2.1
12
+ #
13
+ # Latest version of python-dateutil
14
+ # python-dateutil
15
+ #
16
+ # Your private library stored in S3
17
+ # s3://my-bucket/my-custom-lib.tar.gz
@@ -11,4 +11,4 @@ export LUIGI_CONFIG_PATH=`pwd`/`dirname <%= @python_script %>`/client.cfg
11
11
  <%= @local_install_dir %>/pythonenv/bin/python \
12
12
  <%= @python_arugments %> \
13
13
  <%= @python_script %> \
14
- <%= @script_arguments %>
14
+ <%= @script_arguments %>
@@ -16,5 +16,5 @@
16
16
 
17
17
  module Mortar
18
18
  # see http://semver.org/
19
- VERSION = "0.15.20"
19
+ VERSION = "0.15.21"
20
20
  end
@@ -213,7 +213,7 @@ no_browser=true
213
213
  end
214
214
  end
215
215
 
216
- it "obeys proper overrides" do
216
+ it "obeys proper overrides - deprecated file" do
217
217
  stub_core
218
218
  git = Mortar::Git::Git.new
219
219
 
@@ -241,6 +241,31 @@ polling_interval=10
241
241
  end
242
242
  end
243
243
 
244
+ it "obeys proper overrides" do
245
+ stub_core
246
+ git = Mortar::Git::Git.new
247
+
248
+ with_git_initialized_project do |p|
249
+ text = """
250
+ [DEFAULTS]
251
+ clustersize=5
252
+ no_browser=true
253
+ pigversion=0.12
254
+ """
255
+ write_file(File.join(p.root_path, "project.properties"), text)
256
+
257
+ describe_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
258
+ describe_url = "https://api.mortardata.com/describe/#{describe_id}"
259
+
260
+ mock(Mortar::Auth.api).post_describe("myproject", "my_script", "my_alias", is_a(String), :pig_version => "0.12", :project_script_path => be_a_kind_of(String), :parameters=>[]) {Excon::Response.new(:body => {"describe_id" => describe_id})}
261
+ mock(Mortar::Auth.api).get_describe(describe_id, :exclude_result => true).returns(Excon::Response.new(:body => {"status_code" => Mortar::API::Describe::STATUS_SUCCESS, "status_description" => "Success", "web_result_url" => describe_url})).ordered
262
+ write_file(File.join(p.pigscripts_path, "my_script.pig"))
263
+
264
+ stderr, stdout, d = execute_and_return_command("describe pigscripts/my_script.pig my_alias --polling_interval 0.05", p, git)
265
+ d.options.should == {:polling_interval => "0.05", :no_browser => true, :clustersize => "5", :pigversion => "0.12"}
266
+ end
267
+ end
268
+
244
269
  end
245
270
 
246
271
  end
@@ -210,6 +210,7 @@ PARAMS
210
210
  mock(j).install_or_update.returns(true)
211
211
  end
212
212
  any_instance_of(Mortar::Local::Controller) do |j|
213
+ mock(j).write_local_readme
213
214
  mock(j).ensure_local_install_dirs_in_gitignore.returns(true)
214
215
  end
215
216
  stderr, stdout = execute("local:configure")
@@ -301,8 +302,13 @@ STDERR
301
302
  any_instance_of(Mortar::Local::Controller) do |u|
302
303
  mock(u).install_and_configure(is_a(Mortar::PigVersion::Pig09),'luigi')
303
304
  end
305
+ any_instance_of(Mortar::Command::Local) do |u|
306
+ mock(u).sync_code_with_cloud().returns("some-git-ref")
307
+ end
308
+ ENV['MORTAR_LUIGI_GIT_REF'].should be_nil
304
309
  stderr, stdout = execute("local:luigi some_luigi_script -p myoption=2 -p myotheroption=3", p)
305
310
  stderr.should == ""
311
+ ENV['MORTAR_LUIGI_GIT_REF'].should == 'some-git-ref'
306
312
  end
307
313
  end
308
314
 
@@ -115,11 +115,17 @@ STDOUT
115
115
  File.exists?("macros").should be_true
116
116
  File.exists?("pigscripts").should be_true
117
117
  File.exists?("udfs").should be_true
118
+ File.exists?("project.properties").should be_true
119
+ File.exists?("project.manifest").should be_true
120
+ File.exists?("requirements.txt").should be_true
118
121
  File.exists?("README.md").should be_true
119
122
  File.exists?("Gemfile").should be_false
120
123
  File.exists?("macros/.gitkeep").should be_true
121
124
  File.exists?("pigscripts/some_new_project.pig").should be_true
122
125
  File.exists?("udfs/python/some_new_project.py").should be_true
126
+ File.exists?("luigiscripts/README").should be_true
127
+ File.exists?("lib/README").should be_true
128
+ File.exists?("params/README").should be_true
123
129
 
124
130
  File.read("pigscripts/some_new_project.pig").each_line { |line| line.match(/<%.*%>/).should be_nil }
125
131
 
@@ -127,6 +133,9 @@ STDOUT
127
133
  Sending request to register project: some_new_project... done
128
134
  \e[1;32m create\e[0m
129
135
  \e[1;32m create\e[0m README.md
136
+ \e[1;32m create\e[0m project.properties
137
+ \e[1;32m create\e[0m project.manifest
138
+ \e[1;32m create\e[0m requirements.txt
130
139
  \e[1;32m create\e[0m .gitignore
131
140
  \e[1;32m create\e[0m pigscripts
132
141
  \e[1;32m create\e[0m pigscripts/some_new_project.pig
@@ -139,8 +148,12 @@ Sending request to register project: some_new_project... done
139
148
  \e[1;32m create\e[0m udfs/jython/.gitkeep
140
149
  \e[1;32m create\e[0m udfs/java
141
150
  \e[1;32m create\e[0m udfs/java/.gitkeep
151
+ \e[1;32m create\e[0m luigiscripts
152
+ \e[1;32m create\e[0m luigiscripts/README
142
153
  \e[1;32m create\e[0m lib
143
- \e[1;32m create\e[0m lib/.gitkeep
154
+ \e[1;32m create\e[0m lib/README
155
+ \e[1;32m create\e[0m params
156
+ \e[1;32m create\e[0m params/README
144
157
  \n\r\e[0KStatus: ACTIVE \n\nYour project is ready for use. Type 'mortar help' to see the commands you can perform on the project.\n
145
158
  NOTE: You'll need to change to the new directory to use your project:
146
159
  cd some_new_project
@@ -454,6 +454,46 @@ STASH
454
454
  end
455
455
  end
456
456
 
457
+ context "safe_copy for_snapshot" do
458
+ it "safe copies properly" do
459
+ tmp_dir_src = Dir.mktmpdir
460
+ Dir.chdir(tmp_dir_src)
461
+
462
+ root_file = File.join("root_file")
463
+ root_dir_file = File.join("root_dir", "root_dir_file")
464
+ non_root_dir_file = File.join("dir", "non_root_dir", "non_root_dir_file")
465
+ dir_file = File.join("dir", "dir_file")
466
+
467
+ ex_root_file = File.join("excluded_root_file")
468
+ ex_root_dir_file = File.join("excluded_dir", "excluded_dir_file")
469
+ ex_dir_file = File.join("dir", "excluded_dir_file")
470
+ ex_non_root_dir_file = File.join("dir", "excluded_non_root_dir", "excluded_non_root_dir_file")
471
+
472
+ write_file(root_file)
473
+ write_file(root_dir_file)
474
+ write_file(non_root_dir_file)
475
+ write_file(dir_file)
476
+ write_file(ex_root_file)
477
+ write_file(ex_root_dir_file)
478
+ write_file(ex_dir_file)
479
+ write_file(ex_non_root_dir_file)
480
+
481
+ pathlist = ["root_file", "root_dir", "dir/non_root_dir", "dir/dir_file"]
482
+ new_tmp_dir = @git.safe_copy(pathlist)
483
+
484
+ Dir.chdir(new_tmp_dir)
485
+ File.exists?(root_file).should be_true
486
+ File.exists?(root_dir_file).should be_true
487
+ File.exists?(non_root_dir_file).should be_true
488
+ File.exists?(dir_file).should be_true
489
+
490
+ File.exists?(ex_root_file).should be_false
491
+ File.exists?(ex_root_dir_file).should be_false
492
+ File.exists?(ex_dir_file).should be_false
493
+ File.exists?(ex_non_root_dir_file).should be_false
494
+ end
495
+ end
496
+
457
497
 
458
498
  =begin
459
499
  #TODO: Fix this.
@@ -147,6 +147,7 @@ module Mortar::Local
147
147
  mock(j).install_or_update
148
148
  end
149
149
 
150
+ mock(ctrl).write_local_readme
150
151
  mock(ctrl).ensure_local_install_dirs_in_gitignore
151
152
  ctrl.install_and_configure
152
153
  end
@@ -173,6 +174,7 @@ module Mortar::Local
173
174
  mock(s).install_or_update
174
175
  end
175
176
 
177
+ mock(ctrl).write_local_readme
176
178
  mock(ctrl).ensure_local_install_dirs_in_gitignore
177
179
  ctrl.install_and_configure(Mortar::PigVersion::Pig012.new, command, true)
178
180
  end
data/spec/spec_helper.rb CHANGED
@@ -229,7 +229,7 @@ def with_git_initialized_project_with_remote_prefix(remote_prefix, name="myproje
229
229
  git.create_mortar_project_manifest(project.root_path)
230
230
 
231
231
  remote = "mortar"
232
- `git add .mortar-project-manifest`
232
+ `git add project.manifest`
233
233
  `git commit -a -m "First commit"`
234
234
  `git remote add #{remote} git@github.com:mortarcode-dev/#{remote_prefix}#{project.name}.git`
235
235
  project.remote = remote
@@ -366,6 +366,7 @@ def create_and_validate_git_snapshot(git)
366
366
  FileUtils.remove_entry_secure(snapshot_dir)
367
367
  end
368
368
 
369
+
369
370
  require "mortar/helpers"
370
371
  module Mortar::Helpers
371
372
  @home_directory = Dir.mktmpdir
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mortar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.20
4
+ version: 0.15.21
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-06-24 00:00:00.000000000 Z
12
+ date: 2014-07-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rdoc
@@ -303,9 +303,14 @@ files:
303
303
  - lib/mortar/templates/project/README.md
304
304
  - lib/mortar/templates/project/controlscripts/lib/__init__.py
305
305
  - lib/mortar/templates/project/gitignore
306
- - lib/mortar/templates/project/lib/gitkeep
306
+ - lib/mortar/templates/project/lib/README
307
+ - lib/mortar/templates/project/luigiscripts/README
307
308
  - lib/mortar/templates/project/macros/gitkeep
309
+ - lib/mortar/templates/project/params/README
308
310
  - lib/mortar/templates/project/pigscripts/pigscript.pig
311
+ - lib/mortar/templates/project/project.manifest
312
+ - lib/mortar/templates/project/project.properties
313
+ - lib/mortar/templates/project/requirements.txt
309
314
  - lib/mortar/templates/project/udfs/java/gitkeep
310
315
  - lib/mortar/templates/project/udfs/jython/gitkeep
311
316
  - lib/mortar/templates/project/udfs/python/python_udf.py
File without changes