| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  | module Language | 
					
						
							| 
									
										
										
										
											2020-08-17 18:58:52 +02:00
										 |  |  |   # Helper functions for Node formulae. | 
					
						
							|  |  |  |   # | 
					
						
							|  |  |  |   # @api public | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |   module Node | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |     sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     def self.npm_cache_config | 
					
						
							| 
									
										
										
										
											2017-06-26 21:47:47 +02:00
										 |  |  |       "cache=#{HOMEBREW_CACHE}/npm_cache" | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |     sig { returns(String) } | 
					
						
							| 
									
										
										
										
											2017-05-31 04:57:28 +01:00
										 |  |  |     def self.pack_for_installation | 
					
						
							|  |  |  |       # Homebrew assumes the buildpath/testpath will always be disposable | 
					
						
							|  |  |  |       # and from npm 5.0.0 the logic changed so that when a directory is | 
					
						
							|  |  |  |       # fed to `npm install` only symlinks are created linking back to that | 
					
						
							|  |  |  |       # directory, consequently breaking that assumption. We require a tarball | 
					
						
							|  |  |  |       # because npm install creates a "real" installation when fed a tarball. | 
					
						
							| 
									
										
										
										
											2023-11-05 08:55:58 -08:00
										 |  |  |       package = Pathname("package.json") | 
					
						
							|  |  |  |       if package.exist? | 
					
						
							| 
									
										
										
										
											2020-11-04 21:33:06 -05:00
										 |  |  |         begin | 
					
						
							|  |  |  |           pkg_json = JSON.parse(package.read) | 
					
						
							|  |  |  |         rescue JSON::ParserError | 
					
						
							| 
									
										
										
										
											2020-11-06 06:40:50 -05:00
										 |  |  |           opoo "Could not parse package.json!" | 
					
						
							| 
									
										
										
										
											2020-11-04 21:33:06 -05:00
										 |  |  |           raise | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |         prepare_removed = pkg_json["scripts"]&.delete("prepare") | 
					
						
							|  |  |  |         prepack_removed = pkg_json["scripts"]&.delete("prepack") | 
					
						
							| 
									
										
										
										
											2022-06-14 08:56:04 +01:00
										 |  |  |         postpack_removed = pkg_json["scripts"]&.delete("postpack") | 
					
						
							|  |  |  |         package.atomic_write(JSON.pretty_generate(pkg_json)) if prepare_removed || prepack_removed || postpack_removed | 
					
						
							| 
									
										
										
										
											2020-11-04 21:33:06 -05:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2021-03-17 15:34:20 +00:00
										 |  |  |       output = Utils.popen_read("npm", "pack", "--ignore-scripts") | 
					
						
							| 
									
										
										
										
											2019-02-19 13:11:32 +00:00
										 |  |  |       raise "npm failed to pack #{Dir.pwd}" if !$CHILD_STATUS.exitstatus.zero? || output.lines.empty? | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-26 21:33:12 +02:00
										 |  |  |       output.lines.last.chomp | 
					
						
							| 
									
										
										
										
											2017-05-31 04:57:28 +01:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |     sig { void } | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     def self.setup_npm_environment | 
					
						
							| 
									
										
										
										
											2017-06-26 21:47:47 +02:00
										 |  |  |       # guard that this is only run once | 
					
						
							|  |  |  |       return if @env_set | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |       @env_set = T.let(true, T.nilable(T::Boolean)) | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |       # explicitly use our npm and node-gyp executables instead of the user | 
					
						
							|  |  |  |       # managed ones in HOMEBREW_PREFIX/lib/node_modules which might be broken | 
					
						
							| 
									
										
										
										
											2017-06-19 01:26:52 +05:30
										 |  |  |       begin | 
					
						
							|  |  |  |         ENV.prepend_path "PATH", Formula["node"].opt_libexec/"bin" | 
					
						
							|  |  |  |       rescue FormulaUnavailableError | 
					
						
							|  |  |  |         nil | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |     sig { params(libexec: Pathname).returns(T::Array[String]) } | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     def self.std_npm_install_args(libexec) | 
					
						
							|  |  |  |       setup_npm_environment | 
					
						
							|  |  |  |       # tell npm to not install .brew_home by adding it to the .npmignore file | 
					
						
							|  |  |  |       # (or creating a new one if no .npmignore file already exists) | 
					
						
							| 
									
										
										
										
											2016-09-10 10:38:35 +01:00
										 |  |  |       open(".npmignore", "a") { |f| f.write("\n.brew_home\n") } | 
					
						
							| 
									
										
										
										
											2017-05-31 04:57:28 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       pack = pack_for_installation | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-22 19:36:06 +02:00
										 |  |  |       # npm 7 requires that these dirs exist before install | 
					
						
							|  |  |  |       (libexec/"lib").mkpath | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |       # npm install args for global style module format installed into libexec | 
					
						
							| 
									
										
										
										
											2020-02-28 12:56:38 +01:00
										 |  |  |       args = %W[
 | 
					
						
							| 
									
										
										
										
											2017-06-26 20:28:18 +02:00
										 |  |  |         -ddd | 
					
						
							| 
									
										
										
										
											2017-05-31 04:57:28 +01:00
										 |  |  |         --global | 
					
						
							| 
									
										
										
										
											2017-06-26 20:35:48 +02:00
										 |  |  |         --build-from-source | 
					
						
							| 
									
										
										
										
											2017-06-26 21:47:47 +02:00
										 |  |  |         --#{npm_cache_config} | 
					
						
							| 
									
										
										
										
											2017-05-31 04:57:28 +01:00
										 |  |  |         --prefix=#{libexec} | 
					
						
							|  |  |  |         #{Dir.pwd}/#{pack} | 
					
						
							|  |  |  |       ] | 
					
						
							| 
									
										
										
										
											2020-02-28 12:56:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 13:36:29 +01:00
										 |  |  |       args << "--unsafe-perm" if Process.uid.zero? | 
					
						
							| 
									
										
										
										
											2020-02-28 12:56:38 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |       args | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-20 12:03:48 +02:00
										 |  |  |     sig { returns(T::Array[String]) } | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     def self.local_npm_install_args | 
					
						
							|  |  |  |       setup_npm_environment | 
					
						
							|  |  |  |       # npm install args for local style module format | 
					
						
							| 
									
										
										
										
											2017-06-26 21:47:47 +02:00
										 |  |  |       %W[
 | 
					
						
							| 
									
										
										
										
											2017-06-26 20:35:48 +02:00
										 |  |  |         -ddd | 
					
						
							|  |  |  |         --build-from-source | 
					
						
							| 
									
										
										
										
											2017-06-26 21:47:47 +02:00
										 |  |  |         --#{npm_cache_config} | 
					
						
							| 
									
										
										
										
											2017-06-26 20:35:48 +02:00
										 |  |  |       ] | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2023-08-12 12:36:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Mixin module for {Formula} adding shebang rewrite features. | 
					
						
							|  |  |  |     module Shebang | 
					
						
							|  |  |  |       module_function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       # A regex to match potential shebang permutations. | 
					
						
							| 
									
										
										
										
											2024-01-18 22:18:42 +00:00
										 |  |  |       NODE_SHEBANG_REGEX = %r{^#! ?/usr/bin/(?:env )?node( |$)} | 
					
						
							| 
									
										
										
										
											2023-08-12 12:36:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # The length of the longest shebang matching `SHEBANG_REGEX`. | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |       NODE_SHEBANG_MAX_LENGTH = T.let("#! /usr/bin/env node ".length, Integer) | 
					
						
							| 
									
										
										
										
											2023-08-12 12:36:29 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |       # @private | 
					
						
							|  |  |  |       sig { params(node_path: T.any(String, Pathname)).returns(Utils::Shebang::RewriteInfo) } | 
					
						
							|  |  |  |       def node_shebang_rewrite_info(node_path) | 
					
						
							|  |  |  |         Utils::Shebang::RewriteInfo.new( | 
					
						
							|  |  |  |           NODE_SHEBANG_REGEX, | 
					
						
							|  |  |  |           NODE_SHEBANG_MAX_LENGTH, | 
					
						
							|  |  |  |           "#{node_path}\\1", | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-29 18:26:13 -04:00
										 |  |  |       sig { params(formula: Formula).returns(Utils::Shebang::RewriteInfo) } | 
					
						
							|  |  |  |       def detected_node_shebang(formula = T.cast(self, Formula)) | 
					
						
							| 
									
										
										
										
											2023-08-12 12:36:29 -04:00
										 |  |  |         node_deps = formula.deps.map(&:name).grep(/^node(@.+)?$/) | 
					
						
							|  |  |  |         raise ShebangDetectionError.new("Node", "formula does not depend on Node") if node_deps.empty? | 
					
						
							|  |  |  |         raise ShebangDetectionError.new("Node", "formula has multiple Node dependencies") if node_deps.length > 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         node_shebang_rewrite_info(Formula[node_deps.first].opt_bin/"node") | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							| 
									
										
										
										
											2016-04-27 18:08:44 +02:00
										 |  |  |   end | 
					
						
							|  |  |  | end |