1 | // Copyright 2013 Selenium committers |
2 | // Copyright 2013 Software Freedom Conservancy |
3 | // |
4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
5 | // you may not use this file except in compliance with the License. |
6 | // You may obtain a copy of the License at |
7 | // |
8 | // http://www.apache.org/licenses/LICENSE-2.0 |
9 | // |
10 | // Unless required by applicable law or agreed to in writing, software |
11 | // distributed under the License is distributed on an "AS IS" BASIS, |
12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | // See the License for the specific language governing permissions and |
14 | // limitations under the License. |
15 | |
16 | var fs = require('fs'), |
17 | path = require('path'), |
18 | tmp = require('tmp'); |
19 | |
20 | var promise = require('..').promise; |
21 | |
22 | |
23 | var PATH_SEPARATOR = process.platform === 'win32' ? ';' : ':'; |
24 | |
25 | |
26 | // PUBLIC API |
27 | |
28 | |
29 | |
30 | /** |
31 | * Copies one file to another. |
32 | * @param {string} src The source file. |
33 | * @param {string} dst The destination file. |
34 | * @return {!promise.Promise.<string>} A promise for the copied file's path. |
35 | */ |
36 | exports.copy = function(src, dst) { |
37 | var copied = promise.defer(); |
38 | |
39 | var rs = fs.createReadStream(src); |
40 | rs.on('error', copied.reject); |
41 | rs.on('end', function() { |
42 | copied.fulfill(dst); |
43 | }); |
44 | |
45 | var ws = fs.createWriteStream(dst); |
46 | ws.on('error', copied.reject); |
47 | |
48 | rs.pipe(ws); |
49 | |
50 | return copied.promise; |
51 | }; |
52 | |
53 | |
54 | /** |
55 | * Recursively copies the contents of one directory to another. |
56 | * @param {string} src The source directory to copy. |
57 | * @param {string} dst The directory to copy into. |
58 | * @param {(RegEx|function(string): boolean)=} opt_exclude An exclusion filter |
59 | * as either a regex or predicate function. All files matching this filter |
60 | * will not be copied. |
61 | * @return {!promise.Promise.<string>} A promise for the destination |
62 | * directory's path once all files have been copied. |
63 | */ |
64 | exports.copyDir = function(src, dst, opt_exclude) { |
65 | var predicate = opt_exclude; |
66 | if (opt_exclude && typeof opt_exclude !== 'function') { |
67 | predicate = function(p) { |
68 | return !opt_exclude.test(p); |
69 | }; |
70 | } |
71 | |
72 | // TODO(jleyba): Make this function completely async. |
73 | if (!fs.existsSync(dst)) { |
74 | fs.mkdirSync(dst); |
75 | } |
76 | |
77 | var files = fs.readdirSync(src); |
78 | files = files.map(function(file) { |
79 | return path.join(src, file); |
80 | }); |
81 | |
82 | if (predicate) { |
83 | files = files.filter(predicate); |
84 | } |
85 | |
86 | var results = []; |
87 | files.forEach(function(file) { |
88 | var stats = fs.statSync(file); |
89 | var target = path.join(dst, path.basename(file)); |
90 | |
91 | if (stats.isDirectory()) { |
92 | if (!fs.existsSync(target)) { |
93 | fs.mkdirSync(target, stats.mode); |
94 | } |
95 | results.push(exports.copyDir(file, target, predicate)); |
96 | } else { |
97 | results.push(exports.copy(file, target)); |
98 | } |
99 | }); |
100 | |
101 | return promise.all(results).then(function() { |
102 | return dst; |
103 | }); |
104 | }; |
105 | |
106 | |
107 | /** |
108 | * Tests if a file path exists. |
109 | * @param {string} path The path to test. |
110 | * @return {!promise.Promise.<boolean>} A promise for whether the file exists. |
111 | */ |
112 | exports.exists = function(path) { |
113 | var result = promise.defer(); |
114 | fs.exists(path, result.fulfill); |
115 | return result.promise; |
116 | }; |
117 | |
118 | |
119 | /** |
120 | * @return {!promise.Promise.<string>} A promise for the path to a temporary |
121 | * directory. |
122 | * @see https://www.npmjs.org/package/tmp |
123 | */ |
124 | exports.tmpDir = function() { |
125 | return promise.checkedNodeCall(tmp.dir); |
126 | }; |
127 | |
128 | |
129 | /** |
130 | * @return {!promise.Promise.<string>} A promise for the path to a temporary |
131 | * file. |
132 | * @see https://www.npmjs.org/package/tmp |
133 | */ |
134 | exports.tmpFile = function() { |
135 | return promise.checkedNodeCall(tmp.file); |
136 | }; |
137 | |
138 | |
139 | /** |
140 | * Searches the {@code PATH} environment variable for the given file. |
141 | * @param {string} file The file to locate on the PATH. |
142 | * @param {boolean=} opt_checkCwd Whether to always start with the search with |
143 | * the current working directory, regardless of whether it is explicitly |
144 | * listed on the PATH. |
145 | * @return {?string} Path to the located file, or {@code null} if it could |
146 | * not be found. |
147 | */ |
148 | exports.findInPath = function(file, opt_checkCwd) { |
149 | if (opt_checkCwd) { |
150 | var tmp = path.join(process.cwd(), file); |
151 | if (fs.existsSync(tmp)) { |
152 | return tmp; |
153 | } |
154 | } |
155 | |
156 | var dirs = process.env['PATH'].split(PATH_SEPARATOR); |
157 | var found = null; |
158 | dirs.forEach(function(dir) { |
159 | var tmp = path.join(dir, file); |
160 | if (!found && fs.existsSync(tmp)) { |
161 | found = tmp; |
162 | } |
163 | }); |
164 | return found; |
165 | }; |