modpack-lock 0.1.0 → 0.1.2
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 +16 -12
- package/index.js +116 -14
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -41,6 +41,13 @@ Navigate to your Minecraft profile directory (the folder containing `mods`, `res
|
|
|
41
41
|
modpack-lock
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
Flags:
|
|
45
|
+
|
|
46
|
+
- `--dry-run` or `-d`: Print the files that would be scanned, but don't actually scan them
|
|
47
|
+
- `--quiet` or `-q`: Print only errors and warnings
|
|
48
|
+
- `--silent` or `-s`: Print nothing
|
|
49
|
+
- `--gitignore` or `-g`: Print the rules to add to your `.gitignore` file
|
|
50
|
+
|
|
44
51
|
The script will:
|
|
45
52
|
|
|
46
53
|
1. Scan the `mods`, `resourcepacks`, `datapacks`, and `shaderpacks` directories for `.jar` and `.zip` files
|
|
@@ -51,6 +58,7 @@ The script will:
|
|
|
51
58
|
Then, commit the `modpack.lock` file to your repository and push it to your remote.
|
|
52
59
|
|
|
53
60
|
> [!TIP]
|
|
61
|
+
>
|
|
54
62
|
> You can run this script as a pre-commit hook to ensure that the modpack lockfile is up to date before committing your changes to your repository.
|
|
55
63
|
>
|
|
56
64
|
> Also, consider adding these rules to your `.gitignore` to ensure you don't commit the modpack contents to your repository, with exceptions for any files that are not Modrinth-hosted:
|
|
@@ -71,8 +79,15 @@ The `modpack.lock` file has the following structure:
|
|
|
71
79
|
|
|
72
80
|
```json
|
|
73
81
|
{
|
|
74
|
-
"version": "1.0.
|
|
82
|
+
"version": "1.0.1",
|
|
75
83
|
"generated": "2026-01-06T03:00:00.000Z",
|
|
84
|
+
"total": 7,
|
|
85
|
+
"counts": {
|
|
86
|
+
"mods": 1,
|
|
87
|
+
"resourcepacks": 3,
|
|
88
|
+
"datapacks": 1,
|
|
89
|
+
"shaderpacks": 2
|
|
90
|
+
},
|
|
76
91
|
"dependencies": {
|
|
77
92
|
"mods": [
|
|
78
93
|
{
|
|
@@ -87,17 +102,6 @@ The `modpack.lock` file has the following structure:
|
|
|
87
102
|
}
|
|
88
103
|
```
|
|
89
104
|
|
|
90
|
-
## Future Plans
|
|
91
|
-
|
|
92
|
-
- [ ] Add support for CurseForge
|
|
93
|
-
- [ ] Add support for restoring modpack contents using the lockfile
|
|
94
|
-
- [ ] Add CLI option for dry-run
|
|
95
|
-
- [ ] Add CLI option for verbose output
|
|
96
|
-
- [ ] Add CLI option for quiet output
|
|
97
|
-
- [ ] Add CLI option for printout of rules to add to .gitignore (the files that are not hosted)
|
|
98
|
-
|
|
99
|
-
Feel free to submit a pull request working on any of the above, or open an issue for any feature requests or bug reports.
|
|
100
|
-
|
|
101
105
|
## License
|
|
102
106
|
|
|
103
107
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for more details.
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import fs from 'fs/promises';
|
|
|
4
4
|
import crypto from 'crypto';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
|
|
7
|
-
const LOCKFILE_VERSION = '1.0.
|
|
7
|
+
const LOCKFILE_VERSION = '1.0.1';
|
|
8
8
|
const MODPACK_LOCKFILE_NAME = 'modpack.lock';
|
|
9
9
|
const MODRINTH_API_BASE = 'https://api.modrinth.com/v2';
|
|
10
10
|
const MODRINTH_VERSION_FILES_ENDPOINT = `${MODRINTH_API_BASE}/version_files`;
|
|
@@ -12,6 +12,39 @@ const MODRINTH_VERSION_FILES_ENDPOINT = `${MODRINTH_API_BASE}/version_files`;
|
|
|
12
12
|
// Get the workspace root from the current working directory
|
|
13
13
|
const WORKSPACE_ROOT = process.cwd();
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Parse command-line arguments
|
|
17
|
+
*/
|
|
18
|
+
function parseArgs() {
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
return {
|
|
21
|
+
dryRun: args.includes('--dry-run') || args.includes('-d'),
|
|
22
|
+
quiet: args.includes('--quiet') || args.includes('-q'),
|
|
23
|
+
silent: args.includes('--silent') || args.includes('-s'),
|
|
24
|
+
gitignore: args.includes('--gitignore') || args.includes('-g'),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a logger function that respects quiet mode
|
|
30
|
+
*/
|
|
31
|
+
function createLogger(quiet) {
|
|
32
|
+
if (quiet) {
|
|
33
|
+
return () => {}; // No-op function when quiet
|
|
34
|
+
}
|
|
35
|
+
return (...args) => console.log(...args);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Silence all console.log output
|
|
40
|
+
*/
|
|
41
|
+
function silenceConsole() {
|
|
42
|
+
console.log = () => {};
|
|
43
|
+
console.warn = () => {};
|
|
44
|
+
console.error = () => {};
|
|
45
|
+
console.info = () => {};
|
|
46
|
+
}
|
|
47
|
+
|
|
15
48
|
const DIRECTORIES_TO_SCAN = [
|
|
16
49
|
{ name: 'mods', path: path.join(WORKSPACE_ROOT, 'mods') },
|
|
17
50
|
{ name: 'resourcepacks', path: path.join(WORKSPACE_ROOT, 'resourcepacks') },
|
|
@@ -118,6 +151,8 @@ function createEmptyLockfile() {
|
|
|
118
151
|
return {
|
|
119
152
|
version: LOCKFILE_VERSION,
|
|
120
153
|
generated: new Date().toISOString(),
|
|
154
|
+
total: 0,
|
|
155
|
+
counts: {},
|
|
121
156
|
dependencies: {},
|
|
122
157
|
};
|
|
123
158
|
}
|
|
@@ -146,42 +181,99 @@ function createLockfile(fileEntries, versionData) {
|
|
|
146
181
|
lockfile.dependencies[fileInfo.category].push(entry);
|
|
147
182
|
}
|
|
148
183
|
|
|
184
|
+
// Calculate counts for each category
|
|
185
|
+
for (const [category, entries] of Object.entries(lockfile.dependencies)) {
|
|
186
|
+
lockfile.counts[category] = entries.length;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Calculate total count
|
|
190
|
+
lockfile.total = fileEntries.length;
|
|
191
|
+
|
|
149
192
|
return lockfile;
|
|
150
193
|
}
|
|
151
194
|
|
|
152
195
|
/**
|
|
153
196
|
* Write lockfile to disk
|
|
154
197
|
*/
|
|
155
|
-
async function writeLockfile(lockfile, outputPath) {
|
|
198
|
+
async function writeLockfile(lockfile, outputPath, log) {
|
|
156
199
|
const content = JSON.stringify(lockfile, null, 2);
|
|
157
200
|
await fs.writeFile(outputPath, content, 'utf-8');
|
|
158
|
-
|
|
201
|
+
log(`Lockfile written to: ${outputPath}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Generate .gitignore rules for files not hosted on Modrinth
|
|
206
|
+
*/
|
|
207
|
+
function generateGitignoreRules(lockfile) {
|
|
208
|
+
const rules = [];
|
|
209
|
+
const exceptions = [];
|
|
210
|
+
|
|
211
|
+
// Base ignore patterns for each category
|
|
212
|
+
rules.push('mods/*.jar');
|
|
213
|
+
rules.push('resourcepacks/*.zip');
|
|
214
|
+
rules.push('datapacks/*.zip');
|
|
215
|
+
rules.push('shaderpacks/*.zip');
|
|
216
|
+
rules.push('');
|
|
217
|
+
rules.push('## Exceptions');
|
|
218
|
+
|
|
219
|
+
// Find files not hosted on Modrinth
|
|
220
|
+
for (const [category, entries] of Object.entries(lockfile.dependencies)) {
|
|
221
|
+
for (const entry of entries) {
|
|
222
|
+
if (entry.version === null) {
|
|
223
|
+
exceptions.push(`!${entry.path}`);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Add exceptions if any
|
|
229
|
+
if (exceptions.length > 0) {
|
|
230
|
+
rules.push(...exceptions);
|
|
231
|
+
} else {
|
|
232
|
+
rules.push('# No exceptions needed - all files are hosted on Modrinth');
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return rules.join('\n');
|
|
159
236
|
}
|
|
160
237
|
|
|
161
238
|
/**
|
|
162
239
|
* Main execution function
|
|
163
240
|
*/
|
|
164
241
|
async function main() {
|
|
165
|
-
|
|
242
|
+
const config = parseArgs();
|
|
243
|
+
const log = createLogger(config.quiet);
|
|
244
|
+
|
|
245
|
+
if (config.silent) {
|
|
246
|
+
silenceConsole();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (config.dryRun) {
|
|
250
|
+
log('[DRY RUN] Preview mode - no files will be written');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
log('Scanning directories for modpack files...');
|
|
166
254
|
|
|
167
255
|
// Scan all directories
|
|
168
256
|
const allFileEntries = [];
|
|
169
257
|
for (const dirInfo of DIRECTORIES_TO_SCAN) {
|
|
170
|
-
|
|
258
|
+
log(`Scanning ${dirInfo.name}...`);
|
|
171
259
|
const fileEntries = await scanDirectory(dirInfo);
|
|
172
|
-
|
|
260
|
+
log(` Found ${fileEntries.length} file(s)`);
|
|
173
261
|
allFileEntries.push(...fileEntries);
|
|
174
262
|
}
|
|
175
263
|
|
|
176
264
|
if (allFileEntries.length === 0) {
|
|
177
|
-
|
|
265
|
+
log('No files found. Creating empty lockfile.');
|
|
178
266
|
const outputPath = path.join(WORKSPACE_ROOT, MODPACK_LOCKFILE_NAME);
|
|
179
|
-
|
|
267
|
+
if (config.dryRun) {
|
|
268
|
+
log(`[DRY RUN] Would write lockfile to: ${outputPath}`);
|
|
269
|
+
} else {
|
|
270
|
+
await writeLockfile(createEmptyLockfile(), outputPath, log);
|
|
271
|
+
}
|
|
180
272
|
return;
|
|
181
273
|
}
|
|
182
274
|
|
|
183
|
-
|
|
184
|
-
|
|
275
|
+
log(`\nTotal files found: ${allFileEntries.length}`);
|
|
276
|
+
log('\nQuerying Modrinth API...');
|
|
185
277
|
|
|
186
278
|
// Extract all hashes
|
|
187
279
|
const hashes = allFileEntries.map(info => info.hash);
|
|
@@ -189,21 +281,31 @@ async function main() {
|
|
|
189
281
|
// Query Modrinth API
|
|
190
282
|
const versionData = await getVersionsFromHashes(hashes);
|
|
191
283
|
|
|
192
|
-
|
|
284
|
+
log(`\nFound version information for ${Object.keys(versionData).length} out of ${hashes.length} files`);
|
|
193
285
|
|
|
194
286
|
// Create lockfile
|
|
195
287
|
const lockfile = createLockfile(allFileEntries, versionData);
|
|
196
288
|
|
|
197
289
|
// Write lockfile
|
|
198
290
|
const outputPath = path.join(WORKSPACE_ROOT, MODPACK_LOCKFILE_NAME);
|
|
199
|
-
|
|
291
|
+
if (config.dryRun) {
|
|
292
|
+
log(`[DRY RUN] Would write lockfile to: ${outputPath}`);
|
|
293
|
+
} else {
|
|
294
|
+
await writeLockfile(lockfile, outputPath, log);
|
|
295
|
+
}
|
|
200
296
|
|
|
201
297
|
// Summary
|
|
202
|
-
|
|
298
|
+
log('\n=== Summary ===');
|
|
203
299
|
for (const [category, entries] of Object.entries(lockfile.dependencies)) {
|
|
204
300
|
const withVersion = entries.filter(e => e.version !== null).length;
|
|
205
301
|
const withoutVersion = entries.length - withVersion;
|
|
206
|
-
|
|
302
|
+
log(`${category}: ${entries.length} file(s) (${withVersion} found on Modrinth, ${withoutVersion} unknown)`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Generate .gitignore rules if requested
|
|
306
|
+
if (config.gitignore) {
|
|
307
|
+
log('\n=== .gitignore Rules ===');
|
|
308
|
+
log(generateGitignoreRules(lockfile));
|
|
207
309
|
}
|
|
208
310
|
}
|
|
209
311
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "modpack-lock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Create a modpack lockfile for files hosted on Modrinth (mods, resource packs, shaders and datapacks)",
|
|
5
|
-
"homepage": "https://github.com/nickesc/modpack-lock#readme",
|
|
6
5
|
"bugs": {
|
|
7
6
|
"url": "https://github.com/nickesc/modpack-lock/issues"
|
|
8
7
|
},
|