func()

in src/startupscriptgenerator/src/node/scriptgenerator.go [66:219]


func (gen *NodeStartupScriptGenerator) GenerateEntrypointScript() string {
	logger := common.GetLogger("node.scriptgenerator.GenerateEntrypointScript")
	defer logger.Shutdown()

	logger.LogInformation("Generating script for source.")

	scriptBuilder := strings.Builder{}
	scriptBuilder.WriteString("#!/bin/sh\n")

	nodeBinary := fmt.Sprintf("%s/bin/node", consts.NodeInstallationDir)
	enableDynamicInstall := common.GetBooleanEnvironmentVariable(consts.EnableDynamicInstallKey)
	if enableDynamicInstall && !common.PathExists(nodeBinary) {
		scriptBuilder.WriteString(fmt.Sprintf("oryx setupEnv -appPath %s\n", gen.SourcePath))
	}

	common.SetupPreRunScript(&scriptBuilder, gen.SourcePath, gen.Configuration.PreRunCommand)

	scriptBuilder.WriteString("\n# Enter the source directory to make sure the script runs where the user expects\n")
	scriptBuilder.WriteString("cd \"" + gen.SourcePath + "\"\n\n")
	globalNodeModulesDir := consts.NodeGlobalModulesPath
	scriptBuilder.WriteString("export NODE_PATH=" + globalNodeModulesDir + ":$NODE_PATH\n")

	// Expose the port so that a custom command can use it if needed.
	common.SetEnvironmentVariableInScript(&scriptBuilder, "PORT", gen.BindPort, DefaultBindPort)

	if !gen.SkipNodeModulesExtraction && gen.Manifest.CompressedNodeModulesFile != "" {
		targetNodeModulesDir := "/node_modules"
		if strings.HasSuffix(gen.Manifest.CompressedNodeModulesFile, ".zip") {
			scriptBuilder.WriteString("echo Found zip-based node_modules.\n")
			scriptBuilder.WriteString(
				"extractionCommand=\"unzip -q " + gen.Manifest.CompressedNodeModulesFile +
					" -d " + targetNodeModulesDir + "\"\n")

		} else if strings.HasSuffix(gen.Manifest.CompressedNodeModulesFile, ".tar.gz") {
			scriptBuilder.WriteString("echo Found tar.gz based node_modules.\n")
			scriptBuilder.WriteString(
				"extractionCommand=\"tar -xzf " + gen.Manifest.CompressedNodeModulesFile +
					" -C " + targetNodeModulesDir + "\"\n")
		} else {
			fmt.Printf(
				"Error: Unrecognizable file '%s'. Expected a file with an extension '.zip' or '.tar.gz'\n",
				gen.Manifest.CompressedNodeModulesFile)
			os.Exit(consts.FAILURE_EXIT_CODE)
		}

		scriptBuilder.WriteString("echo \"Removing existing modules directory from root...\"\n")
		scriptBuilder.WriteString("rm -fr " + targetNodeModulesDir + "\n")
		scriptBuilder.WriteString("mkdir -p " + targetNodeModulesDir + "\n")
		scriptBuilder.WriteString("echo Extracting modules...\n")
		scriptBuilder.WriteString("$extractionCommand\n")

		// Some versions of node, in particular Node 4.8 and 6.2 according to our tests, do not find the node_modules
		// folder at the root. To handle these versions, we also add /node_modules to the NODE_PATH directory.
		scriptBuilder.WriteString("export NODE_PATH=\"" + targetNodeModulesDir + "\":$NODE_PATH\n")
		// NPM adds the current directory's node_modules/.bin folder to PATH before it runs, so commands in
		// "npm start" can files there. Since we move node_modules, we have to add it to the path ourselves.
		scriptBuilder.WriteString("export PATH=" + targetNodeModulesDir + "/.bin:$PATH\n")
		// To avoid having older versions of packages available, we rename existing node_modules folder.
		// We move the directory/link first to prevent node from start using it
		scriptBuilder.WriteString("if [ -d node_modules ]; then\n")
		scriptBuilder.WriteString("    mv -f node_modules _del_node_modules || true\n")
		scriptBuilder.WriteString("fi\n\n")
		// Create a symlink to extracted nodemodules directory so that binaries mentioned in package.json(ex: 'ng serve')
		// can still find the nodemodules.
		scriptBuilder.WriteString("if [ -d " + targetNodeModulesDir + " ]; then\n")
		scriptBuilder.WriteString("    ln -sfn " + targetNodeModulesDir + " ./node_modules \n")
		scriptBuilder.WriteString("fi\n\n")
		scriptBuilder.WriteString("echo \"Done.\"\n")
	}

	// If user passed a custom startup command, it should take precedence above all other options
	startupCommand := strings.TrimSpace(gen.UserStartupCommand)
	userStartupCommandFullPath := ""
	if startupCommand != "" {
		userStartupCommandFullPath = filepath.Join(gen.SourcePath, startupCommand)
	}
	commandSource := "User"
	// If the startup command provided by the user is an actual file, we
	// explore it further to see if instead of being a script it is a js
	// or package.json file.
	if startupCommand == "" || common.FileExists(userStartupCommandFullPath) {
		logger.LogVerbose("No user-supplied startup command found")

		// deserialize package.json content
		packageJsonObj, packageJsonPath := getPackageJsonObject(gen.SourcePath, userStartupCommandFullPath)

		startupCommand = gen.getPackageJsonStartCommand(packageJsonObj, packageJsonPath)
		commandSource = "PackageJsonStart"

		if startupCommand == "" {
			logger.LogVerbose("scripts.start not found in package.json")
			startupCommand = gen.getPackageJsonMainCommand(packageJsonObj, packageJsonPath)
			commandSource = "PackageJsonMain"
		}

		if startupCommand == "" {
			startupCommand = gen.getProcessJsonCommand(userStartupCommandFullPath)
			commandSource = "ProcessJson"
		}

		if startupCommand == "" {
			startupCommand = gen.getConfigJsCommand(userStartupCommandFullPath)
			commandSource = "ConfigJs"
		}

		if startupCommand == "" {
			startupCommand = gen.getConfigYamlCommand(userStartupCommandFullPath)
			commandSource = "ConfigYaml"
		}

		if startupCommand == "" {
			startupCommand = gen.getUserProvidedJsFileCommand(userStartupCommandFullPath)
			commandSource = "UserJsFilePath"
		}

		if startupCommand == "" && userStartupCommandFullPath != "" {
			isPermissionAdded := common.ParseCommandAndAddExecutionPermission(gen.UserStartupCommand, gen.SourcePath)
			logger.LogInformation("permission added %t", isPermissionAdded)
			startupCommand = common.ExtendPathForCommand(gen.UserStartupCommand, gen.SourcePath)
			commandSource = "UserScript"
		}

		if startupCommand == "" {
			startupCommand = gen.getCandidateFilesStartCommand(gen.SourcePath)
			commandSource = "CandidateFile"
		}

		if startupCommand == "" {
			logger.LogWarning("Resorting to default startup command")
			startupCommand = gen.getDefaultAppStartCommand()
			commandSource = "DefaultApp"
		}

	} else {
		isPermissionAdded := common.ParseCommandAndAddExecutionPermission(gen.UserStartupCommand, gen.SourcePath)
		logger.LogInformation("Permission added: %t", isPermissionAdded)
		logger.LogInformation("User has supplied a startup command.")
		startupCommand = common.ExtendPathForCommand(startupCommand, gen.SourcePath)
	}

	logger.LogInformation("Looking for App-Insights loader generated by Oryx and export to NODE_OPTIONS if needed")
	if gen.shouldApplicationInsightsBeConfigured() {
		loaderFile := filepath.Join(consts.NodeGlobalModulesPath, consts.NodeAppInsightsLoaderFileName)

		var nodeOptions = "'--require " + loaderFile + " ' $NODE_OPTIONS"
		scriptBuilder.WriteString("export NODE_OPTIONS=" + nodeOptions + "\n")
	}
	scriptBuilder.WriteString(startupCommand + "\n")

	logger.LogProperties("Finalizing script", map[string]string{"commandSource": commandSource})

	var runScript = scriptBuilder.String()
	return runScript
}