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
}