Completed
Push — master ( 19f188...4e9071 )
by Dimas
21:17 queued 11:18
created

libs/src/archiver/backup.ts   A

Complexity

Total Complexity 22
Complexity/F 5.5

Size

Lines of Code 184
Function Count 4

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 115
dl 0
loc 184
rs 10
c 0
b 0
f 0
wmc 22
mnd 18
bc 18
fnc 4
bpm 4.5
cpm 5.5
noi 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A backup.ts ➔ getFuncName 0 6 1
B backup.ts ➔ backup 0 75 7
D backup.ts ➔ readdir 0 85 13
A backup.ts ➔ fromRoot 0 3 1
1
import archiver from "archiver";
2
import fs from "fs";
3
import process from "process";
4
import path from "path";
5
import core from "./../compiler/core";
6
const log = core.log;
7
const root = process.cwd();
8
9
/**
10
 * Get function name
11
 */
12
export function getFuncName() {
13
  return getFuncName.caller.name;
14
}
15
16
/**
17
 * Read directory with deep options
18
 * @param directory directory scan target
19
 * @param deep true for recursive scan, false only scan the folder not subfolder
20
 * @param fileslist files to concat
21
 * @example ['node_modules', /\/node_modules\//]
22
 * @param filter
23
 * @example files only { folders true, files false }
24
 * @example folder only { files true, folder false }
25
 */
26
export function readdir(
27
  directory: string,
28
  deep: boolean,
29
  fileslist: null | string[] = [],
30
  exclude: Array<string | RegExp> = [],
31
  filter: null | {
32
    /**
33
     * Filter files from results (remove)
34
     */
35
    files: boolean;
36
    /**
37
     * Filter directory from results (remove)
38
     */
39
    folders: boolean;
40
  } = null
41
) {
42
  if (!directory) {
43
    log.log("directory(" + log.type(typeof directory) + ") not valid");
44
    return;
45
  }
46
  if (!fileslist) {
47
    fileslist = [];
48
  } else if (!fileslist.length) {
49
    fileslist = [];
50
  } else if (fileslist.length) {
51
    fileslist = fileslist;
52
  }
53
  const doRead = function (directory: string) {
54
    var files = fs.readdirSync(directory, { encoding: "utf-8" });
55
    files.forEach(function (file) {
56
      file = path.resolve(file);
57
      if (Array.isArray(fileslist)) {
58
        fileslist.push(file);
59
        var isDir = fs.lstatSync(file).isDirectory();
60
        if (deep) {
61
          if (isDir) {
62
            fileslist = readdir(file, deep, fileslist);
63
          }
64
        }
65
      }
66
    });
67
    if (exclude && exclude.length) {
68
      exclude.forEach(function (ex) {
69
        fileslist = fileslist.filter(function (item) {
70
          var allow = null;
71
          item = core.normalize(item);
72
          if (ex instanceof RegExp) {
73
            allow = !ex.test(item);
74
          } else {
75
            var matches = item.indexOf(ex) !== -1;
76
            allow = !matches;
77
          }
78
          return allow;
79
        });
80
      });
81
    }
82
    //log.log(typeof filter == "object");
83
    if (filter) {
84
      fileslist = fileslist.filter(function (item) {
85
        var type = fs.statSync(item);
86
        if (filter.hasOwnProperty("files") && filter.files) {
87
          return !type.isFile();
88
        } else if (filter.hasOwnProperty("folders") && filter.folders) {
89
          return !type.isDirectory();
90
        }
91
        return null;
92
      });
93
    }
94
    //log.log(filter);
95
96
    return fileslist;
97
  };
98
99
  return doRead(directory);
100
}
101
102
export function backup() {
103
  const fn = getFuncName();
104
105
  // create a file to stream archive data to.
106
  var output = fs.createWriteStream(root + "/tmp/backup.zip");
107
  var archive = archiver("zip", {
108
    zlib: { level: 9 }, // Sets the compression level.
109
  });
110
111
  // listen for all archive data to be written
112
  // 'close' event is fired only when a file descriptor is involved
113
  output.on("close", function () {
114
    console.log(archive.pointer() + " total bytes");
115
    console.log(
116
      "archiver has been finalized and the output file descriptor has closed."
117
    );
118
  });
119
120
  // This event is fired when the data source is drained no matter what was the data source.
121
  // It is not part of this library but rather from the NodeJS Stream API.
122
  // @see: https://nodejs.org/api/stream.html#stream_event_end
123
  output.on("end", function () {
124
    console.log("Data has been drained");
125
  });
126
127
  // good practice to catch warnings (ie stat failures and other non-blocking errors)
128
  archive.on("warning", function (err) {
129
    if (err.code === "ENOENT") {
130
      // log warning
131
    } else {
132
      // throw error
133
      throw err;
134
    }
135
  });
136
137
  // good practice to catch this error explicitly
138
  archive.on("error", function (err) {
139
    throw err;
140
  });
141
142
  // pipe archive data to the file
143
  archive.pipe(output);
144
  /**
145
   * Process archive
146
   * @param files
147
   */
148
  const archive_now = function (files: string[]) {
149
    if (files.length) {
150
      if (!fs.existsSync(files[0])) {
151
        if (!fs.existsSync(fromRoot(files[0]))) {
152
          log.log(log.error(`${fn}(${files[0]}) not found`));
153
          return;
154
        }
155
        files[0] = fromRoot(files[0]);
156
      }
157
      var type = fs.lstatSync(files[0]);
158
      var filename = path.basename(files[0]);
159
      if (type.isFile()) {
160
        archive.append(fs.createReadStream(files[0]), {
161
          name: filename,
162
        });
163
      } else if (type.isDirectory()) {
164
        archive.directory(fromRoot(files[0]), filename);
165
      }
166
      files.shift();
167
      archive_now(files);
168
    }
169
  };
170
171
  archive_now(
172
    readdir(fromRoot("/"), false, null, null, { folders: true, files: false })
173
  );
174
  archive_now(["src", "assets", ".vscode", "views", "libs"]);
175
176
  // finalize the archive (ie we are done appending files but streams have to finish yet)
177
  // 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
178
  archive.finalize();
179
}
180
181
export function fromRoot(dest: string) {
182
  return path.join(root, dest);
183
}
184