libdragon 10.7.1 → 10.8.1

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/README.md CHANGED
@@ -2,11 +2,64 @@
2
2
 
3
3
  [![Build](https://github.com/anacierdem/libdragon-docker/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/anacierdem/libdragon-docker/actions/workflows/ci.yml)
4
4
 
5
- This is a wrapper for a docker container to make managing the libdragon toolchain easier.
5
+ This is a wrapper for a docker container to make managing the libdragon toolchain easier. It has the additional advantage that libdragon toolchain and library can be installed on a per-project basis instead of managing system-wide installations.
6
6
 
7
- ## Quick Install
7
+ ## Prerequisites
8
8
 
9
- On a system with [docker](https://www.docker.com/products/docker-desktop) (`>= 18`), grab a [pre-built executable](https://github.com/anacierdem/libdragon-docker/releases/latest) and put it somewhere on your PATH. Then navigate to the folder you want to initialize your project and invoke libdragon;
9
+ You should have [docker](https://www.docker.com/products/docker-desktop) (`>= 18`) installed on your system.
10
+
11
+ `git` is not strictly required to use the tool. Still, it is highly recommended to have git on your host machine as it will be used instead of the one in the container.
12
+
13
+ ## Installation
14
+
15
+ This is primarily a node.js script which is also packaged as an executable. You have two options:
16
+
17
+ ### pre-built
18
+
19
+ Download the [pre-built executable](https://github.com/anacierdem/libdragon-docker/releases/latest) for your system and put it somewhere on your PATH. It is discouraged to put it in your project folder.
20
+
21
+ <details>
22
+ <summary>Windows instructions</summary>
23
+
24
+ - Download the Windows executable and copy it to `C:\bin`
25
+ - Press `Windows + R` key combination and then enter `rundll32 sysdm.cpl,EditEnvironmentVariables`
26
+ - In the `Environment Variables` window find the `Path` variable under `User variables for <your user name>`
27
+ - Double click it and add a new entry as `C:\bin`
28
+ - Restart your computer.
29
+ - You should now be able to use the `libdragon` on a command line or PowerShell.
30
+ - To update it with a new version, just replace the file in `C:\bin`
31
+
32
+ </details>
33
+
34
+ <details>
35
+ <summary>MacOS instructions</summary>
36
+
37
+ - Download the MacOS executable and copy it to `/usr/local/bin`
38
+ - Right click it and choose `Open`.
39
+ - It will show a warning, approve it by clicking `Open` again. You can close the newly opened terminal window.
40
+ - You should now be able to use the `libdragon` command.
41
+ - To update it with a new version, replace the file in `/usr/local/bin` and repeat the other steps.
42
+
43
+ </details>
44
+
45
+ <details>
46
+ <summary>Linux instructions</summary>
47
+
48
+ - You should already know this :)
49
+
50
+ </details>
51
+
52
+ ### via NPM
53
+
54
+ Install [node.js](https://nodejs.org/en/download/) (`>= 14`) and install `libdragon` as a global NPM package;
55
+
56
+ npm install -g libdragon
57
+
58
+ To update the tool to the latest, do `npm i -g libdragon@latest`.
59
+
60
+ ## Quick Guide
61
+
62
+ Navigate to the folder you want to initialize your project and invoke libdragon;
10
63
 
11
64
  libdragon init
12
65
 
@@ -22,21 +75,60 @@ To update the library and rebuild/install all the artifacts;
22
75
 
23
76
  libdragon update
24
77
 
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.
78
+ In general, you can invoke libdragon as follows;
26
79
 
27
- ## Overall usage
80
+ libdragon [flags] <action>
28
81
 
29
- This is primarily a node.js script which is also packaged as an executable. If you have [node.js](https://nodejs.org/en/download/) (`>= 14`), you can do a global install and use it as usual. To install `libdragon` as a global NPM package;
82
+ Run `libdragon help [action]` for more details on individual actions.
30
83
 
31
- npm install -g libdragon
84
+ ## Recipes
32
85
 
33
- To update the tool to the latest, do `npm i -g libdragon@latest`.
86
+ ### Using a different branch of libdragon
34
87
 
35
- You can invoke libdragon as follows;
88
+ Initialize your project as usual:
36
89
 
37
- libdragon [flags] <action>
90
+ libdragon init
38
91
 
39
- Run `libdragon help [action]` for more details on individual actions.
92
+ Then switch the submodule to the desired branch:
93
+
94
+ cd ./libdragon
95
+ git checkout opengl
96
+ cd ..
97
+ libdragon install
98
+
99
+ If your changes are on a different remote, then you will need to manage your git remotes as usual.
100
+
101
+ ### Testing changes on libdragon
102
+
103
+ As libdragon is an actively developed library, you may find yourself at a position where you want to change a few things on it and see how it works. In general, if you modify the files in `libdragon` folder of your project, you can install that version to the docker container by simply running:
104
+
105
+ libdragon install
106
+
107
+ This will update all the artifacts in your container and your new code will start linking against the new version when you re-build it via `libdragon make`. The build system should pick up the change in the library and re-compile the dependent files.
108
+
109
+ Instead of depending on the above command, you can re-build the library by making it a make dependency in your project:
110
+
111
+ ```makefile
112
+ libdragon-install: libdragon
113
+ $(MAKE) -C ./libdragon install
114
+
115
+ libdragon:
116
+ $(MAKE) -C ./libdragon
117
+ ```
118
+
119
+ If your build now depends on `libdragon-install`, it will force an install (which should be pretty quick if you don't have changes) and force the build system to rebuild your project when necessary.
120
+
121
+ If you clone this repository, this setup is pretty much ready for you. Make sure you have a working libdragon setup and you get the submodules (e.g `git submodule update --init`). Then you can run `libdragon make bench` to execute the code in `./src` with your library changes. Also see [test bench](#local-test-bench).
122
+
123
+ When managing your changes to the library, you have a few options:
124
+
125
+ #### **Using `submodule` vendor strategy.**
126
+
127
+ To be able to share your project with the library change, you would need to push it somewhere public and make sure it is cloned properly by your contributors. This is not recommended for keeping track of your changes but is very useful if you plan to contribute it back to upstream. In the latter case, you can push your submodule branch to your fork and easily open a PR.
128
+
129
+ #### **Using `subtree` vendor strategy.**
130
+
131
+ To be able to share your project with the library change, you just commit your changes. This is very useful for keeping track of your changes specific to your project. On the other hand this is not recommended if you plan to contribute it back to upstream because you will need to make sure your libdragon commits are isolated and do the juggling when pushing it somewhere via `git subtree push`.
40
132
 
41
133
  ## Working on this repository
42
134
 
@@ -86,15 +178,40 @@ This repository also uses [ed64](https://github.com/anacierdem/ed64), so you can
86
178
 
87
179
  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`).
88
180
 
181
+ ### Developing the tool itself
182
+
183
+ For a quick development loop it really helps linking the code in this repository as the global libdragon installation. To do this run;
184
+
185
+ npm link
186
+
187
+ in the root of the repository. Once you do this, running `libdragon` will use the code here rather than the actual npm installation. Then you can test your changes in the libdragon project here or elsewhere on your computer.
188
+
189
+ When you are happy with your changes, you can verify you conform to the coding standards via:
190
+
191
+ npm run format-check
192
+ npm run lint-check
193
+
194
+ You can auto-fix applicable errors by running `format` and `lint` scripts instead. Additionally, typescript is used as the type system. To be able to get away with transpiling the code during development, jsDoc flavor of types are used instead of inline ones. To check if your types, run:
195
+
196
+ npm run tsc
197
+
198
+ This repository uses [`semantic-release`](https://github.com/semantic-release/semantic-release) and manages releases from specially formatted commit messages. To simplify creating them you can use:
199
+
200
+ npx cz
201
+
202
+ It will create a `semantic-release` compatible commit from your current staged changes.
203
+
89
204
  ## As an NPM dependency
90
205
 
91
206
  You can install libdragon as an NPM dependency by `npm install libdragon --save` in order to use docker in your N64 projects. A `libdragon` command similar to global intallation is provided that can be used in your NPM scripts as follows;
92
207
 
93
- "scripts": {
94
- "prepare": "libdragon init"
95
- "build": "libdragon make",
96
- "clean": "libdragon make clean"
97
- }
208
+ ```json
209
+ "scripts": {
210
+ "prepare": "libdragon init"
211
+ "build": "libdragon make",
212
+ "clean": "libdragon make clean"
213
+ }
214
+ ```
98
215
 
99
216
  See [here](https://github.com/anacierdem/ed64-example) for a full example.
100
217
 
@@ -104,25 +221,32 @@ You can make an NPM package that a `libdragon` project can depend on. Just inclu
104
221
 
105
222
  For example this `package.json` in the dependent project;
106
223
 
107
- {
108
- "name": "libdragonDependentProject",
109
- "version": "1.0.0",
110
- "description": "...",
111
- "scripts": {
112
- "build": "libdragon make",
113
- "clean": "libdragon make clean",
114
- "prepare": "libdragon init"
115
- },
116
- "dependencies": {
117
- "libdragon": <version>,
118
- "ed64": <version>
119
- }
224
+ ```json
225
+ {
226
+ "name": "libdragonDependentProject",
227
+ "version": "1.0.0",
228
+ "description": "...",
229
+ "scripts": {
230
+ "build": "libdragon make",
231
+ "clean": "libdragon make clean",
232
+ "prepare": "libdragon init"
233
+ },
234
+ "dependencies": {
235
+ "libdragon": <version>,
236
+ "ed64": <version>
120
237
  }
238
+ }
239
+ ```
121
240
 
122
241
  will init the container for this project and run `make && make install` for `ed64` upon running `npm install`. To develop a dependency [this](https://github.com/anacierdem/libdragon-dependency) is a good starting point.
123
242
 
124
243
  This is an experimental dependency management.
125
244
 
245
+ ## TODOS
246
+
247
+ - [ ] Skip CI checks for irrelevant changes.
248
+ - [ ] Verify the NPM dependency mechanism is still working and add a test.
249
+
126
250
  ## Funding
127
251
 
128
252
  If this tool helped you, consider supporting its development by sponsoring it!
package/index.js CHANGED
File without changes
@@ -6,6 +6,9 @@ const { CONFIG_FILE, LIBDRAGON_PROJECT_MANIFEST } = require('../constants');
6
6
  const { fileExists, dirExists, log } = require('../helpers');
7
7
  const chalk = require('chalk');
8
8
 
9
+ /**
10
+ * @param {import('../project-info').LibdragonInfo} libdragonInfo
11
+ */
9
12
  const destroy = async (libdragonInfo) => {
10
13
  await destroyContainer(libdragonInfo);
11
14
 
@@ -22,13 +25,13 @@ const destroy = async (libdragonInfo) => {
22
25
  log(chalk.green('Done cleanup.'));
23
26
  };
24
27
 
25
- module.exports = {
28
+ module.exports = /** @type {const} */ ({
26
29
  name: 'destroy',
27
30
  fn: destroy,
28
- mustHaveProject: false,
31
+ forwardsRestParams: false,
29
32
  usage: {
30
33
  name: 'destroy',
31
34
  summary: 'Do clean-up for current project.',
32
35
  description: `Removes libdragon configuration from current project and removes any known containers but will not touch previously vendored files. \`libdragon\` will not work anymore for this project.`,
33
36
  },
34
- };
37
+ });
@@ -10,6 +10,11 @@ const {
10
10
  ParameterError,
11
11
  } = require('../helpers');
12
12
 
13
+ /**
14
+ * @param {string} stop
15
+ * @param {string} start
16
+ * @return {Promise<string>}
17
+ */
13
18
  const findElf = async (stop, start = '.') => {
14
19
  start = path.resolve(start);
15
20
 
@@ -43,6 +48,9 @@ const findElf = async (stop, start = '.') => {
43
48
  }
44
49
  };
45
50
 
51
+ /**
52
+ * @param {import('../project-info').LibdragonInfo} info
53
+ */
46
54
  const disasm = async (info) => {
47
55
  let elfPath;
48
56
  if (info.options.FILE) {
@@ -89,7 +97,7 @@ const disasm = async (info) => {
89
97
  });
90
98
  };
91
99
 
92
- module.exports = {
100
+ module.exports = /** @type {const} */ ({
93
101
  name: 'disasm',
94
102
  fn: disasm,
95
103
  forwardsRestParams: true,
@@ -118,4 +126,4 @@ module.exports = {
118
126
  },
119
127
  ],
120
128
  },
121
- };
129
+ });
@@ -1,3 +1,8 @@
1
+ /**
2
+ *
3
+ * @param {import('../project-info').LibdragonInfo} libdragonInfo
4
+ * @returns
5
+ */
1
6
  function dockerHostUserParams(libdragonInfo) {
2
7
  const { uid, gid } = libdragonInfo.userInfo;
3
8
  return ['-u', `${uid >= 0 ? uid : ''}:${gid >= 0 ? gid : ''}`];
@@ -14,6 +14,10 @@ const { start } = require('./start');
14
14
  const { dockerHostUserParams } = require('./docker-utils');
15
15
  const { installDependencies } = require('./utils');
16
16
 
17
+ /**
18
+ * @param {import('../project-info').LibdragonInfo} libdragonInfo
19
+ * @returns
20
+ */
17
21
  function dockerRelativeWorkdir(libdragonInfo) {
18
22
  return (
19
23
  CONTAINER_TARGET_PATH +
@@ -22,10 +26,20 @@ function dockerRelativeWorkdir(libdragonInfo) {
22
26
  );
23
27
  }
24
28
 
29
+ /**
30
+ *
31
+ * @param {import('../project-info').LibdragonInfo} libdragonInfo
32
+ * @returns
33
+ */
25
34
  function dockerRelativeWorkdirParams(libdragonInfo) {
26
35
  return ['--workdir', dockerRelativeWorkdir(libdragonInfo)];
27
36
  }
28
37
 
38
+ /**
39
+ *
40
+ * @param {import('../project-info').LibdragonInfo} info
41
+ * @returns
42
+ */
29
43
  const exec = async (info) => {
30
44
  const parameters = info.options.EXTRA_PARAMS.slice(1);
31
45
  log(
@@ -37,6 +51,7 @@ const exec = async (info) => {
37
51
 
38
52
  const stdin = new PassThrough();
39
53
 
54
+ /** @type {string[]} */
40
55
  const paramsWithConvertedPaths = parameters.map((item) => {
41
56
  if (item.startsWith('-')) {
42
57
  return item;
@@ -49,9 +64,14 @@ const exec = async (info) => {
49
64
  return item;
50
65
  });
51
66
 
67
+ /**
68
+ *
69
+ * @param {import('../project-info').LibdragonInfo} libdragonInfo
70
+ * @param {import('../helpers').SpawnOptions} opts
71
+ * @returns
72
+ */
52
73
  const tryCmd = (libdragonInfo, opts = {}) => {
53
74
  const enableTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);
54
-
55
75
  return (
56
76
  libdragonInfo.containerId &&
57
77
  dockerExec(
@@ -80,6 +100,11 @@ const exec = async (info) => {
80
100
  };
81
101
 
82
102
  let started = false;
103
+ /**
104
+ *
105
+ * @param {import('fs').ReadStream=} stdin
106
+ * @returns
107
+ */
83
108
  const startOnceAndCmd = async (stdin) => {
84
109
  if (!started) {
85
110
  const newId = await start(info);
@@ -121,7 +146,11 @@ const exec = async (info) => {
121
146
  inheritStderr: false,
122
147
  // In the first run, pass the stdin to the process if it is not a TTY
123
148
  // o/w we loose a user input unnecesarily somehow.
124
- stdin: !process.stdin.isTTY && process.stdin,
149
+ stdin:
150
+ !process.stdin.isTTY &&
151
+ /** @type {import('fs').ReadStream} */ (
152
+ /** @type {unknown} */ (process.stdin)
153
+ ),
125
154
  });
126
155
  } catch (e) {
127
156
  if (
@@ -131,12 +160,14 @@ const exec = async (info) => {
131
160
  ) {
132
161
  throw e;
133
162
  }
134
- await startOnceAndCmd(stdin);
163
+ await startOnceAndCmd(
164
+ /** @type {import('fs').ReadStream} */ (/** @type {unknown} */ (stdin))
165
+ );
135
166
  }
136
167
  return info;
137
168
  };
138
169
 
139
- module.exports = {
170
+ module.exports = /** @type {const} */ ({
140
171
  name: 'exec',
141
172
  fn: exec,
142
173
  forwardsRestParams: true,
@@ -152,4 +183,4 @@ module.exports = {
152
183
 
153
184
  Must be run in an initialized libdragon project.`,
154
185
  },
155
- };
186
+ });
@@ -3,7 +3,10 @@ const commandLineUsage = require('command-line-usage');
3
3
 
4
4
  const { print } = require('../helpers');
5
5
 
6
- const printUsage = (info) => {
6
+ /**
7
+ * @param {import('../project-info').CLIInfo} info
8
+ */
9
+ const printUsage = async (info) => {
7
10
  const actions = require('./');
8
11
  const globalOptionDefinitions = [
9
12
  {
@@ -39,7 +42,7 @@ const printUsage = (info) => {
39
42
 
40
43
  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
44
 
42
- You can always switch to manual by re-running \`init\` with \`--strategy manual\`, though you will be responsible for managing the existing submodule/subtree. Also it is not possible to automatically switch back.
45
+ You can always switch strategy by re-running \`init\` with \`--strategy\`, though you will be responsible for handling the old vendored files as they will be kept as is.
43
46
 
44
47
  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.\n`,
45
48
  alias: 's',
@@ -48,11 +51,12 @@ const printUsage = (info) => {
48
51
  },
49
52
  ];
50
53
 
51
- const actionsToShow =
54
+ const actionsToShow = /** @type {(keyof actions)[]} */ (
52
55
  info?.options.EXTRA_PARAMS?.filter(
53
56
  (action) =>
54
57
  Object.keys(actions).includes(action) && !['help'].includes(action)
55
- ) ?? (info ? [info.options.CURRENT_ACTION.name] : []);
58
+ ) ?? (info ? [info.options.CURRENT_ACTION.name] : [])
59
+ );
56
60
 
57
61
  const sections = [
58
62
  {
@@ -96,13 +100,12 @@ const printUsage = (info) => {
96
100
  print(usage);
97
101
  };
98
102
 
99
- module.exports = {
103
+ module.exports = /** @type {const} */ ({
100
104
  name: 'help',
101
105
  fn: printUsage,
102
106
  forwardsRestParams: true,
103
- mustHaveProject: false,
104
107
  usage: {
105
108
  name: 'help [action]',
106
109
  summary: 'Display this help information or details for the given action.',
107
110
  },
108
- };
111
+ });