albacore 1.0.0 → 2.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (258) hide show
  1. data/.gitignore +6 -21
  2. data/.travis.yml +31 -12
  3. data/Gemfile +14 -6
  4. data/Guardfile +1 -3
  5. data/README.md +200 -47
  6. data/Rakefile +9 -19
  7. data/albacore.gemspec +33 -23
  8. data/lib/albacore.rb +3 -47
  9. data/lib/albacore/albacore_module.rb +57 -0
  10. data/lib/albacore/application.rb +43 -0
  11. data/lib/albacore/cmd_config.rb +66 -0
  12. data/lib/albacore/config_dsl.rb +55 -0
  13. data/lib/albacore/cross_platform_cmd.rb +291 -0
  14. data/lib/albacore/dsl.rb +90 -0
  15. data/lib/albacore/errors/command_failed_error.rb +11 -0
  16. data/lib/albacore/errors/command_not_found_error.rb +13 -0
  17. data/lib/albacore/errors/unfilled_property_error.rb +14 -0
  18. data/lib/albacore/ext/README.md +12 -0
  19. data/lib/albacore/ext/teamcity.rb +64 -0
  20. data/lib/albacore/facts.rb +25 -0
  21. data/lib/albacore/logging.rb +32 -0
  22. data/lib/albacore/nuget_model.rb +387 -0
  23. data/lib/albacore/paths.rb +34 -0
  24. data/lib/albacore/project.rb +141 -0
  25. data/lib/albacore/semver.rb +5 -0
  26. data/lib/albacore/task_types/asmver.rb +72 -0
  27. data/lib/albacore/task_types/asmver/cpp.rb +20 -0
  28. data/lib/albacore/task_types/asmver/cs.rb +17 -0
  29. data/lib/albacore/task_types/asmver/engine.rb +126 -0
  30. data/lib/albacore/task_types/asmver/file_generator.rb +45 -0
  31. data/lib/albacore/task_types/asmver/fs.rb +37 -0
  32. data/lib/albacore/task_types/asmver/vb.rb +27 -0
  33. data/lib/albacore/task_types/build.rb +192 -0
  34. data/lib/albacore/task_types/nugets_authentication.rb +9 -0
  35. data/lib/albacore/task_types/nugets_pack.rb +378 -0
  36. data/lib/albacore/task_types/nugets_restore.rb +138 -0
  37. data/lib/albacore/task_types/test_runner.rb +39 -0
  38. data/lib/albacore/tasks/README.md +16 -0
  39. data/lib/albacore/tasks/albasemver.rb +49 -0
  40. data/lib/albacore/tasks/projectlint.rb +81 -0
  41. data/lib/albacore/tasks/versionizer.rb +65 -0
  42. data/lib/albacore/tools/fluent_migrator.rb +177 -0
  43. data/lib/albacore/tools/restore_hint_paths.rb +112 -0
  44. data/lib/albacore/version.rb +3 -3
  45. data/spec/Rakefile +5 -0
  46. data/spec/albacore_spec.rb +12 -0
  47. data/spec/asmver_spec.rb +151 -0
  48. data/spec/asmver_task_spec.rb +32 -0
  49. data/spec/build_spec.rb +60 -0
  50. data/spec/config_dsl_spec.rb +83 -0
  51. data/spec/cross_platform_cmd_spec.rb +65 -0
  52. data/spec/dsl_spec.rb +39 -0
  53. data/spec/ext_teamcity_spec.rb +71 -0
  54. data/spec/facts_spec.rb +7 -0
  55. data/spec/nuget_model_spec.rb +401 -0
  56. data/spec/nugets_pack_spec.rb +231 -0
  57. data/spec/nugets_restore_spec.rb +55 -0
  58. data/spec/project_spec.rb +26 -0
  59. data/spec/projectlint/added_but_not_on_filesystem/aproject.csproj +29 -0
  60. data/spec/projectlint/correct/File.cs +1 -0
  61. data/spec/projectlint/correct/Image.txt +1 -0
  62. data/spec/projectlint/correct/MyHeavy.heavy +1 -0
  63. data/spec/projectlint/correct/Schema.xsd +1 -0
  64. data/spec/projectlint/correct/SubFolder/AnotherFile.cs +1 -0
  65. data/spec/projectlint/correct/aproject.csproj +29 -0
  66. data/spec/projectlint/on_filesystem_but_not_added/File.cs +1 -0
  67. data/spec/projectlint/on_filesystem_but_not_added/Image.txt +1 -0
  68. data/spec/projectlint/on_filesystem_but_not_added/aproject.csproj +11 -0
  69. data/spec/projectlint_spec.rb +77 -0
  70. data/spec/smoke_spec.rb +55 -0
  71. data/spec/spec_helper.rb +19 -20
  72. data/spec/support/Nuget/NuGet.exe +0 -0
  73. data/spec/support/echo/FSharp.Core.dll +0 -0
  74. data/spec/support/echo/FSharp.Core.xml +10517 -0
  75. data/spec/support/echo/echo.XML +12 -0
  76. data/spec/support/echo/echo.exe +0 -0
  77. data/spec/support/echo/echo.exe.config +17 -0
  78. data/spec/support/echo/echo.pdb +0 -0
  79. data/spec/support/returnstatus/FSharp.Core.dll +0 -0
  80. data/spec/support/returnstatus/FSharp.Core.xml +10517 -0
  81. data/spec/support/returnstatus/returnstatus.XML +12 -0
  82. data/spec/support/returnstatus/returnstatus.exe +0 -0
  83. data/spec/support/returnstatus/returnstatus.exe.config +17 -0
  84. data/spec/support/returnstatus/returnstatus.pdb +0 -0
  85. data/spec/support/sh_interceptor.rb +83 -0
  86. data/spec/testdata/.gitignore +5 -0
  87. data/spec/testdata/DebugProject/.gitignore +1 -0
  88. data/spec/testdata/DebugProject/Degbu.fsproj +57 -0
  89. data/spec/testdata/DebugProject/Degbu.sln +20 -0
  90. data/spec/testdata/DebugProject/Gemfile +1 -0
  91. data/spec/testdata/DebugProject/Library1.fs +4 -0
  92. data/spec/testdata/DebugProject/Rakefile +22 -0
  93. data/spec/testdata/EmptyProject/EmptyProject.csproj +39 -0
  94. data/spec/{assemblyinfo → testdata/EmptyProject/Properties}/AssemblyInfo.cs +5 -5
  95. data/spec/testdata/Gemfile +1 -0
  96. data/spec/testdata/NuGet.exe +0 -0
  97. data/spec/testdata/Project/Library1.fs +4 -0
  98. data/spec/testdata/Project/Project.fsproj +52 -0
  99. data/spec/testdata/Project/Project.sln +20 -0
  100. data/spec/testdata/Project/packages.config +6 -0
  101. data/spec/testdata/Rakefile +22 -0
  102. data/spec/testdata/TestingDependencies/Sample.Commands/Library.fs +6 -0
  103. data/spec/testdata/TestingDependencies/Sample.Commands/Sample.Commands.fsproj +78 -0
  104. data/spec/testdata/TestingDependencies/Sample.Commands/Script.fsx +8 -0
  105. data/spec/testdata/TestingDependencies/Sample.Commands/packages.config +6 -0
  106. data/spec/testdata/TestingDependencies/Sample.Core/Library.fs +3 -0
  107. data/spec/testdata/TestingDependencies/Sample.Core/Sample.Core.fsproj +59 -0
  108. data/spec/testdata/TestingDependencies/Sample.Core/Script.fsx +8 -0
  109. data/spec/testdata/TestingDependencies/Sample.Core/packages.config +4 -0
  110. data/spec/testdata/TestingDependencies/Sample.sln +26 -0
  111. data/spec/testdata/TestingDependencies/vendor/FSharp.Core.dll +0 -0
  112. data/spec/testdata/TestingDependencies/vendor/FSharp.Core.optdata +0 -0
  113. data/spec/testdata/TestingDependencies/vendor/FSharp.Core.sigdata +0 -0
  114. data/spec/testdata/TestingDependencies/vendor/FSharp.Core.xml +8748 -0
  115. data/spec/testdata/example.nuspec +14 -0
  116. data/spec/testdata/example.symbols.nuspec +21 -0
  117. data/spec/tools/fluent_migrator_spec.rb +80 -0
  118. metadata +303 -212
  119. data/.bundle/config +0 -2
  120. data/.rspec +0 -2
  121. data/CONTRIBUTING.md +0 -87
  122. data/LICENSE +0 -21
  123. data/lib/albacore/albacoretask.rb +0 -50
  124. data/lib/albacore/aspnetcompiler.rb +0 -80
  125. data/lib/albacore/assemblyinfo.rb +0 -163
  126. data/lib/albacore/assemblyinfolanguages/assemblyinfoengine.rb +0 -54
  127. data/lib/albacore/assemblyinfolanguages/cppcliengine.rb +0 -18
  128. data/lib/albacore/assemblyinfolanguages/csharpengine.rb +0 -15
  129. data/lib/albacore/assemblyinfolanguages/fsharpengine.rb +0 -23
  130. data/lib/albacore/assemblyinfolanguages/vbnetengine.rb +0 -15
  131. data/lib/albacore/config/aspnetcompilerconfig.rb +0 -30
  132. data/lib/albacore/config/assemblyinfoconfig.rb +0 -18
  133. data/lib/albacore/config/config.rb +0 -22
  134. data/lib/albacore/config/cscconfig.rb +0 -28
  135. data/lib/albacore/config/docuconfig.rb +0 -19
  136. data/lib/albacore/config/execconfig.rb +0 -19
  137. data/lib/albacore/config/fluentmigratorconfig.rb +0 -19
  138. data/lib/albacore/config/ilmergeconfig.rb +0 -19
  139. data/lib/albacore/config/msbuildconfig.rb +0 -29
  140. data/lib/albacore/config/mspecconfig.rb +0 -19
  141. data/lib/albacore/config/mstestconfig.rb +0 -19
  142. data/lib/albacore/config/nantconfig.rb +0 -18
  143. data/lib/albacore/config/nchurnconfig.rb +0 -19
  144. data/lib/albacore/config/ncoverconsoleconfig.rb +0 -19
  145. data/lib/albacore/config/ncoverreportconfig.rb +0 -18
  146. data/lib/albacore/config/ndependconfig.rb +0 -19
  147. data/lib/albacore/config/netversion.rb +0 -28
  148. data/lib/albacore/config/nugetinstallconfig.rb +0 -18
  149. data/lib/albacore/config/nugetpackconfig.rb +0 -18
  150. data/lib/albacore/config/nugetpushconfig.rb +0 -18
  151. data/lib/albacore/config/nugetupdateconfig.rb +0 -18
  152. data/lib/albacore/config/nunitconfig.rb +0 -19
  153. data/lib/albacore/config/nuspecconfig.rb +0 -18
  154. data/lib/albacore/config/plinkconfig.rb +0 -18
  155. data/lib/albacore/config/specflowconfig.rb +0 -18
  156. data/lib/albacore/config/sqlcmdconfig.rb +0 -18
  157. data/lib/albacore/config/unzipconfig.rb +0 -19
  158. data/lib/albacore/config/xbuildconfig.rb +0 -18
  159. data/lib/albacore/config/xunitconfig.rb +0 -18
  160. data/lib/albacore/config/zipdirectoryconfig.rb +0 -18
  161. data/lib/albacore/csc.rb +0 -77
  162. data/lib/albacore/docu.rb +0 -38
  163. data/lib/albacore/exec.rb +0 -20
  164. data/lib/albacore/fluentmigrator.rb +0 -69
  165. data/lib/albacore/ilmerge.rb +0 -38
  166. data/lib/albacore/msbuild.rb +0 -55
  167. data/lib/albacore/mspec.rb +0 -39
  168. data/lib/albacore/mstest.rb +0 -47
  169. data/lib/albacore/nant.rb +0 -41
  170. data/lib/albacore/nchurn.rb +0 -49
  171. data/lib/albacore/ncoverconsole.rb +0 -56
  172. data/lib/albacore/ncoverreport.rb +0 -40
  173. data/lib/albacore/ncoverreports.rb +0 -16
  174. data/lib/albacore/ncoverreports/assemblyfilter.rb +0 -10
  175. data/lib/albacore/ncoverreports/branchcoverage.rb +0 -10
  176. data/lib/albacore/ncoverreports/classfilter.rb +0 -9
  177. data/lib/albacore/ncoverreports/codecoveragebase.rb +0 -27
  178. data/lib/albacore/ncoverreports/cyclomaticcomplexity.rb +0 -23
  179. data/lib/albacore/ncoverreports/documentfilter.rb +0 -9
  180. data/lib/albacore/ncoverreports/fullcoveragereport.rb +0 -9
  181. data/lib/albacore/ncoverreports/methodcoverage.rb +0 -10
  182. data/lib/albacore/ncoverreports/methodfilter.rb +0 -9
  183. data/lib/albacore/ncoverreports/namespacefilter.rb +0 -9
  184. data/lib/albacore/ncoverreports/reportbase.rb +0 -23
  185. data/lib/albacore/ncoverreports/reportfilterbase.rb +0 -29
  186. data/lib/albacore/ncoverreports/summaryreport.rb +0 -9
  187. data/lib/albacore/ncoverreports/symbolcoverage.rb +0 -9
  188. data/lib/albacore/ndepend.rb +0 -33
  189. data/lib/albacore/nugetinstall.rb +0 -62
  190. data/lib/albacore/nugetpack.rb +0 -50
  191. data/lib/albacore/nugetpush.rb +0 -40
  192. data/lib/albacore/nugetupdate.rb +0 -50
  193. data/lib/albacore/nunit.rb +0 -46
  194. data/lib/albacore/nuspec.rb +0 -180
  195. data/lib/albacore/output.rb +0 -105
  196. data/lib/albacore/plink.rb +0 -50
  197. data/lib/albacore/specflow.rb +0 -30
  198. data/lib/albacore/sqlcmd.rb +0 -67
  199. data/lib/albacore/support/attrmethods.rb +0 -33
  200. data/lib/albacore/support/createtask.rb +0 -50
  201. data/lib/albacore/support/failure.rb +0 -15
  202. data/lib/albacore/support/logging.rb +0 -38
  203. data/lib/albacore/support/openstruct.rb +0 -13
  204. data/lib/albacore/support/platform.rb +0 -25
  205. data/lib/albacore/support/runcommand.rb +0 -45
  206. data/lib/albacore/support/updateattributes.rb +0 -13
  207. data/lib/albacore/support/yamlconfig.rb +0 -18
  208. data/lib/albacore/unzip.rb +0 -42
  209. data/lib/albacore/xbuild.rb +0 -41
  210. data/lib/albacore/xunit.rb +0 -44
  211. data/lib/albacore/zipdirectory.rb +0 -106
  212. data/spec/albacoremodel_spec.rb +0 -52
  213. data/spec/aspnetcompiler_spec.rb +0 -84
  214. data/spec/assemblyinfo_spec.rb +0 -209
  215. data/spec/attrmethods_spec.rb +0 -135
  216. data/spec/config_spec.rb +0 -32
  217. data/spec/createtask_spec.rb +0 -234
  218. data/spec/csc_spec.rb +0 -86
  219. data/spec/docu_spec.rb +0 -31
  220. data/spec/exec_spec.rb +0 -25
  221. data/spec/fluentmigrator_spec.rb +0 -88
  222. data/spec/ilmerge_spec.rb +0 -35
  223. data/spec/msbuild_spec.rb +0 -55
  224. data/spec/mspec_spec.rb +0 -30
  225. data/spec/mstest_spec.rb +0 -35
  226. data/spec/nant_spec.rb +0 -40
  227. data/spec/nchurn_spec.rb +0 -80
  228. data/spec/ncoverconsole_spec.rb +0 -80
  229. data/spec/ncoverreport_spec.rb +0 -139
  230. data/spec/ndepend_spec.rb +0 -26
  231. data/spec/netversion_spec.rb +0 -51
  232. data/spec/nugetinstall_spec.rb +0 -59
  233. data/spec/nugetpack_spec.rb +0 -49
  234. data/spec/nugetpush_spec.rb +0 -39
  235. data/spec/nugetupdate_spec.rb +0 -49
  236. data/spec/nunit_spec.rb +0 -35
  237. data/spec/nuspec/nuspec.xsd +0 -84
  238. data/spec/nuspec_spec.rb +0 -74
  239. data/spec/output/bar/bar.txt +0 -0
  240. data/spec/output/baz.txt +0 -0
  241. data/spec/output/erb.txt +0 -1
  242. data/spec/output/foo/foo/foo.txt +0 -0
  243. data/spec/output_spec.rb +0 -85
  244. data/spec/patch/system_patch.rb +0 -12
  245. data/spec/platform_spec.rb +0 -15
  246. data/spec/plink_spec.rb +0 -56
  247. data/spec/runcommand_spec.rb +0 -92
  248. data/spec/specflow_spec.rb +0 -30
  249. data/spec/sqlcmd_spec.rb +0 -66
  250. data/spec/unzip_spec.rb +0 -56
  251. data/spec/xbuild_spec.rb +0 -40
  252. data/spec/xunit_spec.rb +0 -30
  253. data/spec/yaml/test.yml +0 -3
  254. data/spec/yamlconfig_spec.rb +0 -53
  255. data/spec/zip/baz.txt +0 -0
  256. data/spec/zip/foo/bar/bar.txt +0 -0
  257. data/spec/zip/foo/foo.txt +0 -0
  258. data/spec/zip_spec.rb +0 -97
@@ -1,47 +1,3 @@
1
- # infrastructure
2
- require "albacore/version"
3
- require "albacore/albacoretask"
4
-
5
- require "albacore/config/config"
6
- require "albacore/config/netversion"
7
-
8
- require "albacore/support/attrmethods"
9
- require "albacore/support/createtask"
10
- require "albacore/support/failure"
11
- require "albacore/support/logging"
12
- require "albacore/support/openstruct"
13
- require "albacore/support/runcommand"
14
- require "albacore/support/platform"
15
- require "albacore/support/updateattributes"
16
- require "albacore/support/yamlconfig"
17
-
18
- # tasks
19
- require "albacore/aspnetcompiler"
20
- require "albacore/assemblyinfo"
21
- require "albacore/csc"
22
- require "albacore/docu"
23
- require "albacore/exec"
24
- require "albacore/fluentmigrator"
25
- require "albacore/ilmerge"
26
- require "albacore/msbuild"
27
- require "albacore/mspec"
28
- require "albacore/mstest"
29
- require "albacore/nant"
30
- require "albacore/nchurn"
31
- require "albacore/ncoverconsole"
32
- require "albacore/ncoverreport"
33
- require "albacore/ndepend"
34
- require "albacore/nugetinstall"
35
- require "albacore/nugetpack"
36
- require "albacore/nugetpush"
37
- require "albacore/nugetupdate"
38
- require "albacore/nunit"
39
- require "albacore/nuspec"
40
- require "albacore/output"
41
- require "albacore/plink"
42
- require "albacore/specflow"
43
- require "albacore/sqlcmd"
44
- require "albacore/unzip"
45
- require "albacore/xbuild"
46
- require "albacore/xunit"
47
- require "albacore/zipdirectory"
1
+ require 'albacore/version'
2
+ require 'albacore/albacore_module'
3
+ require 'albacore/dsl'
@@ -0,0 +1,57 @@
1
+ require 'albacore/application'
2
+ require 'albacore/logging'
3
+
4
+ # The albacore module instance methods.
5
+ module Albacore
6
+ class << self
7
+ # Accessor for the Albacore application. Configuration
8
+ # and similar singleton values will be stored in this
9
+ # instance. Multiple calls will yield the same instance.
10
+ def application
11
+ @application ||= Albacore::Application.new
12
+ end
13
+
14
+ # set the application -- good for testing
15
+ # the infrastructure of albacore by resetting the
16
+ # state after each test
17
+ def set_application app
18
+ @application = app
19
+ end
20
+
21
+ # Defines a new task with all of what that entails:
22
+ # will call application.define_task.
23
+ def define_task *args, &block
24
+ args = [caller[0][/`.*'/][1..-2]] if args.nil? or args.empty?
25
+ # delegate to the application singleton
26
+ application.define_task *args, &block
27
+ end
28
+
29
+ # Set the global albacore logging level.
30
+ def log_level= level
31
+ application.logger.level = level
32
+ end
33
+
34
+ # Use to write to STDOUT (by default)
35
+ def puts *args
36
+ application.puts *args
37
+ end
38
+
39
+ def events
40
+ @events ||= {}
41
+ end
42
+
43
+ def subscribe event, &block
44
+ event = event.to_sym unless event.is_a? Symbol
45
+ events[event] ||= Set.new
46
+ events[event].add block
47
+ end
48
+
49
+ def publish event, obj
50
+ if events.member? event
51
+ events[event].each { |m| m.call(obj) }
52
+ end
53
+ end
54
+
55
+ Albacore.log_level = Logger::DEBUG if ENV["DEBUG"]
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ require 'rake'
2
+ module Albacore
3
+ class Application
4
+
5
+ # the logger instance for this application
6
+ attr_reader :logger
7
+
8
+ # the output IO for this application, defaults to
9
+ # STDOUT
10
+ attr_reader :output
11
+
12
+ # the standard IO error output
13
+ attr_reader :output_err
14
+
15
+ # initialize a new albacore application with a given log IO object
16
+ def initialize log = STDOUT, output = STDOUT, output_err = STDERR
17
+ raise ArgumentError, "log must not be nil" unless log
18
+ raise ArgumentError, "output must not be nil" unless output
19
+ raise ArgumentError, "out_err must not be nil" unless output_err
20
+ @logger = Logger.new log
21
+ @logger.level = Logger::INFO
22
+ @logger.formatter = proc do |severity, datetime, progname, msg|
23
+ "#{severity[0]} #{datetime.to_datetime.iso8601(6)}: #{msg}\n"
24
+ end
25
+ @output = output
26
+ @output_err = output_err
27
+ end
28
+
29
+ def define_task *args, &block
30
+ Rake::Task.define_task *args, &block
31
+ end
32
+
33
+ # wite a line to stdout
34
+ def puts *args
35
+ @output.puts *args
36
+ end
37
+
38
+ # write a line to stderr
39
+ def err *args
40
+ @output_err.puts *args
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'set'
4
+ require 'albacore/config_dsl'
5
+
6
+ module Albacore
7
+
8
+ # Use on **configuration** objects that are command-oriented.
9
+ #
10
+ # a mixin that adds a couple of field writers and readers.
11
+ # specifically, allows the configuration to have a work_dir and exe field
12
+ # and defined a method that joins paths relative to the work_dir
13
+ module CmdConfig
14
+ include Logging
15
+ self.extend ConfigDSL
16
+
17
+ # TODO: move towards opts for all task types rather than
18
+ # reading these public properties.
19
+
20
+ # the working directory for this command
21
+ attr_path_accessor :work_dir
22
+
23
+ # TODO: move towards opts for all task types rather than
24
+ # reading these public properties.
25
+
26
+ # field field denoting the path of the executable that should be on the path
27
+ # specified in the work_dir parameter.
28
+ attr_path_accessor :exe
29
+
30
+ # TODO: move towards opts for all task types rather than
31
+ # reading these public properties.
32
+
33
+ # returns a Set with parameters
34
+ def parameters
35
+ @parameters ||= Set.new
36
+ end
37
+
38
+ # add a parameter to the list of parameters to pass to the executable
39
+ def add_parameter param
40
+ parameters.add param
41
+ end
42
+
43
+ # helper method that joins the path segments with
44
+ # respect to the work_dir.
45
+ private
46
+ def join *segments
47
+ segments ||= []
48
+ segments.unshift work_dir
49
+ File.join segments
50
+ end
51
+
52
+ # helper method that changes directory to the work directory
53
+ # and then yields to the block
54
+ def in_work_dir
55
+ unless @work_dir.nil?
56
+ Dir.chdir @work_dir do
57
+ trace "in work dir '#{@work_dir}'"
58
+ yield
59
+ end
60
+ else
61
+ trace "not in work dir, because it is nil."
62
+ yield
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,55 @@
1
+ require 'albacore/paths'
2
+
3
+ module Albacore
4
+ # a small DSL to mix into your configuration classes
5
+ module ConfigDSL
6
+ # creates a new attr_writer for the symbols passed,
7
+ # such that a write to that method will normalise the paths
8
+ # of the written value: you can pass an optional callback
9
+ def attr_path *syms, &block
10
+ given = block_given?
11
+
12
+ syms.each do |sym|
13
+
14
+ # this is the callback method when the value is set
15
+ self.send(:define_method, :"__on_#{sym}") do |val|
16
+ instance_exec(val, &block) if given
17
+ end
18
+
19
+ # this is the setter, it also calls the callback method
20
+ # defined above.
21
+ self.class_eval(
22
+ %{def #{sym}= val
23
+ @#{sym} = ::Albacore::Paths.normalise_slashes val
24
+ __on_#{sym} @#{sym}
25
+ end})
26
+ end
27
+ end
28
+
29
+ # read/write attribute with rewriting of set values to
30
+ # match the system's paths
31
+ def attr_path_accessor *syms, &block
32
+ given = block_given?
33
+
34
+ syms.each do |sym|
35
+
36
+ # this is the callback method when the value is set
37
+ self.send(:define_method, :"__on_#{sym}") do |val|
38
+ instance_exec(val, &block) if given
39
+ end
40
+
41
+ # this is the setter and getter. The setter also calls
42
+ # the callback method defined above.
43
+ self.class_eval(
44
+ %{def #{sym}= val
45
+ @#{sym} = ::Albacore::Paths.normalise_slashes val
46
+ __on_#{sym} @#{sym}
47
+ end})
48
+ self.class_eval(
49
+ %{def #{sym}
50
+ @#{sym}
51
+ end})
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,291 @@
1
+ require 'rake'
2
+ require 'map'
3
+ require 'open3'
4
+ require 'timeout'
5
+ require 'processpilot/processpilot'
6
+ require 'albacore/paths'
7
+ require 'albacore/logging'
8
+ require 'albacore/errors/command_not_found_error'
9
+ require 'albacore/errors/command_failed_error'
10
+
11
+ module Albacore
12
+ # module for normalising slashes across operating systems
13
+ # and running commands
14
+ module CrossPlatformCmd
15
+ include Logging
16
+
17
+ # Exit status class for times the system just gives us a nil.
18
+ class PseudoStatus
19
+ attr_reader :exitstatus
20
+ def initialize(code=0)
21
+ @exitstatus = code
22
+ end
23
+ def to_i
24
+ @exitstatus << 8
25
+ end
26
+ def >>(n)
27
+ to_i >> n
28
+ end
29
+ def stopped?
30
+ false
31
+ end
32
+ def exited?
33
+ true
34
+ end
35
+ end
36
+
37
+ class << self
38
+ include CrossPlatformCmd
39
+ end
40
+
41
+ attr_reader :pid
42
+
43
+ KILL_TIMEOUT = 2 # seconds
44
+
45
+ def initialize
46
+ pid = Process.pid
47
+ at_exit { stop if Process.pid == pid }
48
+ end
49
+
50
+ # run executable
51
+ #
52
+ # system(cmd, [args array], Hash(opts), block|ok,status|)
53
+ # ok => false if bad exit code, or the output otherwise
54
+ #
55
+ # options are passed as the last argument
56
+ #
57
+ # options:
58
+ # work_dir: a file path (default '.')
59
+ # silent: whether to supress all output or not (default false)
60
+ # output: whether to supress the command's output (default false)
61
+ # out: output pipe
62
+ # err: error pipe
63
+ #
64
+ def system *cmd, &block
65
+ raise ArgumentError, "cmd is nil" if cmd.nil? # don't allow nothing to be passed
66
+ opts = Map.options((Hash === cmd.last) ? cmd.pop : {}). # same arg parsing as rake
67
+ apply(
68
+ silent: false,
69
+ output: true,
70
+ work_dir: FileUtils.pwd,
71
+ out: Albacore.application.output,
72
+ err: Albacore.application.output_err)
73
+
74
+ exe, pars, printable, block = prepare_command cmd, &block
75
+
76
+ # TODO: figure out how to interleave output and error streams
77
+ out, _, inmem = opts.get(:out), opts.get(:err), StringIO.new
78
+
79
+ trace { "system( exe=#{exe}, pars=[#{pars.join(', ')}], options=#{opts.to_s}), in directory: #{opts.getopt(:workdir, '<<current>>')} [cross_platform_cmd #system]" }
80
+
81
+ puts printable unless opts.get :silent, false # log cmd verbatim
82
+
83
+ handle_not_found block do
84
+ # create a pipe for the process to work with
85
+ read, write = IO.pipe
86
+ eread, ewrite = IO.pipe
87
+
88
+ # this thread chews through the output
89
+ @out_thread = Thread.new {
90
+ while !read.eof?
91
+ data = read.readpartial(1024)
92
+ out.write data
93
+ inmem.write data # to give the block at the end
94
+ end
95
+ }
96
+
97
+ debug 'execute the new process, letting it write to the write FD (file descriptor)'
98
+ @pid = Process.spawn(*[exe, *pars],
99
+ out: write,
100
+ # err: ewrite,
101
+ chdir: opts.get(:work_dir))
102
+
103
+ debug 'waiting for process completion'
104
+ _, status = Process.wait2 @pid
105
+
106
+ #debug 'waiting for thread completion'
107
+ #@out_thread.join
108
+
109
+ return block.call(status.success? && inmem.string, status)
110
+ end
111
+ end
112
+
113
+ def stop
114
+ if pid
115
+ begin
116
+ Process.kill('TERM', pid)
117
+
118
+ begin
119
+ Timeout.timeout(KILL_TIMEOUT) { Process.wait(pid) }
120
+ rescue Timeout::Error
121
+ Process.kill('KILL', pid)
122
+ Process.wait(pid)
123
+ end
124
+ rescue Errno::ESRCH, Errno::ECHILD
125
+ # Zed's dead, baby
126
+ end
127
+
128
+ @out_thread.kill
129
+ @pid = nil
130
+ end
131
+ end
132
+
133
+ # http://www.ruby-doc.org/core-2.0/Process.html#method-c-spawn
134
+ # https://practicingruby.com/articles/shared/ujxrxprnlugz
135
+ # https://github.com/jonleighton/poltergeist/blob/3365dadfb6242b0b91fe00359ff881e582cc2557/lib/capybara/poltergeist/client.rb
136
+
137
+ # run in shell
138
+ def sh *cmd, &block
139
+ raise ArgumentError, "cmd is nil" if cmd.nil? # don't allow nothing to be passed
140
+ opts = Map.options((Hash === cmd.last) ? cmd.pop : {}) # same arg parsing as rake
141
+
142
+ cmd = cmd.join(' ') # shell needs a single string
143
+ block = handler_with_message cmd unless block_given?
144
+
145
+ chdir opts.get(:work_dir) do
146
+
147
+ trace { "#sh( ..., options: #{opts.to_s}) [cross_platform_cmd #sh]" }
148
+ puts cmd unless opts.getopt :silent, false # log cmd verbatim
149
+
150
+ lines = ''
151
+ handle_not_found block do
152
+ IO.popen(cmd, 'r') do |io|
153
+ io.each do |line|
154
+ lines << line
155
+ puts line if opts.getopt(:output, true) or not opts.getopt(:silent, false)
156
+ end
157
+ end
158
+ end
159
+
160
+ return block.call($? == 0 && lines, $?)
161
+ end
162
+ end
163
+
164
+ # shell ignore exit code
165
+ # returns:
166
+ # [ok, status]
167
+ # where status:
168
+ # #exitstatus : Int
169
+ # #pid : Int
170
+ def shie *cmd, &block
171
+ block = lambda { |ok, status| ok } unless block_given?
172
+ sh *cmd, &block
173
+ end
174
+
175
+ def system_control cmd, *opts, &block
176
+ cmd = opts[0]
177
+ opts = Map.options((Hash === cmd.last) ? cmd.pop : {}) # same arg parsing as rake
178
+ chdir opts[:work_dir] do
179
+ puts cmd
180
+ ProcessPilot::pilot cmd, opts, &block
181
+ end
182
+ end
183
+
184
+ def normalise_slashes path
185
+ ::Albacore::Paths.normalise_slashes path
186
+ end
187
+
188
+ # create a new command string
189
+ def make_command
190
+ ::Albacore::Paths.make_command @executable, @parameters
191
+ end
192
+
193
+ def which executable
194
+ raise ArgumentError, "executable is nil" unless executable
195
+
196
+ dir = File.dirname executable
197
+ file = File.basename executable
198
+
199
+ cmd = ::Rake::Win32.windows? ? 'where' : 'which'
200
+ parameters = []
201
+ parameters << Paths.normalise_slashes(file) if dir == '.'
202
+ parameters << Paths.normalise_slashes("#{dir}:#{file}") unless dir == '.'
203
+ cmd, parameters = Paths.normalise cmd, parameters
204
+
205
+ trace { "#{cmd} #{parameters.join(' ')} [cross_platform_cmd #which]" }
206
+
207
+ null = ::Rake::Win32.windows? ? "NUL" : "/dev/null"
208
+ res = IO.popen([cmd, *parameters]) do |io|
209
+ io.read.chomp
210
+ end
211
+
212
+ unless $? == 0
213
+ nil
214
+ else
215
+ res
216
+ end
217
+ rescue Errno::ENOENT => e
218
+ trace "which/where returned #{$?}: #{e} [cross_platform_cmd #which]"
219
+ nil
220
+ end
221
+
222
+ def chdir wd, &block
223
+ return block.call if wd.nil?
224
+ Dir.chdir wd do
225
+ debug { "pushd #{wd} [cross_platform_cmd #chdir]" }
226
+ res = block.call
227
+ debug { "popd #{wd} [cross_platform_cmd #chdir]" }
228
+ return res
229
+ end
230
+ end
231
+
232
+ private
233
+
234
+ def prepare_command cmd, &block
235
+ pars = cmd[1..-1].flatten
236
+ raise ArgumentError, "arguments 1..-1 must be an array" unless pars.is_a? Array
237
+
238
+ exe, pars = ::Albacore::Paths.normalise cmd[0], pars
239
+ printable = %Q{#{exe} #{pars.join(' ')}}
240
+ handler = block_given? ? block : handler_with_message(printable)
241
+ [exe, pars, printable, handler]
242
+ end
243
+
244
+ def handler_with_message printable
245
+ lambda { |ok, status| ok or raise_failure(printable, status) }
246
+ end
247
+
248
+ # handles the errors from not finding the executable on the system
249
+ def handle_not_found rescue_block
250
+ yield
251
+ rescue Errno::ENOENT => e
252
+ rescue_block.call(nil, PseudoStatus.new(127))
253
+ rescue IOError => e # rescue for JRuby
254
+ rescue_block.call(nil, PseudoStatus.new(127))
255
+ end
256
+
257
+
258
+ def knowns
259
+ { 127 => 'number 127 in particular means that the operating system could not find the executable' }
260
+ end
261
+
262
+ def raise_failure cmd, status
263
+ if status.exitstatus == 127
264
+ raise CommandNotFoundError.new(format_failure(cmd, status), cmd)
265
+ else
266
+ raise CommandFailedError.new(format_failure(cmd, status), cmd)
267
+ end
268
+ end
269
+
270
+ def format_failure cmd, status
271
+ if knowns.has_key? status.exitstatus
272
+ %{Command failed with status (#{status.exitstatus}) - #{knowns[status.exitstatus]}:
273
+ #{cmd}}
274
+ else
275
+ %{Command failed with status (#{status.exitstatus}):
276
+ #{cmd}}
277
+ end
278
+ end
279
+
280
+ # shuffle the executable to be a parameter to
281
+ # mono, if not on windows.
282
+ def mono_command
283
+ unless ::Rake::Win32.windows?
284
+ trace 'detected running on mono -- unshifting exe file for mono'
285
+ executable = @executable
286
+ @executable = "mono"
287
+ @parameters.unshift executable
288
+ end
289
+ end
290
+ end
291
+ end