/
InMemoryProject.ts
172 lines (143 loc) · 5.09 KB
/
InMemoryProject.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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import * as _ from "lodash";
import * as minimatch from "minimatch";
import * as spigot from "stream-spigot";
import { RepoRef } from "../../operations/common/RepoId";
import {
File,
isFile,
} from "../File";
import {
FileStream,
Project,
} from "../Project";
import { AbstractProject } from "../support/AbstractProject";
import { copyFiles } from "../support/projectUtils";
import { InMemoryFile } from "./InMemoryFile";
/**
* In memory Project implementation. Primarily intended
* for testing. BE WARNED: Does not correctly handle permissions and binary files!
*/
export class InMemoryProject extends AbstractProject {
/**
* Create a new InMemoryProject
* @param id: RepoRef
* @param files files to include in the project
* @return {InMemoryProject}
*/
public static from(id: RepoRef, ...files: Array<{ path: string, content: string } | File>): InMemoryProject {
const inp = new InMemoryProject(id);
files.forEach(f => inp.recordAddFile(f.path,
isFile(f) ? f.getContentSync() : f.content));
return inp;
}
/**
* Create a new InMemoryProject without an id
*/
public static of(...files: Array<{ path: string, content: string } | File>): InMemoryProject {
return InMemoryProject.from({
owner: "dummyOwner",
repo: "dummyRepo",
url: "https://fakeGitHub.com/dummyOwner/dummyRepo",
}, ...files);
}
/**
* Make an independent copy of the given project, with the same files
* @param {Project} p
* @return {InMemoryProject}
*/
public static cache(p: Project): Promise<InMemoryProject> {
const to = new InMemoryProject(p.id);
return copyFiles(p, to);
}
/**
* Directories added. May contain no files. Must
* be included when copying to a file system.
* @type {Array}
*/
public readonly addedDirectoryPaths: string[] = [];
private memFiles: InMemoryFile[] = [];
constructor(xid?: RepoRef) {
super(xid);
}
get fileCount() {
return this.memFiles.length;
}
get filesSync(): File[] {
return this.memFiles;
}
public findFile(path: string): Promise<File> {
const file = this.findFileSync(path);
return file ? Promise.resolve(file) : Promise.reject(new Error(`File not found at ${path}`));
}
public async getFile(path: string): Promise<File> {
return this.memFiles.find(f => f.path === path);
}
public findFileSync(path: string): File {
return this.memFiles.find(f => f.path === path);
}
public recordAddFile(path: string, content: string): this {
this.memFiles.push(new InMemoryFile(path, content));
return this;
}
public addFileSync(path: string, content: string): void {
this.recordAddFile(path, content);
}
public addFile(path: string, content: string): Promise<this> {
this.addFileSync(path, content);
return Promise.resolve(this);
}
public addDirectory(path: string): Promise<this> {
this.addedDirectoryPaths.push(path);
return Promise.resolve(this);
}
public deleteDirectorySync(path: string): void {
this.memFiles.forEach(f => {
if (f.path.startsWith(`${path}/`)) {
this.deleteFileSync(f.path);
}
});
}
public deleteDirectory(path: string): Promise<this> {
this.deleteDirectorySync(path);
return Promise.resolve(this);
}
public deleteFileSync(path: string): this {
this.memFiles = this.memFiles.filter(f => f.path !== path);
return this;
}
public deleteFile(path: string): Promise<this> {
this.deleteFileSync(path);
return Promise.resolve(this);
}
public makeExecutableSync(path: string): void {
throw new Error("unimplemented: makeExecutableSync");
}
public directoryExistsSync(path: string): boolean {
return this.memFiles.some(f => f.path.startsWith(`${path}/`));
}
public async hasDirectory(path: string): Promise<boolean> {
return Promise.resolve(this.directoryExistsSync(path));
}
public fileExistsSync(path: string): boolean {
return this.memFiles.some(f => f.path === path);
}
public streamFilesRaw(globPatterns: string[], opts: {}): FileStream {
const positiveMatches = _.flatten(
this.memFiles.filter(f =>
globPatterns.some(gp => !gp.startsWith("!") && minimatch.match([f.path], gp).includes(f.path)),
));
const matchingFiles = _.reject(positiveMatches,
f => globPatterns.some(gp => gp.startsWith("!") && minimatch.match([f.path], gp.substring(1)).includes(f.path)),
);
return spigot.array({ objectMode: true },
matchingFiles,
);
}
public makeExecutable(path: string): Promise<this> {
return Promise.reject(new Error("makeExecutable not implemented"));
}
}
export function isInMemoryProject(p: Project): p is InMemoryProject {
const maybe = p as InMemoryProject;
return maybe.addedDirectoryPaths !== undefined;
}