1 | 'use strict'
|
2 | const fs = require('fs')
|
3 | const path = require('path')
|
4 | const minimatch = require('minimatch')
|
5 | const mkdirp = require('mkdirp')
|
6 |
|
7 | const Filesystem = require('./filesystem')
|
8 | const disk = require('./disk')
|
9 | const crawlFilesystem = require('./crawlfs')
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const isUnpackDir = function (path, pattern, unpackDirs) {
|
19 | if (path.indexOf(pattern) === 0 || minimatch(path, pattern)) {
|
20 | if (unpackDirs.indexOf(path) === -1) {
|
21 | unpackDirs.push(path)
|
22 | }
|
23 | return true
|
24 | } else {
|
25 | for (let i = 0; i < unpackDirs.length; i++) {
|
26 | if (path.indexOf(unpackDirs[i]) === 0) {
|
27 | return true
|
28 | }
|
29 | }
|
30 | return false
|
31 | }
|
32 | }
|
33 |
|
34 | module.exports.createPackage = function (src, dest, callback) {
|
35 | return module.exports.createPackageWithOptions(src, dest, {}, callback)
|
36 | }
|
37 |
|
38 | module.exports.createPackageWithOptions = function (src, dest, options, callback) {
|
39 | const dot = typeof options.dot === 'undefined' ? true : options.dot
|
40 |
|
41 | return crawlFilesystem(src, { dot: dot }, function (error, filenames, metadata) {
|
42 | if (error) { return callback(error) }
|
43 | module.exports.createPackageFromFiles(src, dest, filenames, metadata, options, callback)
|
44 | })
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 | module.exports.createPackageFromFiles = function (src, dest, filenames, metadata, options, callback) {
|
57 | if (typeof metadata === 'undefined' || metadata === null) { metadata = {} }
|
58 | const filesystem = new Filesystem(src)
|
59 | const files = []
|
60 | const unpackDirs = []
|
61 |
|
62 | let filenamesSorted = []
|
63 | if (options.ordering) {
|
64 | const orderingFiles = fs.readFileSync(options.ordering).toString().split('\n').map(function (line) {
|
65 | if (line.includes(':')) { line = line.split(':').pop() }
|
66 | line = line.trim()
|
67 | if (line.startsWith('/')) { line = line.slice(1) }
|
68 | return line
|
69 | })
|
70 |
|
71 | const ordering = []
|
72 | for (const file of orderingFiles) {
|
73 | const pathComponents = file.split(path.sep)
|
74 | let str = src
|
75 | for (const pathComponent of pathComponents) {
|
76 | str = path.join(str, pathComponent)
|
77 | ordering.push(str)
|
78 | }
|
79 | }
|
80 |
|
81 | let missing = 0
|
82 | const total = filenames.length
|
83 |
|
84 | for (const file of ordering) {
|
85 | if (!filenamesSorted.includes(file) && filenames.includes(file)) {
|
86 | filenamesSorted.push(file)
|
87 | }
|
88 | }
|
89 |
|
90 | for (const file of filenames) {
|
91 | if (!filenamesSorted.includes(file)) {
|
92 | filenamesSorted.push(file)
|
93 | missing += 1
|
94 | }
|
95 | }
|
96 |
|
97 | console.log(`Ordering file has ${((total - missing) / total) * 100}% coverage.`)
|
98 | } else {
|
99 | filenamesSorted = filenames
|
100 | }
|
101 |
|
102 | const handleFile = function (filename, done) {
|
103 | let file = metadata[filename]
|
104 | let type
|
105 | if (!file) {
|
106 | const stat = fs.lstatSync(filename)
|
107 | if (stat.isDirectory()) { type = 'directory' }
|
108 | if (stat.isFile()) { type = 'file' }
|
109 | if (stat.isSymbolicLink()) { type = 'link' }
|
110 | file = {stat, type}
|
111 | }
|
112 |
|
113 | let shouldUnpack
|
114 | switch (file.type) {
|
115 | case 'directory':
|
116 | shouldUnpack = options.unpackDir
|
117 | ? isUnpackDir(path.relative(src, filename), options.unpackDir, unpackDirs)
|
118 | : false
|
119 | filesystem.insertDirectory(filename, shouldUnpack)
|
120 | break
|
121 | case 'file':
|
122 | shouldUnpack = false
|
123 | if (options.unpack) {
|
124 | shouldUnpack = minimatch(filename, options.unpack, {matchBase: true})
|
125 | }
|
126 | if (!shouldUnpack && options.unpackDir) {
|
127 | const dirName = path.relative(src, path.dirname(filename))
|
128 | shouldUnpack = isUnpackDir(dirName, options.unpackDir, unpackDirs)
|
129 | }
|
130 | files.push({filename: filename, unpack: shouldUnpack})
|
131 | filesystem.insertFile(filename, shouldUnpack, file, options, done)
|
132 | return
|
133 | case 'link':
|
134 | filesystem.insertLink(filename, file.stat)
|
135 | break
|
136 | }
|
137 | return process.nextTick(done)
|
138 | }
|
139 |
|
140 | const insertsDone = function () {
|
141 | return mkdirp(path.dirname(dest), function (error) {
|
142 | if (error) { return callback(error) }
|
143 | return disk.writeFilesystem(dest, filesystem, files, metadata, function (error) {
|
144 | if (error) { return callback(error) }
|
145 | if (options.snapshot) {
|
146 |
|
147 | } else {
|
148 | return callback(null)
|
149 | }
|
150 | })
|
151 | })
|
152 | }
|
153 |
|
154 | const names = filenamesSorted.slice()
|
155 |
|
156 | const next = function (name) {
|
157 | if (!name) { return insertsDone() }
|
158 |
|
159 | return handleFile(name, function () {
|
160 | return next(names.shift())
|
161 | })
|
162 | }
|
163 |
|
164 | return next(names.shift())
|
165 | }
|
166 |
|
167 | module.exports.statFile = function (archive, filename, followLinks) {
|
168 | const filesystem = disk.readFilesystemSync(archive)
|
169 | return filesystem.getFile(filename, followLinks)
|
170 | }
|
171 |
|
172 | module.exports.listPackage = function (archive) {
|
173 | return disk.readFilesystemSync(archive).listFiles()
|
174 | }
|
175 |
|
176 | module.exports.extractFile = function (archive, filename) {
|
177 | const filesystem = disk.readFilesystemSync(archive)
|
178 | return disk.readFileSync(filesystem, filename, filesystem.getFile(filename))
|
179 | }
|
180 |
|
181 | module.exports.extractAll = function (archive, dest) {
|
182 | const filesystem = disk.readFilesystemSync(archive)
|
183 | const filenames = filesystem.listFiles()
|
184 |
|
185 |
|
186 | const followLinks = process.platform === 'win32'
|
187 |
|
188 |
|
189 | mkdirp.sync(dest)
|
190 |
|
191 | return filenames.map((filename) => {
|
192 | filename = filename.substr(1)
|
193 | const destFilename = path.join(dest, filename)
|
194 | const file = filesystem.getFile(filename, followLinks)
|
195 | if (file.files) {
|
196 |
|
197 | mkdirp.sync(destFilename)
|
198 | } else if (file.link) {
|
199 |
|
200 | const linkSrcPath = path.dirname(path.join(dest, file.link))
|
201 | const linkDestPath = path.dirname(destFilename)
|
202 | const relativePath = path.relative(linkDestPath, linkSrcPath);
|
203 |
|
204 | (() => {
|
205 | try {
|
206 | fs.unlinkSync(destFilename)
|
207 | } catch (error) {}
|
208 | })()
|
209 | const linkTo = path.join(relativePath, path.basename(file.link))
|
210 | fs.symlinkSync(linkTo, destFilename)
|
211 | } else {
|
212 |
|
213 | const content = disk.readFileSync(filesystem, filename, file)
|
214 | fs.writeFileSync(destFilename, content)
|
215 | }
|
216 | })
|
217 | }
|