Skip to content

Commit b92ceaa

Browse files
committed
feat(spm): Copy plugins and rewrite Cordova dependency
1 parent 14e30aa commit b92ceaa

File tree

4 files changed

+101
-28
lines changed

4 files changed

+101
-28
lines changed

lib/Api.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,8 @@ class Api {
239239
.addPlugin(plugin, installOptions)
240240
.then(() => {
241241
if (plugin != null && isSwiftPackagePlugin(plugin)) {
242-
const packagePath = path.join(this.locations.root, 'CordovaPlugins', 'Package.swift');
243-
const spm = new SwiftPackage(packagePath);
244-
spm.addPlugin(plugin);
242+
const spm = new SwiftPackage(this.locations.root);
243+
spm.addPlugin(plugin, installOptions);
245244
}
246245
})
247246
.then(() => {
@@ -293,8 +292,7 @@ class Api {
293292
.removePlugin(plugin, uninstallOptions)
294293
.then(() => {
295294
if (plugin != null && isSwiftPackagePlugin(plugin)) {
296-
const packagePath = path.join(this.locations.root, 'CordovaPlugins', 'Package.swift');
297-
const spm = new SwiftPackage(packagePath);
295+
const spm = new SwiftPackage(this.locations.root);
298296
spm.removePlugin(plugin);
299297
}
300298
})

lib/SwiftPackage.js

+36-7
Original file line numberDiff line numberDiff line change
@@ -18,38 +18,67 @@
1818
*/
1919

2020
const fs = require('node:fs');
21+
const path = require('node:path');
2122
const CordovaError = require('cordova-common').CordovaError;
2223

2324
class SwiftPackage {
24-
constructor (packagePath) {
25-
this.path = packagePath;
25+
constructor (projectRoot) {
26+
this.root = projectRoot;
27+
this.path = path.join(this.root, 'CordovaPlugins', 'Package.swift');
2628

2729
if (!fs.existsSync(this.path)) {
2830
throw new CordovaError('Package.swift is not found.');
2931
}
3032
}
3133

32-
_pluginReference (plugin) {
34+
_pluginReference (plugin, opts = {}) {
35+
let pluginPath = path.relative(path.dirname(this.path), path.join(this.root, 'packages', plugin.id));
36+
if (opts.link) {
37+
pluginPath = path.relative(path.dirname(this.path), plugin.dir);
38+
}
39+
3340
return `
34-
package.dependencies.append(.package(name: "${plugin.id}", path: "../../../plugins/${plugin.id}"))
41+
package.dependencies.append(.package(name: "${plugin.id}", path: "${pluginPath.replaceAll(path.sep, path.posix.sep)}"))
3542
package.targets.first?.dependencies.append(.product(name: "${plugin.id}", package: "${plugin.id}"))
3643
`;
3744
}
3845

39-
addPlugin (plugin) {
46+
addPlugin (plugin, opts = {}) {
47+
if (!opts.link) {
48+
// Copy the plugin into the packages directory
49+
fs.cpSync(plugin.dir, path.join(this.root, 'packages', plugin.id), { recursive: true });
50+
51+
const pkgSwiftPath = path.join(this.root, 'packages', plugin.id, 'Package.swift');
52+
const pkg_fd = fs.openSync(pkgSwiftPath, 'r+');
53+
54+
let packageContent = fs.readFileSync(pkg_fd, 'utf8');
55+
packageContent = packageContent.replace(/\(.*url.+cordova-ios.+\)/gm, '(name: "cordova-ios", path: "../cordova-ios")');
56+
57+
fs.ftruncateSync(pkg_fd);
58+
fs.writeSync(pkg_fd, packageContent, 0, 'utf8');
59+
fs.closeSync(pkg_fd);
60+
}
61+
4062
const fd = fs.openSync(this.path, 'a');
41-
fs.writeFileSync(fd, this._pluginReference(plugin), 'utf8');
63+
fs.writeFileSync(fd, this._pluginReference(plugin, opts), 'utf8');
4264
fs.closeSync(fd);
4365
}
4466

4567
removePlugin (plugin) {
4668
const fd = fs.openSync(this.path, 'r+');
4769

70+
if (fs.existsSync(path.join(this.root, 'packages', plugin.id))) {
71+
fs.rmSync(path.join(this.root, 'packages', plugin.id), { recursive: true, force: true });
72+
}
73+
4874
let packageContent = fs.readFileSync(fd, 'utf8');
75+
76+
// We don't know if it was originally linked or not, so try to remove both
4977
packageContent = packageContent.replace(this._pluginReference(plugin), '');
78+
packageContent = packageContent.replace(this._pluginReference(plugin, { link: true }), '');
5079

5180
fs.ftruncateSync(fd);
52-
fs.writeFileSync(fd, packageContent, 'utf8');
81+
fs.writeSync(fd, packageContent, 0, 'utf8');
5382
fs.closeSync(fd);
5483
}
5584
}

tests/spec/unit/Api.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ describe('Platform Api', () => {
167167
it('should add the plugin reference to Package.swift', () => {
168168
return api.addPlugin(swift_plugin)
169169
.then(() => {
170-
expect(swiftPackage_mock.addPlugin).toHaveBeenCalledWith(swift_plugin);
170+
expect(swiftPackage_mock.addPlugin).toHaveBeenCalledWith(swift_plugin, jasmine.any(Object));
171171
});
172172
});
173173
});

tests/spec/unit/SwiftPackage.spec.js

+61-15
Original file line numberDiff line numberDiff line change
@@ -27,56 +27,102 @@ tmp.setGracefulCleanup();
2727
const fixturePackage = fs.readFileSync(path.join(__dirname, 'fixtures', 'test-Package.swift'), 'utf-8');
2828

2929
describe('SwiftPackage', () => {
30+
let tmpDir;
31+
beforeEach(() => {
32+
tmpDir = tmp.dirSync();
33+
});
34+
35+
afterEach(() => {
36+
fs.rmSync(tmpDir.name, { recursive: true, force: true });
37+
});
38+
3039
it('should error if Package.swift file does not exist', () => {
3140
expect(() => {
32-
const _ = new SwiftPackage('dummypath');
41+
const _ = new SwiftPackage(tmpDir.name);
3342
expect(_).not.toEqual(null); // To avoid ESLINT error "Do not use 'new' for side effects"
3443
}).toThrow();
3544
});
3645

3746
describe('addPlugin', () => {
3847
const my_plugin = {
39-
id: 'my-plugin'
48+
id: 'my-plugin',
49+
dir: path.join(__dirname, 'fixtures', 'org.test.plugins.swiftpackageplugin')
4050
};
4151

4252
let pkg;
43-
let tmpFile;
4453
beforeEach(() => {
45-
tmpFile = tmp.fileSync({ discardDescriptor: true });
46-
fs.writeFileSync(tmpFile.name, fixturePackage, 'utf8');
54+
fs.mkdirSync(path.join(tmpDir.name, 'CordovaPlugins'));
55+
fs.writeFileSync(path.join(tmpDir.name, 'CordovaPlugins', 'Package.swift'), fixturePackage, 'utf8');
4756

48-
pkg = new SwiftPackage(tmpFile.name);
57+
pkg = new SwiftPackage(tmpDir.name);
4958
});
5059

5160
it('should add plugin references to the package file', () => {
5261
pkg.addPlugin(my_plugin);
5362

54-
const content = fs.readFileSync(tmpFile.name, 'utf8');
55-
expect(content).toContain('.package(name: "my-plugin"');
63+
const pkgPath = path.join(tmpDir.name, 'CordovaPlugins', 'Package.swift');
64+
const content = fs.readFileSync(pkgPath, 'utf8');
65+
expect(content).toContain('.package(name: "my-plugin", path: "../packages/my-plugin")');
5666
expect(content).toContain('.product(name: "my-plugin", package: "my-plugin")');
5767
});
68+
69+
it('should copy the plugin into the packages directory', () => {
70+
pkg.addPlugin(my_plugin);
71+
72+
expect(fs.existsSync(path.join(tmpDir.name, 'packages', 'my-plugin'))).toBeTruthy();
73+
});
74+
75+
it('should add plugin references to the package file when linked', () => {
76+
pkg.addPlugin(my_plugin, { link: true });
77+
78+
const pkgPath = path.join(tmpDir.name, 'CordovaPlugins', 'Package.swift');
79+
const content = fs.readFileSync(pkgPath, 'utf8');
80+
81+
expect(content).toContain('.package(name: "my-plugin", path: "');
82+
expect(content).not.toContain('.package(name: "my-plugin", path: "../packages/my-plugin")');
83+
expect(content).toContain('.product(name: "my-plugin", package: "my-plugin")');
84+
});
85+
86+
it('should copy a linked plugin into the packages directory', () => {
87+
pkg.addPlugin(my_plugin, { link: true });
88+
89+
expect(fs.existsSync(path.join(tmpDir.name, 'packages', 'my-plugin'))).toBeFalsy();
90+
});
5891
});
5992

6093
describe('removePlugin', () => {
6194
const my_plugin = {
62-
id: 'my-plugin'
95+
id: 'my-plugin',
96+
dir: path.join(__dirname, 'fixtures', 'org.test.plugins.swiftpackageplugin')
6397
};
6498

6599
let pkg;
66-
let tmpFile;
67100
beforeEach(() => {
68-
tmpFile = tmp.fileSync({ discardDescriptor: true });
101+
fs.mkdirSync(path.join(tmpDir.name, 'CordovaPlugins'));
102+
const pkgPath = path.join(tmpDir.name, 'CordovaPlugins', 'Package.swift');
103+
fs.writeFileSync(pkgPath, fixturePackage, 'utf8');
69104

70-
pkg = new SwiftPackage(tmpFile.name);
71-
fs.writeFileSync(tmpFile.name, fixturePackage + pkg._pluginReference(my_plugin), 'utf8');
105+
pkg = new SwiftPackage(tmpDir.name);
106+
fs.writeFileSync(pkgPath, fixturePackage + pkg._pluginReference(my_plugin), 'utf8');
72107
});
73108

74-
it('should add plugin references to the package file', () => {
109+
it('should remove plugin references to the package file', () => {
75110
pkg.removePlugin(my_plugin);
76111

77-
const content = fs.readFileSync(tmpFile.name, 'utf8');
112+
const content = fs.readFileSync(path.join(tmpDir.name, 'CordovaPlugins', 'Package.swift'), 'utf8');
78113
expect(content).not.toContain('.package(name: "my-plugin"');
79114
expect(content).not.toContain('.product(name: "my-plugin", package: "my-plugin")');
80115
});
116+
117+
it('should remove the plugin from the packages directory', () => {
118+
fs.mkdirSync(path.join(tmpDir.name, 'packages', 'my-plugin'), { recursive: true });
119+
fs.writeFileSync(path.join(tmpDir.name, 'packages', 'my-plugin', 'test.txt'), 'Test', 'utf-8');
120+
121+
expect(fs.existsSync(path.join(tmpDir.name, 'packages', 'my-plugin'))).toBeTruthy();
122+
123+
pkg.removePlugin(my_plugin);
124+
125+
expect(fs.existsSync(path.join(tmpDir.name, 'packages', 'my-plugin'))).toBeFalsy();
126+
});
81127
});
82128
});

0 commit comments

Comments
 (0)