Skip to main content

Environment

With each execution, jko creates an Independent environment—an entirely new instance that derives from either the system environment or the parent process environment. The environment variables can be reached in various contexts:

  • Function scripts: process.env.NAME
  • Traditional scripts: $NAME
  • Other processes: through mechanisms specific to each process (e.g., a Node.js process uses process.env.NAME)

For example:

  export default {
scripts: {
functionScriptA: function (param1, param2) {
console.log('functionScriptA')
process.env.jko_return_0 = `1. ${param1}_${param2}`
return 'functionScriptB'
},
functionScriptB: function (param1, param2) {
console.log('functionScriptB')
process.env.jko_return_1 = `2. ${param1}_${param2}`
return 'scriptC'
},
scriptC: 'echo scriptC: $jko_arg_0, $jko_return_0, $jko_return_1',
scriptD: 'jko functionScriptA 2 3 && jko scriptC'
}
}

(Actually, the output will be longer, but it has been simplified to emphasize functionality over presentation. To get the exact same output as in the example, must add -l=e options to all jko executions)

When executed:

$ jko scriptD
$ functionScriptA
$ functionScriptB
$ scriptC: 2, 1. 2_3, 2. 2_3
$ scriptC: , ,

scriptD chains two processes: jko functionScriptA 2 3 and jko scriptC.

Each execution creates an "Independent" environment:

  • In the first execution, being a chaining, the environment is shared, so when the tail script is invoked, it receives all the values. That's why you see scriptC: 2, 1. 2_3, 2. 2_3.
  • In the second execution, which operates in an "Independent" environment, both jko_return_0 and jko_return_1 are empty. As a result, the output is scriptC: , ,.

Let's change a few lines in functionScriptA and scriptD:

  export default {
scripts: {
functionScriptA: function (param1, param2) {
console.log('functionScriptA')
process.env.jko_return_0 = `1. ${param1}_${param2}`
return 'scriptD'
},
functionScriptB: function (param1, param2) {
console.log('functionScriptB')
process.env.jko_return_1 = `2. ${param1}_${param2}`
return 'scriptC'
},
scriptC: 'echo scriptC: $jko_arg_0, $jko_return_0, $jko_return_1',
scriptD: 'jko functionScriptB && jko scriptC',
}
}

(Actually, the output will be longer, but it has been simplified to emphasize functionality over presentation. To get the exact same output as in the example, must add -l=e options to all jko executions)

When executed:

$ jko functionScriptA 2 3
$ functionScriptA
$ functionScriptB
$ scriptC: 2, 1. 2_3, 2. undefined_undefined
$ scriptC: 2, 1. 2_3,
  • Shared Environment Creation:

    Executing jko functionScriptA 2 3 creates a Shared environment used by the two chained processes jko functionScriptB and jko scriptC, and also by their descendants.

    • In this process, jko_return_0 becomes available to both.
    • However, both jko functionScriptB and jko scriptC operate within their own Independent environments.
  • Argument Availability:

    Although the arguments 2 and 3 are available in scriptD, they are not accessible to functionScriptB. This is why the output displays undefined for those values (scriptC: 2, 1. 2_3, 2. undefined_undefined).

    • Nevertheless, jko_arg_0 and jko_arg_1 belong to the Shared environment and remain available.
  • Additionally, jko_return_1 is defined in the functionScriptB Independent environment and is not accessible to the initial scriptC. This is why the output appears as: scriptC: 2, 1. 2_3,.

Let's change a line in functionScriptB:

  export default {
scripts: {
functionScriptA: function (param1, param2) {
console.log('functionScriptA')
process.env.jko_return_0 = `1. ${param1}_${param2}`
return 'scriptD'
},
functionScriptB: function () {
console.log('functionScriptB')
process.env.jko_return_1 = `2. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`
return 'scriptC'
},
scriptC: 'echo scriptC: $jko_arg_0, $jko_return_0, $jko_return_1',
scriptD: 'jko functionScriptB && jko scriptC',
}
}

(Actually, the output will be longer, but it has been simplified to emphasize functionality over presentation. To get the exact same output as in the example, must add -l=e options to all jko executions)

When executed:

$ jko functionScriptA 2 3
$ functionScriptA
$ functionScriptB
$ scriptC: 2, 1. 2_3, 2. 2_3
$ scriptC: 2, 1. 2_3,

Using jko_arg_0 and jko_arg_1, which belong to the Shared environment, allows functionScriptB to access to original arguments.

Shared Environments

Chained processes share a common environment. As a result:

  • The environment variables holding the initial arguments are accessible in every script.
  • Newly added environment variables are available to subsequent scripts after their definition.

Review the following image that demonstrates how the environment evolves during the chaining calls:

See that:

  • Initial arguments, jko_arg_0, jko_arg_1, etc. are accessible in every script, functionScript1, functionScript2 and functionScript3.
    • Furthermore, they can be accessed as parameters these functions.
  • jko_return_0 is accessible to functionScript2 and functionScript3.
  • jko_return_1 is accessible to functionScript3.

For example:

  export default {
scripts: {
functionScript1: function (param1, param2) {
console.log('functionScript1:')
console.log(param1 === process.env.jko_arg_0)
console.log(param2 === process.env.jko_arg_1)
process.env.jko_return_0 = `1. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`
return 'functionScript2'
},
functionScript2: function (param1, param2) {
console.log('functionScript2:')
console.log(param1 === process.env.jko_arg_0)
console.log(param2 === process.env.jko_arg_1)
console.log(process.env.jko_return_0 === `1. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`)
process.env.jko_return_1 = `2. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`
return 'functionScript3'
},
functionScript3: function (param1, param2) {
console.log('functionScript3:')
console.log(param1 === process.env.jko_arg_0)
console.log(param2 === process.env.jko_arg_1)
console.log(process.env.jko_return_0 === `1. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`)
console.log(process.env.jko_return_1 === `2. ${process.env.jko_arg_0}_${process.env.jko_arg_1}`)
// End of the chaining
}
}
}

When executed:

$ jko functionScript1 1 2
$ functionScript1:
$ true
$ true
$ functionScript2:
$ true
$ true
$ true
$ functionScript3:
$ true
$ true
$ true
$ true
$ jko functionScript2 1 2
$ functionScript2:
$ true
$ true
$ false
$ functionScript3:
$ true
$ true
$ false
$ true

(Actually, the output will be longer, but it has been simplified to emphasize functionality over presentation. To get the exact same output as in the example, use the following command: jko -l=e functionScript1 1 2)

Enhancing Environment

Use envFile in jko.js to specify the path of a .env file, which provides required environment variables to the new instance where the script will run.

jko.js:

export default {
scripts: {
yourScript1: "someCommand",
},
envFile: './path/to/.env',
}

.env:

SOME_ENV_VAR=VALUE1

Additionally, the .env file can be specified using the CLI option --env-file:

$ jko --env-file=./path/to/.env yourScript arg1 ... argN 
info

command line option --env-file takes precedence over envFile.

Additional Environment Variables

In addition to generating environment variables for each command-line argument, jko creates environment variables for every field exported by jko.js (package.json, or any configuration file specified via the --config-file option) — excluding scripts field.

These environment variables are generated with a jko_ prefix. Additionally, for compatibility reasons, variables prefixed with npm_package_ are also added.

For example, using the following jko.js:

export default {
scripts: {
yourScript1: "someCommand",
},
envFile: './path/to/.env',
dependencies: {
packageName1: "1.0.0"
},
devDependencies: {
devPackageName1: "1.0.0"
},
packageManager: 'yarn',
logLevel: 'warn',
config: {
data: ['A', 'B']
},
version: '1.2.3',
name: 'theName'
}

jko will generated the following variables:

  • jko_config_data_0, npm_package_config_data_0.
  • jko_config_data_1, npm_package_config_data_1.
  • jko_version, npm_package_version.
  • jko_name, npm_package_name.
  • etc.
tip

You can provide default jko_arg_ values using this mechanism—simply define an arg field as an array:

export default {
scripts: {
yourScript1: "someCommand",
},
arg: ['arg1', 'argN']
}

Summary

tip
  • Each jko execution runs in a new Independent Environment. This environment may belong to a Shared Environment or not, and it is a Shared Environment among its descendant processes.
  • Chained function scripts run in a Shared Environment.
  • Chained commands in traditional scripts run in a Shared Environment.
  • jko introduces custom environment variables with a jko_ prefix (and, for compatibility, supports variables prefixed with npm_package_).
  • Environment variables will be reachable in multiple ways. For function scripts, use process.env.NAME; for traditional scripts, use $NAME; and for other processes, the access method varies.