-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathpacote-service.ts
140 lines (122 loc) · 4.36 KB
/
pacote-service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import * as pacote from "pacote";
import * as tar from "tar";
import * as path from "path";
import { PassThrough } from "stream";
import * as _ from "lodash";
import { cache } from "../common/decorators";
import { INpmConfigService, INodePackageManager } from "../declarations";
import { IProxyService, IFileSystem } from "../common/declarations";
import { IInjector } from "../common/definitions/yok";
import { injector } from "../common/yok";
export class PacoteService implements IPacoteService {
constructor(
private $fs: IFileSystem,
private $injector: IInjector,
private $logger: ILogger,
private $npmConfigService: INpmConfigService,
private $proxyService: IProxyService
) {}
@cache()
public get $packageManager(): INodePackageManager {
// need to be resolved here due to cyclic dependency
return this.$injector.resolve("packageManager");
}
public async manifest(
packageName: string,
options?: IPacoteManifestOptions
): Promise<any> {
this.$logger.trace(
`Calling pacoteService.manifest for packageName: '${packageName}' and options: ${options}`
);
const manifestOptions: IPacoteBaseOptions = await this.getPacoteBaseOptions();
if (options) {
_.extend(manifestOptions, options);
}
packageName = this.getRealPackageName(packageName);
this.$logger.trace(
`Calling pacote.manifest for packageName: ${packageName} and options: ${JSON.stringify(
manifestOptions,
null,
2
)}`
);
const result = pacote.manifest(packageName, manifestOptions);
return result;
}
public async extractPackage(
packageName: string,
destinationDirectory: string,
options?: IPacoteExtractOptions
): Promise<void> {
// strip: Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped. More info: https://github.com/npm/node-tar/blob/e89c4d37519b1c20133a9f49d5f6b85fa34c203b/README.md
// C: Create an archive
this.$logger.trace(
`Calling pacoteService.extractPackage for packageName: '${packageName}', destinationDir: '${destinationDirectory}' and options: ${options}`
);
const extractOptions = { strip: 1, C: destinationDirectory };
if (options) {
_.extend(extractOptions, options);
}
packageName = this.getRealPackageName(packageName);
const pacoteOptions = await this.getPacoteBaseOptions();
return new Promise<void>(async (resolve, reject) => {
this.$logger.trace(
`Calling pacoteService.extractPackage for packageName: '${packageName}', destinationDir: '${destinationDirectory}' and options: ${options}`
);
const source = await pacote
.tarball(packageName, pacoteOptions)
.catch((err: Error) => {
this.$logger.trace(
`Error in source while trying to extract stream from ${packageName}. Error is ${err}`
);
reject(err);
});
this.$logger.trace(
`Creating extract tar stream with options: ${JSON.stringify(
extractOptions,
null,
2
)}`
);
const destination = tar.x(extractOptions);
// Initiate the source
const sourceStream = new PassThrough();
sourceStream.end(source);
sourceStream.pipe(destination);
destination.on("error", (err: Error) => {
this.$logger.trace(
`Error in destination while trying to extract stream from ${packageName}. Error is ${err}`
);
reject(err);
});
destination.on("finish", () => {
this.$logger.trace(
`Successfully extracted '${packageName}' to ${destinationDirectory}`
);
resolve();
});
});
}
private async getPacoteBaseOptions(): Promise<IPacoteBaseOptions> {
// In case `tns create myapp --template https://github.com/NativeScript/template-hello-world.git` command is executed, pacote module throws an error if cache option is not provided.
const cachePath = await this.$packageManager.getCachePath();
// Add NPM Configuration to our Manifest options
const npmConfig = this.$npmConfigService.getConfig();
const pacoteOptions = _.extend(npmConfig, { cache: cachePath });
const proxySettings = await this.$proxyService.getCache();
if (proxySettings) {
_.extend(pacoteOptions, proxySettings);
}
return pacoteOptions;
}
private getRealPackageName(packageName: string): string {
if (this.$fs.exists(packageName)) {
this.$logger.trace(
`Will resolve the full path to package ${packageName}.`
);
packageName = path.resolve(packageName);
}
return packageName;
}
}
injector.register("pacoteService", PacoteService);