UNPKG

4.74 kBJavaScriptView Raw
1var fs = require ('fs');
2var os = require ('os');
3var path = require ('path');
4
5var yauzl = require ('yauzl');
6var crypto = require ('crypto');
7
8function createTempFolder (cb) {
9 var fileName = path.join (os.tmpdir (), 'nomination.'+crypto.randomBytes(4).readUInt32LE(0));
10
11 fs.mkdir (fileName, function (err) {
12 // TODO: make something on error
13 if (err) {
14 cb (err)
15 return;
16 }
17 cb (null, fileName);
18 });
19}
20
21function mkdirParent (dirPath, mode, callback) {
22 //Call the standard fs.mkdir
23 if (!callback) {
24 callback = mode;
25 mode = undefined;
26 }
27 fs.mkdir(dirPath, mode, function(error) {
28 //When it fail in this way, do the custom steps
29 if (error && error.code === 'ENOENT') {
30 //Create all the parents recursively
31 mkdirParent (path.dirname (dirPath), mode, function (err) {
32 //And then the directory
33 mkdirParent (dirPath, mode, callback);
34 });
35 return;
36 }
37 //Manually run the callback since we used our own callback to do all these
38 callback && callback(error);
39 });
40};
41
42// file permissions, octal 0... isn't allowed in ES5, 0o... supported only in ES6
43// 0644.toString(16)
44var fileReadable = 0x1a4;
45// 0755.toString(16)
46var dirReadable = 0x1ed;
47
48
49
50function unzip (fileName, targetFolder, options) {
51
52 if (!options) {
53 options = {
54 cb: function (err, data) {console.log (err, data);}
55 };
56 }
57
58 var cb = options.cb;
59
60 var archiveFiles = [];
61
62 var err;
63
64 var waitFileWrite = false;
65
66 yauzl.open (fileName, function(error, zipfile) {
67 if (error) {
68 cb (error, archiveFiles);
69 return;
70 }
71 var remains = 0;
72
73 function fileOpDone (error) {
74 err = error;
75 remains --;
76 if (!remains && waitFileWrite) {
77 cb (err, archiveFiles);
78 }
79 }
80
81 zipfile.on ("entry", function(entry) {
82 console.log ('zip file entry', entry);
83
84 if (!options.macosx && /^__MACOSX\//.test(entry.fileName)) {
85 // TODO: mac os resource forks and extended attrs
86 // fs-xattr, node-xattr-file
87 // http://apple.stackexchange.com/questions/141861/do-zip-files-preserve-all-hfs-features-when-created-using-finders-compress-co
88 return;
89 }
90
91 if ((!options.macosx || os.platform() !== "darwin") && /(?:^|\/)\.(?:_\.|DS_Store)/.test(entry.fileName)) {
92 // files like ._filename and .DS_Store is a mac only things
93 return;
94 }
95
96 // http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute
97 // from stat(2)
98 var modeHi = (entry.externalFileAttributes >> 16) & 0xffff;
99 var isDir = 0x4 & modeHi; // #define S_IFDIR 0040000 /* directory */
100 var isFile = 0x8 & modeHi; // #define S_IFREG 0100000 /* regular */
101 var isSymlink = 0xa & modeHi; // #define S_IFLNK 0120000 /* symbolic link */
102
103 var iUmask = ~process.umask ();
104 var perms = iUmask & (entry.externalFileAttributes || fileReadable);
105 if (isDir) {
106 // TODO: not used
107 perms = iUmask & (entry.externalFileAttributes || dirReadable);
108 }
109
110 if (/\/$/.test(entry.fileName)) {
111 // directory file names end with '/'
112 // archiveFolders.push (entry.fileName);
113 return;
114 }
115
116 archiveFiles.push (entry);
117 remains++;
118 zipfile.openReadStream (entry, function(error, readStream) {
119 if (error) {
120 fileOpDone (error);
121 return;
122 }
123
124 // console.log (targetFolder, entry.fileName);
125
126 var entryFile = path.join (targetFolder, entry.fileName);
127 if (options.replacePath) {
128 entryFile = entryFile.replace (options.replacePath[0], options.replacePath[1])
129 }
130 var entryFolder = path.dirname (entryFile);
131
132 if (entryFolder) {
133 mkdirParent (
134 entryFolder,
135 isSymlink ? writeSymlink : writeFile
136 );
137 } else {
138 isSymlink ? writeSymlink () : writeFile ();
139 }
140
141 function writeFile () {
142 var writeStream = fs.createWriteStream (entryFile, {mode: perms});
143 writeStream.on ('error', fileOpDone);
144 writeStream.on ('finish', fileOpDone);
145 readStream.pipe (writeStream);
146 }
147
148 function writeSymlink () {
149 var buf = new Buffer(0);
150 readStream.on ('data', function (d) { buf += d; });
151 readStream.on ('end', function () {
152 var linkSrc = buf.toString ('utf8');
153 fs.symlink (linkSrc, entryFile, fileOpDone);
154 });
155 }
156 });
157 });
158 // archive read complete
159 zipfile.on ('end', function () {
160 // console.log ('zip file end', remains);
161 if (remains) {
162 waitFileWrite = true;
163 } else {
164 cb (err, archiveFiles);
165 }
166 });
167 });
168}
169
170if (typeof describe !== "undefined") {
171 return;
172}
173
174if (process.argv[2]) {
175 createTempFolder (function (err, folderName) {
176 if (err) {
177 console.error (err);
178 return;
179 }
180
181 unzip (process.argv[2], folderName, {dryRun: process.argv[3], cb: function (err, archiveFiles) {
182 console.log (err);
183 console.log (archiveFiles);
184 }});
185 });
186}