文件操作 - install.js
返回文件管理
返回主菜单
删除本文件
文件: /usr/share/atom/resources/app/apm/lib/install.js
编辑文件内容
(function() { var CSON, Command, Git, Install, RebuildModuleCache, _, assert, async, config, fs, hostedGitInfo, isDeprecatedPackage, path, request, semver, temp, yargs, boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } }; assert = require('assert'); path = require('path'); _ = require('underscore-plus'); async = require('async'); CSON = require('season'); yargs = require('yargs'); Git = require('git-utils'); semver = require('semver'); temp = require('temp'); hostedGitInfo = require('hosted-git-info'); config = require('./apm'); Command = require('./command'); fs = require('./fs'); RebuildModuleCache = require('./rebuild-module-cache'); request = require('./request'); ({isDeprecatedPackage} = require('./deprecated-packages')); module.exports = Install = (function() { class Install extends Command { constructor() { super(); this.installModules = this.installModules.bind(this); this.installGitPackageDependencies = this.installGitPackageDependencies.bind(this); this.atomDirectory = config.getAtomDirectory(); this.atomPackagesDirectory = path.join(this.atomDirectory, 'packages'); this.atomNodeDirectory = path.join(this.atomDirectory, '.node-gyp'); this.atomNpmPath = require.resolve('npm/bin/npm-cli'); this.repoLocalPackagePathRegex = /^file:(?!\/\/)(.*)/; } parseOptions(argv) { var options; options = yargs(argv).wrap(Math.min(100, yargs.terminalWidth())); options.usage("\nUsage: apm install [<package_name>...]\n apm install <package_name>@<package_version>\n apm install <git_remote>\n apm install <github_username>/<github_project>\n apm install --packages-file my-packages.txt\n apm i (with any of the previous argument usage)\n\nInstall the given Atom package to ~/.atom/packages/<package_name>.\n\nIf no package name is given then all the dependencies in the package.json\nfile are installed to the node_modules folder in the current working\ndirectory.\n\nA packages file can be specified that is a newline separated list of\npackage names to install with optional versions using the\n`package-name@version` syntax."); options.alias('c', 'compatible').string('compatible').describe('compatible', 'Only install packages/themes compatible with this Atom version'); options.alias('h', 'help').describe('help', 'Print this usage message'); options.alias('s', 'silent').boolean('silent').describe('silent', 'Set the npm log level to silent'); options.alias('q', 'quiet').boolean('quiet').describe('quiet', 'Set the npm log level to warn'); options.boolean('check').describe('check', 'Check that native build tools are installed'); options.boolean('verbose').default('verbose', false).describe('verbose', 'Show verbose debug information'); options.string('packages-file').describe('packages-file', 'A text file containing the packages to install'); return options.boolean('production').describe('production', 'Do not install dev dependencies'); } installModule(options, pack, moduleURI, callback) { var env, installArgs, installDirectory, installGlobally, installOptions, nodeModulesDirectory, ref, vsArgs; installGlobally = (ref = options.installGlobally) != null ? ref : true; installArgs = ['--globalconfig', config.getGlobalConfigPath(), '--userconfig', config.getUserConfigPath(), 'install']; installArgs.push(moduleURI); installArgs.push(...this.getNpmBuildFlags()); if (installGlobally) { installArgs.push("--global-style"); } if (options.argv.silent) { installArgs.push('--silent'); } if (options.argv.quiet) { installArgs.push('--quiet'); } if (options.argv.production) { installArgs.push('--production'); } if (vsArgs = this.getVisualStudioFlags()) { installArgs.push(vsArgs); } fs.makeTreeSync(this.atomDirectory); env = _.extend({}, process.env, { HOME: this.atomNodeDirectory, RUSTUP_HOME: config.getRustupHomeDirPath() }); this.addBuildEnvVars(env); installOptions = {env}; if (this.verbose) { installOptions.streaming = true; } if (installGlobally) { installDirectory = temp.mkdirSync('apm-install-dir-'); nodeModulesDirectory = path.join(installDirectory, 'node_modules'); fs.makeTreeSync(nodeModulesDirectory); installOptions.cwd = installDirectory; } return this.fork(this.atomNpmPath, installArgs, installOptions, (code, stderr = '', stdout = '') => { var child, children, commands, destination, error, source; if (code === 0) { if (installGlobally) { commands = []; children = fs.readdirSync(nodeModulesDirectory).filter(function(dir) { return dir !== ".bin"; }); assert.equal(children.length, 1, "Expected there to only be one child in node_modules"); child = children[0]; source = path.join(nodeModulesDirectory, child); destination = path.join(this.atomPackagesDirectory, child); commands.push(function(next) { return fs.cp(source, destination, next); }); commands.push((next) => { return this.buildModuleCache(pack.name, next); }); commands.push((next) => { return this.warmCompileCache(pack.name, next); }); return async.waterfall(commands, (error) => { if (error != null) { this.logFailure(); } else { if (!options.argv.json) { this.logSuccess(); } } return callback(error, { name: child, installPath: destination }); }); } else { return callback(null, { name: child, installPath: destination }); } } else { if (installGlobally) { fs.removeSync(installDirectory); this.logFailure(); } error = `${stdout}\n${stderr}`; if (error.indexOf('code ENOGIT') !== -1) { error = this.getGitErrorMessage(pack); } return callback(error); } }); } getGitErrorMessage(pack) { var message; message = `Failed to install ${pack.name} because Git was not found.\n\nThe ${pack.name} package has module dependencies that cannot be installed without Git.\n\nYou need to install Git and add it to your path environment variable in order to install this package.\n`; switch (process.platform) { case 'win32': message += "\nYou can install Git by downloading, installing, and launching GitHub for Windows: https://windows.github.com\n"; break; case 'linux': message += "\nYou can install Git from your OS package manager.\n"; } message += "\nRun apm -v after installing Git to see what version has been detected."; return message; } installModules(options, callback) { boundMethodCheck(this, Install); if (!options.argv.json) { process.stdout.write('Installing modules '); } return this.forkInstallCommand(options, (...args) => { if (options.argv.json) { return this.logCommandResultsIfFail(callback, ...args); } else { return this.logCommandResults(callback, ...args); } }); } forkInstallCommand(options, callback) { var env, installArgs, installOptions, vsArgs; installArgs = ['--globalconfig', config.getGlobalConfigPath(), '--userconfig', config.getUserConfigPath(), 'install']; installArgs.push(...this.getNpmBuildFlags()); if (options.argv.silent) { installArgs.push('--silent'); } if (options.argv.quiet) { installArgs.push('--quiet'); } if (options.argv.production) { installArgs.push('--production'); } if (vsArgs = this.getVisualStudioFlags()) { installArgs.push(vsArgs); } fs.makeTreeSync(this.atomDirectory); env = _.extend({}, process.env, { HOME: this.atomNodeDirectory, RUSTUP_HOME: config.getRustupHomeDirPath() }); this.addBuildEnvVars(env); installOptions = {env}; if (options.cwd) { installOptions.cwd = options.cwd; } if (this.verbose) { installOptions.streaming = true; } return this.fork(this.atomNpmPath, installArgs, installOptions, callback); } // Request package information from the atom.io API for a given package name. // packageName - The string name of the package to request. // callback - The function to invoke when the request completes with an error // as the first argument and an object as the second. requestPackage(packageName, callback) { var requestSettings; requestSettings = { url: `${config.getAtomPackagesUrl()}/${packageName}`, json: true, retries: 4 }; return request.get(requestSettings, function(error, response, body = {}) { var message; if (error != null) { message = `Request for package information failed: ${error.message}`; if (error.code) { message += ` (${error.code})`; } return callback(message); } else if (response.statusCode !== 200) { message = request.getErrorMessage(response, body); return callback(`Request for package information failed: ${message}`); } else { if (body.releases.latest) { return callback(null, body); } else { return callback(`No releases available for ${packageName}`); } } }); } // Is the package at the specified version already installed? // * packageName: The string name of the package. // * packageVersion: The string version of the package. isPackageInstalled(packageName, packageVersion) { var error, ref, version; try { ({version} = (ref = CSON.readFileSync(CSON.resolve(path.join('node_modules', packageName, 'package')))) != null ? ref : {}); return packageVersion === version; } catch (error1) { error = error1; return false; } } // Install the package with the given name and optional version // metadata - The package metadata object with at least a name key. A version // key is also supported. The version defaults to the latest if // unspecified. // options - The installation options object. // callback - The function to invoke when installation completes with an // error as the first argument. installRegisteredPackage(metadata, options, callback) { var installGlobally, label, packageName, packageVersion, ref; packageName = metadata.name; packageVersion = metadata.version; installGlobally = (ref = options.installGlobally) != null ? ref : true; if (!installGlobally) { if (packageVersion && this.isPackageInstalled(packageName, packageVersion)) { callback(null, {}); return; } } label = packageName; if (packageVersion) { label += `@${packageVersion}`; } if (!options.argv.json) { process.stdout.write(`Installing ${label} `); if (installGlobally) { process.stdout.write(`to ${this.atomPackagesDirectory} `); } } return this.requestPackage(packageName, (error, pack) => { var commands, ref1, ref2, tarball; if (error != null) { this.logFailure(); return callback(error); } else { if (packageVersion == null) { packageVersion = this.getLatestCompatibleVersion(pack); } if (!packageVersion) { this.logFailure(); callback(`No available version compatible with the installed Atom version: ${this.installedAtomVersion}`); return; } ({tarball} = (ref1 = (ref2 = pack.versions[packageVersion]) != null ? ref2.dist : void 0) != null ? ref1 : {}); if (!tarball) { this.logFailure(); callback(`Package version: ${packageVersion} not found`); return; } commands = []; commands.push((next) => { return this.installModule(options, pack, tarball, next); }); if (installGlobally && (packageName.localeCompare(pack.name, 'en', { sensitivity: 'accent' }) !== 0)) { commands.push((newPack, next) => { // package was renamed; delete old package folder fs.removeSync(path.join(this.atomPackagesDirectory, packageName)); return next(null, newPack); }); } commands.push(function({installPath}, next) { var json; if (installPath != null) { metadata = JSON.parse(fs.readFileSync(path.join(installPath, 'package.json'), 'utf8')); json = {installPath, metadata}; return next(null, json); } else { return next(null, {}); // installed locally, no install path data } }); return async.waterfall(commands, (error, json) => { if (!installGlobally) { if (error != null) { this.logFailure(); } else { if (!options.argv.json) { this.logSuccess(); } } } return callback(error, json); }); } }); } // Install the package with the given name and local path // packageName - The name of the package // packagePath - The local path of the package in the form "file:./packages/package-name" // options - The installation options object. // callback - The function to invoke when installation completes with an // error as the first argument. installLocalPackage(packageName, packagePath, options, callback) { var commands; if (!options.argv.json) { process.stdout.write(`Installing ${packageName} from ${packagePath.slice('file:'.length)} `); commands = []; commands.push((next) => { return this.installModule(options, { name: packageName }, packagePath, next); }); commands.push(function({installPath}, next) { var json, metadata; if (installPath != null) { metadata = JSON.parse(fs.readFileSync(path.join(installPath, 'package.json'), 'utf8')); json = {installPath, metadata}; return next(null, json); } else { return next(null, {}); // installed locally, no install path data } }); return async.waterfall(commands, (error, json) => { if (error != null) { this.logFailure(); } else { if (!options.argv.json) { this.logSuccess(); } } return callback(error, json); }); } } // Install all the package dependencies found in the package.json file. // options - The installation options // callback - The callback function to invoke when done with an error as the // first argument. installPackageDependencies(options, callback) { var commands, name, ref, version; options = _.extend({}, options, { installGlobally: false }); commands = []; ref = this.getPackageDependencies(); for (name in ref) { version = ref[name]; ((name, version) => { return commands.push((next) => { if (this.repoLocalPackagePathRegex.test(version)) { return this.installLocalPackage(name, version, options, next); } else { return this.installRegisteredPackage({name, version}, options, next); } }); })(name, version); } return async.series(commands, callback); } installDependencies(options, callback) { var commands; options.installGlobally = false; commands = []; commands.push((callback) => { return this.installModules(options, callback); }); commands.push((callback) => { return this.installPackageDependencies(options, callback); }); return async.waterfall(commands, callback); } // Get all package dependency names and versions from the package.json file. getPackageDependencies() { var dependencies, dependencyPath, error, filteredPackages, metadata, packageDependencies, packageDependencyPath, packageName, packageSpec, ref; try { metadata = fs.readFileSync('package.json', 'utf8'); ({packageDependencies, dependencies} = (ref = JSON.parse(metadata)) != null ? ref : {}); if (!packageDependencies) { return {}; } if (!dependencies) { return packageDependencies; } // This code filters out any `packageDependencies` that have an equivalent // normalized repo-local package path entry in the `dependencies` section of // `package.json`. Versioned `packageDependencies` are always returned. filteredPackages = {}; for (packageName in packageDependencies) { packageSpec = packageDependencies[packageName]; dependencyPath = this.getRepoLocalPackagePath(dependencies[packageName]); packageDependencyPath = this.getRepoLocalPackagePath(packageSpec); if (!(packageDependencyPath && dependencyPath === packageDependencyPath)) { filteredPackages[packageName] = packageSpec; } } return filteredPackages; } catch (error1) { error = error1; return {}; } } getRepoLocalPackagePath(packageSpec) { var repoLocalPackageMatch; if (!packageSpec) { return void 0; } repoLocalPackageMatch = packageSpec.match(this.repoLocalPackagePathRegex); if (repoLocalPackageMatch) { return path.normalize(repoLocalPackageMatch[1]); } else { return void 0; } } createAtomDirectories() { fs.makeTreeSync(this.atomDirectory); fs.makeTreeSync(this.atomPackagesDirectory); return fs.makeTreeSync(this.atomNodeDirectory); } // Compile a sample native module to see if a useable native build toolchain // is instlalled and successfully detected. This will include both Python // and a compiler. checkNativeBuildTools(callback) { var buildArgs, buildOptions, env, vsArgs; process.stdout.write('Checking for native build tools '); buildArgs = ['--globalconfig', config.getGlobalConfigPath(), '--userconfig', config.getUserConfigPath(), 'build']; buildArgs.push(path.resolve(__dirname, '..', 'native-module')); buildArgs.push(...this.getNpmBuildFlags()); if (vsArgs = this.getVisualStudioFlags()) { buildArgs.push(vsArgs); } fs.makeTreeSync(this.atomDirectory); env = _.extend({}, process.env, { HOME: this.atomNodeDirectory, RUSTUP_HOME: config.getRustupHomeDirPath() }); this.addBuildEnvVars(env); buildOptions = {env}; if (this.verbose) { buildOptions.streaming = true; } fs.removeSync(path.resolve(__dirname, '..', 'native-module', 'build')); return this.fork(this.atomNpmPath, buildArgs, buildOptions, (...args) => { return this.logCommandResults(callback, ...args); }); } packageNamesFromPath(filePath) { var packages; filePath = path.resolve(filePath); if (!fs.isFileSync(filePath)) { throw new Error(`File '${filePath}' does not exist`); } packages = fs.readFileSync(filePath, 'utf8'); return this.sanitizePackageNames(packages.split(/\s/)); } buildModuleCache(packageName, callback) { var packageDirectory, rebuildCacheCommand; packageDirectory = path.join(this.atomPackagesDirectory, packageName); rebuildCacheCommand = new RebuildModuleCache(); return rebuildCacheCommand.rebuild(packageDirectory, function() { // Ignore cache errors and just finish the install return callback(); }); } warmCompileCache(packageName, callback) { var packageDirectory; packageDirectory = path.join(this.atomPackagesDirectory, packageName); return this.getResourcePath((resourcePath) => { var CompileCache, onDirectory, onFile; try { CompileCache = require(path.join(resourcePath, 'src', 'compile-cache')); onDirectory = function(directoryPath) { return path.basename(directoryPath) !== 'node_modules'; }; onFile = (filePath) => { try { return CompileCache.addPathToCache(filePath, this.atomDirectory); } catch (error1) {} }; fs.traverseTreeSync(packageDirectory, onFile, onDirectory); } catch (error1) {} return callback(null); }); } isBundledPackage(packageName, callback) { return this.getResourcePath(function(resourcePath) { var atomMetadata, error, ref; try { atomMetadata = JSON.parse(fs.readFileSync(path.join(resourcePath, 'package.json'))); } catch (error1) { error = error1; return callback(false); } return callback(atomMetadata != null ? (ref = atomMetadata.packageDependencies) != null ? ref.hasOwnProperty(packageName) : void 0 : void 0); }); } getLatestCompatibleVersion(pack) { var engine, latestVersion, metadata, ref, ref1, ref2, ref3, version; if (!this.installedAtomVersion) { if (isDeprecatedPackage(pack.name, pack.releases.latest)) { return null; } else { return pack.releases.latest; } } latestVersion = null; ref1 = (ref = pack.versions) != null ? ref : {}; for (version in ref1) { metadata = ref1[version]; if (!semver.valid(version)) { continue; } if (!metadata) { continue; } if (isDeprecatedPackage(pack.name, version)) { continue; } engine = (ref2 = (ref3 = metadata.engines) != null ? ref3.atom : void 0) != null ? ref2 : '*'; if (!semver.validRange(engine)) { continue; } if (!semver.satisfies(this.installedAtomVersion, engine)) { continue; } if (latestVersion == null) { latestVersion = version; } if (semver.gt(version, latestVersion)) { latestVersion = version; } } return latestVersion; } getHostedGitInfo(name) { return hostedGitInfo.fromUrl(name); } installGitPackage(packageUrl, options, callback) { var cloneDir, iteratee, tasks; tasks = []; cloneDir = temp.mkdirSync("atom-git-package-clone-"); tasks.push((data, next) => { var urls; urls = this.getNormalizedGitUrls(packageUrl); return this.cloneFirstValidGitUrl(urls, cloneDir, options, function(err) { return next(err, data); }); }); tasks.push((data, next) => { return this.installGitPackageDependencies(cloneDir, options, function(err) { return next(err, data); }); }); tasks.push((data, next) => { return this.getRepositoryHeadSha(cloneDir, function(err, sha) { data.sha = sha; return next(err, data); }); }); tasks.push(function(data, next) { var metadataFilePath; metadataFilePath = CSON.resolve(path.join(cloneDir, 'package')); return CSON.readFile(metadataFilePath, function(err, metadata) { data.metadataFilePath = metadataFilePath; data.metadata = metadata; return next(err, data); }); }); tasks.push(function(data, next) { data.metadata.apmInstallSource = { type: "git", source: packageUrl, sha: data.sha }; return CSON.writeFile(data.metadataFilePath, data.metadata, function(err) { return next(err, data); }); }); tasks.push((data, next) => { var name, targetDir; ({name} = data.metadata); targetDir = path.join(this.atomPackagesDirectory, name); if (!options.argv.json) { process.stdout.write(`Moving ${name} to ${targetDir} `); } return fs.cp(cloneDir, targetDir, (err) => { var json; if (err) { return next(err); } else { if (!options.argv.json) { this.logSuccess(); } json = { installPath: targetDir, metadata: data.metadata }; return next(null, json); } }); }); iteratee = function(currentData, task, next) { return task(currentData, next); }; return async.reduce(tasks, {}, iteratee, callback); } getNormalizedGitUrls(packageUrl) { var packageInfo; packageInfo = this.getHostedGitInfo(packageUrl); if (packageUrl.indexOf('file://') === 0) { return [packageUrl]; } else if (packageInfo.default === 'sshurl') { return [packageInfo.toString()]; } else if (packageInfo.default === 'https') { return [packageInfo.https().replace(/^git\+https:/, "https:")]; } else if (packageInfo.default === 'shortcut') { return [packageInfo.https().replace(/^git\+https:/, "https:"), packageInfo.sshurl()]; } } cloneFirstValidGitUrl(urls, cloneDir, options, callback) { return async.detectSeries(urls, (url, next) => { return this.cloneNormalizedUrl(url, cloneDir, options, function(error) { return next(!error); }); }, function(result) { var invalidUrls, invalidUrlsError; if (!result) { invalidUrls = `Couldn't clone ${urls.join(' or ')}`; invalidUrlsError = new Error(invalidUrls); return callback(invalidUrlsError); } else { return callback(); } }); } cloneNormalizedUrl(url, cloneDir, options, callback) { var Develop, develop; // Require here to avoid circular dependency Develop = require('./develop'); develop = new Develop(); return develop.cloneRepository(url, cloneDir, options, function(err) { return callback(err); }); } installGitPackageDependencies(directory, options, callback) { boundMethodCheck(this, Install); options.cwd = directory; return this.installDependencies(options, callback); } getRepositoryHeadSha(repoDir, callback) { var err, repo, sha; try { repo = Git.open(repoDir); sha = repo.getReferenceTarget("HEAD"); return callback(null, sha); } catch (error1) { err = error1; return callback(err); } } run(options) { var callback, commands, error, installPackage, iteratee, packageNames, packagesFilePath; ({callback} = options); options = this.parseOptions(options.commandArgs); packagesFilePath = options.argv['packages-file']; this.createAtomDirectories(); if (options.argv.check) { config.loadNpm((error, npm) => { this.npm = npm; return this.loadInstalledAtomMetadata(() => { return this.checkNativeBuildTools(callback); }); }); return; } this.verbose = options.argv.verbose; if (this.verbose) { request.debug(true); process.env.NODE_DEBUG = 'request'; } installPackage = (name, nextInstallStep) => { var atIndex, gitPackageInfo, version; gitPackageInfo = this.getHostedGitInfo(name); if (gitPackageInfo || name.indexOf('file://') === 0) { return this.installGitPackage(name, options, nextInstallStep); } else if (name === '.') { return this.installDependencies(options, nextInstallStep); // is registered package } else { atIndex = name.indexOf('@'); if (atIndex > 0) { version = name.substring(atIndex + 1); name = name.substring(0, atIndex); } return this.isBundledPackage(name, (isBundledPackage) => { if (isBundledPackage) { console.error(`The ${name} package is bundled with Atom and should not be explicitly installed.\nYou can run \`apm uninstall ${name}\` to uninstall it and then the version bundled\nwith Atom will be used.`.yellow); } return this.installRegisteredPackage({name, version}, options, nextInstallStep); }); } }; if (packagesFilePath) { try { packageNames = this.packageNamesFromPath(packagesFilePath); } catch (error1) { error = error1; return callback(error); } } else { packageNames = this.packageNamesFromArgv(options.argv); if (packageNames.length === 0) { packageNames.push('.'); } } commands = []; commands.push((callback) => { return config.loadNpm((error, npm) => { this.npm = npm; return callback(error); }); }); commands.push((callback) => { return this.loadInstalledAtomMetadata(function() { return callback(); }); }); packageNames.forEach(function(packageName) { return commands.push(function(callback) { return installPackage(packageName, callback); }); }); iteratee = function(item, next) { return item(next); }; return async.mapSeries(commands, iteratee, function(err, installedPackagesInfo) { if (err) { return callback(err); } installedPackagesInfo = _.compact(installedPackagesInfo); installedPackagesInfo = installedPackagesInfo.filter(function(item, idx) { return packageNames[idx] !== "."; }); if (options.argv.json) { console.log(JSON.stringify(installedPackagesInfo, null, " ")); } return callback(null); }); } }; Install.commandNames = ['install', 'i']; return Install; }).call(this); }).call(this);
修改文件时间
将文件时间修改为当前时间的前一年
删除文件