Blame view

node_modules/bower/lib/commands/cache/clean.js 5.59 KB
2dda2e10   Administrator   generator ignore
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
173
174
175
176
177
178
179
180
181
182
183
184
185
  var fs = require('../../util/fs');
  var path = require('path');
  var mout = require('mout');
  var Q = require('q');
  var rimraf = require('../../util/rimraf');
  var endpointParser = require('bower-endpoint-parser');
  var PackageRepository = require('../../core/PackageRepository');
  var semver = require('../../util/semver');
  var defaultConfig = require('../../config');
  
  function clean(logger, endpoints, options, config) {
      var decEndpoints;
      var names;
  
      options = options || {};
      config = defaultConfig(config);
  
      // If endpoints is an empty array, null them
      if (endpoints && !endpoints.length) {
          endpoints = null;
      }
  
      // Generate decomposed endpoints and names based on the endpoints
      if (endpoints) {
          decEndpoints = endpoints.map(function (endpoint) {
              return endpointParser.decompose(endpoint);
          });
          names = decEndpoints.map(function (decEndpoint) {
              return decEndpoint.name || decEndpoint.source;
          });
      }
  
      return Q.all([
          clearPackages(decEndpoints, config, logger),
          clearLinks(names, config, logger)
      ])
      .spread(function (entries) {
          return entries;
      });
  }
  
  function clearPackages(decEndpoints, config, logger) {
      var repository =  new PackageRepository(config, logger);
  
      return repository.list()
      .then(function (entries) {
          var promises;
  
          // Filter entries according to the specified packages
          if (decEndpoints) {
              entries = entries.filter(function (entry) {
                  return !!mout.array.find(decEndpoints, function (decEndpoint) {
                      var entryPkgMeta = entry.pkgMeta;
  
                      // Check if name or source match the entry
                      if  (decEndpoint.name !== entryPkgMeta.name &&
                          decEndpoint.source !== entryPkgMeta.name &&
                          decEndpoint.source !== entryPkgMeta._source
                      ) {
                          return false;
                      }
  
                      // If target is a wildcard, simply return true
                      if (decEndpoint.target === '*') {
                          return true;
                      }
  
                      // If it's a semver target, compare using semver spec
                      if (semver.validRange(decEndpoint.target)) {
                          return semver.satisfies(entryPkgMeta.version, decEndpoint.target);
                      }
  
                      // Otherwise, compare against target/release
                      return decEndpoint.target === entryPkgMeta._target ||
                             decEndpoint.target === entryPkgMeta._release;
                  });
              });
          }
  
          promises = entries.map(function (entry) {
              return repository.eliminate(entry.pkgMeta)
              .then(function () {
                  logger.info('deleted', 'Cached package ' + entry.pkgMeta.name + ': ' + entry.canonicalDir, {
                      file: entry.canonicalDir
                  });
              });
          });
  
          return Q.all(promises)
          .then(function () {
              if (!decEndpoints) {
                  // Ensure that everything is cleaned,
                  // even invalid packages in the cache
                  return repository.clear();
              }
          })
          .then(function () {
              return entries;
          });
      });
  }
  
  function clearLinks(names, config, logger) {
      var promise;
      var dir = config.storage.links;
  
      // If no names are passed, grab all links
      if (!names) {
          promise = Q.nfcall(fs.readdir, dir)
          .fail(function (err) {
              if (err.code === 'ENOENT') {
                  return [];
              }
  
              throw err;
          });
      // Otherwise use passed ones
      } else {
          promise = Q.resolve(names);
      }
  
      return promise
      .then(function (names) {
          var promises;
          var linksToRemove = [];
  
          // Decide which links to delete
          promises = names.map(function (name) {
              var link = path.join(config.storage.links, name);
  
              return Q.nfcall(fs.readlink, link)
              .then(function (linkTarget) {
                  // Link exists, check if it points to a folder
                  // that still exists
                  return Q.nfcall(fs.stat, linkTarget)
                  .then(function (stat) {
                      // Target is not a folder..
                      if (!stat.isDirectory()) {
                          linksToRemove.push(link);
                      }
                  })
                  // Error occurred reading the link
                  .fail(function () {
                      linksToRemove.push(link);
                  });
              // Ignore if link does not exist
              }, function (err) {
                  if (err.code !== 'ENOENT') {
                      linksToRemove.push(link);
                  }
              });
          });
  
          return Q.all(promises)
          .then(function () {
              var promises;
  
              // Remove each link that was declared as invalid
              promises = linksToRemove.map(function (link) {
                  return Q.nfcall(rimraf, link)
                  .then(function () {
                      logger.info('deleted', 'Invalid link: ' + link, {
                          file: link
                      });
                  });
              });
  
              return Q.all(promises);
          });
      });
  }
  
  // -------------------
  
  clean.readOptions = function (argv) {
      var cli = require('../../util/cli');
      var options = cli.readOptions(argv);
      var endpoints = options.argv.remain.slice(2);
  
      delete options.argv;
  
      return [endpoints, options];
  };
  
  module.exports = clean;