libdragon 10.3.1 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -1
- package/README.md +2 -12
- package/index.js +44 -6
- package/modules/actions/exec.js +91 -0
- package/modules/{usage.js → actions/help.js} +37 -9
- package/modules/actions/index.js +43 -0
- package/modules/actions/init.js +190 -0
- package/modules/actions/install.js +52 -0
- package/modules/actions/start.js +114 -0
- package/modules/actions/update.js +48 -0
- package/modules/actions/utils.js +314 -0
- package/modules/constants.js +9 -4
- package/modules/globals.js +5 -0
- package/modules/helpers.js +82 -276
- package/modules/project-info.js +232 -0
- package/package.json +4 -4
- package/modules/actions.js +0 -611
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## [10.4.0] - 2022-03-23
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Update the root makefile to utilize `SOURCE_DIR` for example builds. Then we are
|
|
8
|
+
able to map container files to local files properly with a generic regex in the
|
|
9
|
+
problem matcher. This fixes #13 and does not change any behaviour.
|
|
10
|
+
- Add missing examples to the vscode run configurations.
|
|
11
|
+
- Install and build libdragon related things in the container when `exec` and
|
|
12
|
+
`make` causes a new container run. This was previously prevented on `v10.3.1`
|
|
13
|
+
because it was unnecessarily delaying all exec operations when the container
|
|
14
|
+
is started. Refactoring things allowed me to realize this can be improved
|
|
15
|
+
instead of forcing the user to do a manual `install`.
|
|
16
|
+
- Fix a potential issue that may cause the git commands to run in current folder
|
|
17
|
+
instead of the project root.
|
|
18
|
+
- Attach the error handler once for spawnProcess.
|
|
19
|
+
- Update vulnerable dependencies.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- `--directory` option to customize vendoring location.
|
|
24
|
+
- `--strategy` option to select a vendoring strategy. Currently supported options
|
|
25
|
+
are `submodule`, `subtree` and `manual`. The default is `submodule` and `manual`
|
|
26
|
+
can be used to opt-out of auto vendoring. Useful if the user wants to utilize
|
|
27
|
+
a different vendoring strategy and opt-out of the auto-managed git flows.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Migrate to a json file for persistent project information.
|
|
32
|
+
- Only save the configuration file on successful exit except for the initial
|
|
33
|
+
migration.
|
|
34
|
+
- Do not prevent init if there is a file named libdragon in the target folder.
|
|
35
|
+
This used to cause problems on windows but I cannot reproduce it anymore
|
|
36
|
+
with `2.33.1.windows.1`. It may be something caused by my old configuration.
|
|
37
|
+
- Minor performance improvements.
|
|
38
|
+
|
|
3
39
|
## [10.3.1] - 2022-01-25
|
|
4
40
|
|
|
5
41
|
### Fixed
|
|
@@ -19,7 +55,7 @@
|
|
|
19
55
|
|
|
20
56
|
### Changed
|
|
21
57
|
|
|
22
|
-
- Only accept
|
|
58
|
+
- Only accept the image flag for init, install, and update actions as documented.
|
|
23
59
|
- Improve documentation for the `init` and `install` actions.
|
|
24
60
|
- Do not attempt an `install` when running `exec`, just start the container. If
|
|
25
61
|
there is a half-baked container, a manual `install` will potentially restore it.
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ To update the library and rebuild/install all the artifacts;
|
|
|
22
22
|
|
|
23
23
|
libdragon update
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
`git` is not strictly required to use this tool as docker's git will be used instead. Still, it is highly recommended to have git on your host machine.
|
|
26
26
|
|
|
27
27
|
## Overall usage
|
|
28
28
|
|
|
@@ -38,16 +38,6 @@ You can invoke libdragon as follows;
|
|
|
38
38
|
|
|
39
39
|
Run `libdragon help [action]` for more details on individual actions.
|
|
40
40
|
|
|
41
|
-
### Available flags
|
|
42
|
-
|
|
43
|
-
**`--image <docker-image>`**
|
|
44
|
-
|
|
45
|
-
Use this flag to provide a custom image to use instead of the default. It should include the toolchain at `/n64_toolchain`. It will be effective for `init`, `install` and `update` actions and will cause a re-initialization of the container if an image different from what was written to project configuration is provided.
|
|
46
|
-
|
|
47
|
-
**`--verbose`**
|
|
48
|
-
|
|
49
|
-
Be verbose. This will print all commands dispatched and their outputs as well.
|
|
50
|
-
|
|
51
41
|
## Working on this repository
|
|
52
42
|
|
|
53
43
|
After cloning this repository on a system with node.js (`>= 14`) & docker (`>= 18`), in this repository's root do;
|
|
@@ -92,7 +82,7 @@ To update the submodule and re-build everything;
|
|
|
92
82
|
|
|
93
83
|
### Local test bench
|
|
94
84
|
|
|
95
|
-
This repository also uses [ed64](https://github.com/anacierdem/ed64), so you can just hit F5 on vscode (The `Run Test Bench` launch configuration) to run the test code in `src` folder to develop libdragon itself quicker if you have an everdrive.
|
|
85
|
+
This repository also uses [ed64](https://github.com/anacierdem/ed64), so you can just hit F5 on vscode (The `Run Test Bench` launch configuration) to run the test code in `src` folder to develop libdragon itself quicker if you have an everdrive.
|
|
96
86
|
|
|
97
87
|
There are also additional vscode launch configurations to build libdragon examples and tests based on the currently built and installed libdragon in the docker container. Most of these will always rebuild so that they will use the latest if you made and installed an alternative libdragon. The test bench itself and a few examples (that use the new build system) will already rebuild and reinstall libdragon automatically. These will always produce a rom image using the latest libdragon code in the active repository via its make dependencies. You can clean everything with the `clean` task (open the command palette and choose `Run Task -> clean`).
|
|
98
88
|
|
package/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const { readProjectInfo, CommandError, globals } = require('./modules/helpers');
|
|
5
|
-
const actions = require('./modules/actions');
|
|
6
|
-
const { printUsage } = require('./modules/usage');
|
|
7
4
|
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
5
|
+
const actions = require('./modules/actions');
|
|
6
|
+
const { fn: printUsage } = require('./modules/actions/help');
|
|
7
|
+
const {
|
|
8
|
+
STATUS_OK,
|
|
9
|
+
STATUS_BAD_PARAM,
|
|
10
|
+
STATUS_ERROR,
|
|
11
|
+
} = require('./modules/constants');
|
|
12
|
+
const { globals } = require('./modules/globals');
|
|
13
|
+
const { CommandError, ParameterError } = require('./modules/helpers');
|
|
14
|
+
const { readProjectInfo, writeProjectInfo } = require('./modules/project-info');
|
|
11
15
|
|
|
12
16
|
let options = {},
|
|
13
17
|
currentAction;
|
|
@@ -32,6 +36,22 @@ for (let i = 2; i < process.argv.length; i++) {
|
|
|
32
36
|
continue;
|
|
33
37
|
}
|
|
34
38
|
|
|
39
|
+
if (['--directory', '-d'].includes(val)) {
|
|
40
|
+
options.VENDOR_DIR = process.argv[++i];
|
|
41
|
+
continue;
|
|
42
|
+
} else if (val.indexOf('--directory=') === 0) {
|
|
43
|
+
options.VENDOR_DIR = val.split('=')[1];
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (['--strategy', '-s'].includes(val)) {
|
|
48
|
+
options.VENDOR_STRAT = process.argv[++i];
|
|
49
|
+
continue;
|
|
50
|
+
} else if (val.indexOf('--strategy=') === 0) {
|
|
51
|
+
options.VENDOR_STRAT = val.split('=')[1];
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
35
55
|
if (val.indexOf('--') >= 0) {
|
|
36
56
|
console.error(chalk.red(`Invalid flag \`${val}\``));
|
|
37
57
|
printUsage();
|
|
@@ -81,6 +101,15 @@ if (
|
|
|
81
101
|
process.exit(STATUS_BAD_PARAM);
|
|
82
102
|
}
|
|
83
103
|
|
|
104
|
+
if (
|
|
105
|
+
options.VENDOR_STRAT &&
|
|
106
|
+
!['submodule', 'subtree', 'manual'].includes(options.VENDOR_STRAT)
|
|
107
|
+
) {
|
|
108
|
+
console.error(chalk.red(`Invalid strategy \`${options.VENDOR_STRAT}\``));
|
|
109
|
+
printUsage();
|
|
110
|
+
process.exit(STATUS_BAD_PARAM);
|
|
111
|
+
}
|
|
112
|
+
|
|
84
113
|
readProjectInfo()
|
|
85
114
|
.then((info) =>
|
|
86
115
|
currentAction.fn(
|
|
@@ -93,6 +122,11 @@ readProjectInfo()
|
|
|
93
122
|
)
|
|
94
123
|
)
|
|
95
124
|
.catch((e) => {
|
|
125
|
+
if (e instanceof ParameterError) {
|
|
126
|
+
console.error(chalk.red(e.message));
|
|
127
|
+
printUsage(undefined, [currentAction.name]);
|
|
128
|
+
process.exit(STATUS_BAD_PARAM);
|
|
129
|
+
}
|
|
96
130
|
const userTargetedError = e instanceof CommandError && e.userCommand;
|
|
97
131
|
|
|
98
132
|
// Show additional information to user if verbose or we did a mistake
|
|
@@ -115,6 +149,10 @@ readProjectInfo()
|
|
|
115
149
|
// We don't have a user targeted error anymore, we did a mistake for sure
|
|
116
150
|
process.exit(STATUS_ERROR);
|
|
117
151
|
})
|
|
152
|
+
.then(() => {
|
|
153
|
+
// Everything was done, update the configuration file if not exiting early
|
|
154
|
+
return writeProjectInfo();
|
|
155
|
+
})
|
|
118
156
|
.finally(() => {
|
|
119
157
|
process.exit(STATUS_OK);
|
|
120
158
|
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const { CONTAINER_TARGET_PATH } = require('../constants');
|
|
4
|
+
const { log, dockerExec, toPosixPath } = require('../helpers');
|
|
5
|
+
|
|
6
|
+
const { fn: start } = require('./start');
|
|
7
|
+
const { dockerHostUserParams, installDependencies } = require('./utils');
|
|
8
|
+
|
|
9
|
+
function dockerRelativeWorkdir(libdragonInfo) {
|
|
10
|
+
return (
|
|
11
|
+
CONTAINER_TARGET_PATH +
|
|
12
|
+
'/' +
|
|
13
|
+
toPosixPath(path.relative(libdragonInfo.root, process.cwd()))
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function dockerRelativeWorkdirParams(libdragonInfo) {
|
|
18
|
+
return ['--workdir', dockerRelativeWorkdir(libdragonInfo)];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const exec = async (libdragonInfo, commandAndParams) => {
|
|
22
|
+
log(
|
|
23
|
+
`Running ${commandAndParams[0]} at ${dockerRelativeWorkdir(
|
|
24
|
+
libdragonInfo
|
|
25
|
+
)} with [${commandAndParams.slice(1)}]`,
|
|
26
|
+
true
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const tryCmd = (libdragonInfo) =>
|
|
30
|
+
libdragonInfo.containerId &&
|
|
31
|
+
dockerExec(
|
|
32
|
+
libdragonInfo,
|
|
33
|
+
[
|
|
34
|
+
...dockerRelativeWorkdirParams(libdragonInfo),
|
|
35
|
+
...dockerHostUserParams(libdragonInfo),
|
|
36
|
+
],
|
|
37
|
+
commandAndParams,
|
|
38
|
+
true,
|
|
39
|
+
true // Cannot use "full" here, we need to know if the container is alive
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
let started = false;
|
|
43
|
+
const startOnceAndCmd = async () => {
|
|
44
|
+
if (!started) {
|
|
45
|
+
const newId = await start(libdragonInfo);
|
|
46
|
+
started = true;
|
|
47
|
+
|
|
48
|
+
// Re-install vendors on new container if one was created upon start
|
|
49
|
+
// Ideally we would want the consumer to handle dependencies and rebuild
|
|
50
|
+
// libdragon if necessary. Currently this saves the day with a little bit
|
|
51
|
+
// extra waiting when the container is deleted.
|
|
52
|
+
if (libdragonInfo.containerId !== newId) {
|
|
53
|
+
await installDependencies({
|
|
54
|
+
...libdragonInfo,
|
|
55
|
+
containerId: newId,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
await tryCmd({
|
|
59
|
+
...libdragonInfo,
|
|
60
|
+
containerId: newId,
|
|
61
|
+
});
|
|
62
|
+
return newId;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
if (!libdragonInfo.containerId) {
|
|
67
|
+
log(`Container does not exist for sure, restart`, true);
|
|
68
|
+
await startOnceAndCmd();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
await tryCmd(libdragonInfo);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
if (
|
|
76
|
+
!e.out ||
|
|
77
|
+
// TODO: is there a better way?
|
|
78
|
+
!e.out.toString().includes(libdragonInfo.containerId)
|
|
79
|
+
) {
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
await startOnceAndCmd();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports = {
|
|
87
|
+
name: 'exec',
|
|
88
|
+
fn: exec,
|
|
89
|
+
forwardsRestParams: true,
|
|
90
|
+
showStatus: true,
|
|
91
|
+
};
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const commandLineUsage = require('command-line-usage');
|
|
3
3
|
|
|
4
|
-
const { log } = require('
|
|
4
|
+
const { log } = require('../helpers');
|
|
5
5
|
|
|
6
6
|
const printUsage = (_, actionArr) => {
|
|
7
7
|
const globalOptionDefinitions = [
|
|
8
8
|
{
|
|
9
9
|
name: 'verbose',
|
|
10
|
-
description:
|
|
10
|
+
description:
|
|
11
|
+
'Be verbose. This will print all commands dispatched and their outputs as well. Will also start printing error stack traces.',
|
|
11
12
|
alias: 'v',
|
|
13
|
+
typeLabel: ' ',
|
|
12
14
|
group: 'global',
|
|
13
15
|
},
|
|
14
16
|
];
|
|
@@ -16,11 +18,34 @@ const printUsage = (_, actionArr) => {
|
|
|
16
18
|
const optionDefinitions = [
|
|
17
19
|
{
|
|
18
20
|
name: 'image',
|
|
19
|
-
description:
|
|
21
|
+
description:
|
|
22
|
+
'Use this flag to provide a custom image to use instead of the default. It should include the toolchain at `/n64_toolchain`. It will cause a re-initialization of the container if a different image is provided.\n',
|
|
20
23
|
alias: 'i',
|
|
21
24
|
typeLabel: '<docker-image>',
|
|
22
25
|
group: 'docker',
|
|
23
26
|
},
|
|
27
|
+
{
|
|
28
|
+
name: 'directory',
|
|
29
|
+
description: `Directory where libdragon files are expected. It must be a project relative path as it will be mounted on the docker container. The cli will create and manage it when using a non-manual strategy. Defaults to \`./libdragon\` if not provided.\n`,
|
|
30
|
+
alias: 'd',
|
|
31
|
+
typeLabel: '<path>',
|
|
32
|
+
group: 'vendoring',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'strategy',
|
|
36
|
+
description: `libdragon Vendoring strategy. Defaults to \`submodule\`, which safely creates a git repository at project root and a submodule at \`--directory\` to automatically update the vendored libdragon files.
|
|
37
|
+
|
|
38
|
+
With \`subtree\`, the cli will create a subtree at \`--directory\` instead. Keep in mind that git user name and email must be set up for this to work. Do not use if you are not using git yourself.
|
|
39
|
+
|
|
40
|
+
To disable auto-vendoring, init with \`manual\`. With \`manual\`, libdragon files are expected at the location provided by \`--directory\` flag and the user is responsible for vendoring and updating them. This will allow using any other manual vendoring method.
|
|
41
|
+
|
|
42
|
+
With the \`manual\` strategy, it is still recommended to have a git repository at project root such that container actions can execute faster by caching the container id inside the \`.git\` folder.
|
|
43
|
+
|
|
44
|
+
It is also possible to opt-out later on by running \`init\` with \`--strategy manual\`, though you will be responsible for managing the existing submodule/subtree.\n`,
|
|
45
|
+
alias: 'v',
|
|
46
|
+
typeLabel: '<strategy>',
|
|
47
|
+
group: 'vendoring',
|
|
48
|
+
},
|
|
24
49
|
];
|
|
25
50
|
|
|
26
51
|
const actions = {
|
|
@@ -31,12 +56,12 @@ const printUsage = (_, actionArr) => {
|
|
|
31
56
|
init: {
|
|
32
57
|
name: 'init',
|
|
33
58
|
summary: 'Create a libdragon project in the current directory.',
|
|
34
|
-
description: `Creates a libdragon project in the current directory. Every libdragon project will have its own docker container instance. If you are in a git repository or an NPM project, libdragon will be initialized at their root also marking there with a \`.libdragon\` folder.
|
|
59
|
+
description: `Creates a libdragon project in the current directory. Every libdragon project will have its own docker container instance. If you are in a git repository or an NPM project, libdragon will be initialized at their root also marking there with a \`.libdragon\` folder. Do not remove the \`.libdragon\` folder and commit its contents if you are using source control, as it keeps persistent libdragon project information.
|
|
35
60
|
|
|
36
|
-
|
|
61
|
+
By default, a git repository and a submodule at \`./libdragon\` will be created to automatically update the vendored libdragon files on subsequent \`update\`s. If you intend to opt-out from this feature, see the \`--strategy manual\` flag to provide your self-managed libdragon copy. The default behaviour is intended for users who primarily want to consume libdragon as is.
|
|
37
62
|
|
|
38
63
|
If this is the first time you are creating a libdragon project at that location, this action will also create skeleton project files to kickstart things with the given image, if provided. For subsequent runs, it will act like \`start\` thus can be used to revive an existing project without modifying it.`,
|
|
39
|
-
group: ['docker'],
|
|
64
|
+
group: ['docker', 'vendoring'],
|
|
40
65
|
},
|
|
41
66
|
make: {
|
|
42
67
|
name: 'make [params]',
|
|
@@ -70,7 +95,7 @@ const printUsage = (_, actionArr) => {
|
|
|
70
95
|
name: 'install',
|
|
71
96
|
summary: 'Vendor libdragon as is.',
|
|
72
97
|
group: ['docker'],
|
|
73
|
-
description: `Attempts to build and install everything libdragon related into the container. This includes all the tools and third parties used by libdragon except for the toolchain. If you have made changes to libdragon, you can execute this action to build everything based on your changes. Requires you to have an intact
|
|
98
|
+
description: `Attempts to build and install everything libdragon related into the container. This includes all the tools and third parties used by libdragon except for the toolchain. If you have made changes to libdragon, you can execute this action to build everything based on your changes. Requires you to have an intact vendoring target (also see the \`--directory\` flag). If you are not working on libdragon itself, you can just use the \`update\` action instead.
|
|
74
99
|
|
|
75
100
|
This can be useful to recover from a half-baked container.`,
|
|
76
101
|
},
|
|
@@ -78,7 +103,7 @@ const printUsage = (_, actionArr) => {
|
|
|
78
103
|
name: 'update',
|
|
79
104
|
summary: 'Update libdragon and do an install.',
|
|
80
105
|
description:
|
|
81
|
-
'
|
|
106
|
+
'If you are using auto-vendoring (see `--strategy`), this action will update the submodule/subtree from the remote branch (`trunk`) with a merge/squash strategy and then perform a `libdragon install`. This is the same as an `install` when the vendoring strategy is `manual`. You can use the `install` action to only update all libdragon related artifacts in the container.',
|
|
82
107
|
group: ['docker'],
|
|
83
108
|
},
|
|
84
109
|
};
|
|
@@ -125,5 +150,8 @@ const printUsage = (_, actionArr) => {
|
|
|
125
150
|
};
|
|
126
151
|
|
|
127
152
|
module.exports = {
|
|
128
|
-
|
|
153
|
+
name: 'help',
|
|
154
|
+
fn: printUsage,
|
|
155
|
+
showStatus: true,
|
|
156
|
+
forwardsRestParams: true,
|
|
129
157
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const { spawnProcess } = require('../helpers');
|
|
2
|
+
const { checkContainerRunning } = require('./utils');
|
|
3
|
+
|
|
4
|
+
const { fn: exec } = require('./exec');
|
|
5
|
+
|
|
6
|
+
const stop = async (libdragonInfo) => {
|
|
7
|
+
const running =
|
|
8
|
+
libdragonInfo.containerId &&
|
|
9
|
+
(await checkContainerRunning(libdragonInfo.containerId));
|
|
10
|
+
if (!running) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
await spawnProcess('docker', ['container', 'stop', running]);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const make = async (libdragonInfo, params) => {
|
|
18
|
+
await exec(libdragonInfo, ['make', ...params]);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// TODO: separate into files
|
|
22
|
+
module.exports = {
|
|
23
|
+
start: require('./start'),
|
|
24
|
+
stop: {
|
|
25
|
+
name: 'stop',
|
|
26
|
+
fn: stop,
|
|
27
|
+
showStatus: false, // This will only print out the id
|
|
28
|
+
},
|
|
29
|
+
init: require('./init'),
|
|
30
|
+
|
|
31
|
+
exec: require('./exec'),
|
|
32
|
+
make: {
|
|
33
|
+
name: 'make',
|
|
34
|
+
fn: make,
|
|
35
|
+
forwardsRestParams: true,
|
|
36
|
+
showStatus: true,
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
install: require('./install'),
|
|
40
|
+
update: require('./update'),
|
|
41
|
+
|
|
42
|
+
help: require('./help'),
|
|
43
|
+
};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const fs = require('fs/promises');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
|
|
6
|
+
const { fn: install } = require('./install');
|
|
7
|
+
const { fn: start } = require('./start');
|
|
8
|
+
const {
|
|
9
|
+
installDependencies,
|
|
10
|
+
tryCacheContainerId,
|
|
11
|
+
updateImage,
|
|
12
|
+
runGitMaybeHost,
|
|
13
|
+
} = require('./utils');
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
LIBDRAGON_PROJECT_MANIFEST,
|
|
17
|
+
LIBDRAGON_SUBMODULE,
|
|
18
|
+
LIBDRAGON_BRANCH,
|
|
19
|
+
LIBDRAGON_GIT,
|
|
20
|
+
} = require('../constants');
|
|
21
|
+
const {
|
|
22
|
+
log,
|
|
23
|
+
copyDirContents,
|
|
24
|
+
CommandError,
|
|
25
|
+
ParameterError,
|
|
26
|
+
} = require('../helpers');
|
|
27
|
+
const { setProjectInfoToSave } = require('../project-info');
|
|
28
|
+
|
|
29
|
+
const autoVendor = async (libdragonInfo) => {
|
|
30
|
+
await runGitMaybeHost(libdragonInfo, ['init']);
|
|
31
|
+
|
|
32
|
+
if (libdragonInfo.vendorStrategy === 'submodule') {
|
|
33
|
+
await runGitMaybeHost(libdragonInfo, [
|
|
34
|
+
'submodule',
|
|
35
|
+
'add',
|
|
36
|
+
'--force',
|
|
37
|
+
'--name',
|
|
38
|
+
LIBDRAGON_SUBMODULE,
|
|
39
|
+
'--branch',
|
|
40
|
+
LIBDRAGON_BRANCH,
|
|
41
|
+
LIBDRAGON_GIT,
|
|
42
|
+
libdragonInfo.vendorDirectory,
|
|
43
|
+
]);
|
|
44
|
+
} else if (libdragonInfo.vendorStrategy === 'subtree') {
|
|
45
|
+
// Create a commit if it does not exist. This is required for subtree.
|
|
46
|
+
try {
|
|
47
|
+
await runGitMaybeHost(libdragonInfo, ['rev-parse', 'HEAD']);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
if (!(e instanceof CommandError)) throw e;
|
|
50
|
+
|
|
51
|
+
// This will throw if git user name/email is not set up. Let's not assume
|
|
52
|
+
// anything for now. This means subtree is not supported for someone without
|
|
53
|
+
// git on the host machine.
|
|
54
|
+
await runGitMaybeHost(libdragonInfo, [
|
|
55
|
+
'commit',
|
|
56
|
+
'--allow-empty',
|
|
57
|
+
'-n',
|
|
58
|
+
'-m',
|
|
59
|
+
'Initial commit.',
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await runGitMaybeHost(libdragonInfo, [
|
|
64
|
+
'subtree',
|
|
65
|
+
'add',
|
|
66
|
+
'--prefix',
|
|
67
|
+
path.relative(libdragonInfo.root, libdragonInfo.vendorDirectory),
|
|
68
|
+
LIBDRAGON_GIT,
|
|
69
|
+
LIBDRAGON_BRANCH,
|
|
70
|
+
'--squash',
|
|
71
|
+
]);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return libdragonInfo;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Initialize a new libdragon project in current working directory
|
|
79
|
+
* Also downloads the image
|
|
80
|
+
*/
|
|
81
|
+
async function init(libdragonInfo) {
|
|
82
|
+
log(`Initializing a libdragon project at ${libdragonInfo.root}`);
|
|
83
|
+
|
|
84
|
+
// TODO: use exists instead & check if it is a directory
|
|
85
|
+
const files = await fs.readdir(libdragonInfo.root);
|
|
86
|
+
|
|
87
|
+
const manifestFile = files.find(
|
|
88
|
+
(name) => name === LIBDRAGON_PROJECT_MANIFEST
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
let newInfo = libdragonInfo;
|
|
92
|
+
|
|
93
|
+
// Validate vendoring strategy. Do not allow a switch after successful initialization
|
|
94
|
+
if (
|
|
95
|
+
manifestFile &&
|
|
96
|
+
newInfo.options.VENDOR_STRAT &&
|
|
97
|
+
newInfo.options.VENDOR_STRAT !== 'manual' &&
|
|
98
|
+
newInfo.vendorStrategy !== newInfo.options.VENDOR_STRAT
|
|
99
|
+
) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`Requested strategy switch: ${newInfo.vendorStrategy} -> ${newInfo.options.VENDOR_STRAT} It is not possible to switch vendoring strategy after initializing a project. You can always switch to manual and handle libdragon yourself.`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Update the strategy information for the project if the flag is provided
|
|
106
|
+
if (newInfo.options.VENDOR_STRAT) {
|
|
107
|
+
newInfo = setProjectInfoToSave({
|
|
108
|
+
...newInfo,
|
|
109
|
+
vendorStrategy: newInfo.options.VENDOR_STRAT,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Update the directory information for the project if the flag is provided
|
|
114
|
+
if (newInfo.options.VENDOR_DIR) {
|
|
115
|
+
// Validate vendoring path
|
|
116
|
+
if (path.isAbsolute(newInfo.options.VENDOR_DIR)) {
|
|
117
|
+
throw new ParameterError(
|
|
118
|
+
'`--directory` must be project-relative as it will be mounted to the docker container.'
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
newInfo = setProjectInfoToSave({
|
|
123
|
+
...newInfo,
|
|
124
|
+
vendorDirectory: newInfo.options.VENDOR_DIR,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (manifestFile) {
|
|
129
|
+
log(
|
|
130
|
+
`${path.join(
|
|
131
|
+
newInfo.root,
|
|
132
|
+
manifestFile
|
|
133
|
+
)} exists. This is already a libdragon project, starting it...`
|
|
134
|
+
);
|
|
135
|
+
if (newInfo.options.DOCKER_IMAGE) {
|
|
136
|
+
log(
|
|
137
|
+
`Not changing docker image. Use the install action if you want to override the image.`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
await install(newInfo);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
newInfo.imageName =
|
|
145
|
+
(await updateImage(newInfo, newInfo.imageName)) || newInfo.imageName;
|
|
146
|
+
// Download image and start it
|
|
147
|
+
const containerReadyPromise = start(newInfo).then((newId) => ({
|
|
148
|
+
...newInfo,
|
|
149
|
+
containerId: newId,
|
|
150
|
+
}));
|
|
151
|
+
|
|
152
|
+
let vendorAndGitReadyPromise = containerReadyPromise;
|
|
153
|
+
if (newInfo.vendorStrategy !== 'manual') {
|
|
154
|
+
const libdragonFile = files.find((name) =>
|
|
155
|
+
name.match(
|
|
156
|
+
new RegExp(`^${path.relative(newInfo.root, newInfo.vendorDirectory)}$`)
|
|
157
|
+
)
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
if (libdragonFile) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`${path.join(
|
|
163
|
+
newInfo.root,
|
|
164
|
+
libdragonFile
|
|
165
|
+
)} already exists. That is the libdragon vendoring target, please remove and retry.`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
vendorAndGitReadyPromise = containerReadyPromise.then(autoVendor);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
log(`Preparing project files...`);
|
|
173
|
+
const skeletonFolder = path.join(__dirname, '../../skeleton');
|
|
174
|
+
|
|
175
|
+
await Promise.all([
|
|
176
|
+
// We have created a new container, save the new info
|
|
177
|
+
vendorAndGitReadyPromise.then(tryCacheContainerId),
|
|
178
|
+
vendorAndGitReadyPromise.then(installDependencies),
|
|
179
|
+
// node copy functions does not work with pkg
|
|
180
|
+
copyDirContents(skeletonFolder, newInfo.root),
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
log(chalk.green(`libdragon ready at \`${newInfo.root}\`.`));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = {
|
|
187
|
+
name: 'init',
|
|
188
|
+
fn: init,
|
|
189
|
+
showStatus: true,
|
|
190
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const { log } = require('../helpers');
|
|
2
|
+
const {
|
|
3
|
+
destroyContainer,
|
|
4
|
+
installDependencies,
|
|
5
|
+
updateImage,
|
|
6
|
+
} = require('./utils');
|
|
7
|
+
const { fn: start } = require('./start');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Updates the image if flag is provided and install vendors onto the container.
|
|
11
|
+
* We should probably remove the image installation responsibility from this
|
|
12
|
+
* action but it might be a breaking change. Maybe we can keep it backward
|
|
13
|
+
* compatible with additional flags.
|
|
14
|
+
* @param libdragonInfo
|
|
15
|
+
*/
|
|
16
|
+
const install = async (libdragonInfo) => {
|
|
17
|
+
let containerId;
|
|
18
|
+
const oldImageName = libdragonInfo.imageName;
|
|
19
|
+
const imageName = libdragonInfo.options.DOCKER_IMAGE;
|
|
20
|
+
// If an image is provided, always attempt to install it
|
|
21
|
+
// See https://github.com/anacierdem/libdragon-docker/issues/47
|
|
22
|
+
if (imageName) {
|
|
23
|
+
log(`Changing image from \`${oldImageName}\` to \`${imageName}\``);
|
|
24
|
+
|
|
25
|
+
// Download the new image and if it is different, re-create the container
|
|
26
|
+
if (await updateImage(libdragonInfo, imageName)) {
|
|
27
|
+
await destroyContainer(libdragonInfo);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
containerId = await start({
|
|
31
|
+
...libdragonInfo,
|
|
32
|
+
imageName,
|
|
33
|
+
});
|
|
34
|
+
} else {
|
|
35
|
+
// Make sure existing one is running
|
|
36
|
+
containerId = await start(libdragonInfo);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Re-install vendors on new image
|
|
40
|
+
// TODO: skip this if unnecessary
|
|
41
|
+
await installDependencies({
|
|
42
|
+
...libdragonInfo,
|
|
43
|
+
imageName,
|
|
44
|
+
containerId,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
name: 'install',
|
|
50
|
+
fn: install,
|
|
51
|
+
showStatus: true,
|
|
52
|
+
};
|