diff --git a/spec/package-spec.coffee b/spec/package-spec.coffee index bf059e0b5..c106689f2 100644 --- a/spec/package-spec.coffee +++ b/spec/package-spec.coffee @@ -13,29 +13,29 @@ describe "Package", -> it "does not activate it", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) expect(pack.isCompatible()).toBe false expect(pack.incompatibleModules[0].name).toBe 'native-module' expect(pack.incompatibleModules[0].path).toBe path.join(packagePath, 'node_modules', 'native-module') it "utilizes _atomModuleCache if present to determine the package's native dependencies", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-ignored-incompatible-native-module') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) expect(pack.getNativeModuleDependencyPaths().length).toBe(1) # doesn't see the incompatible module expect(pack.isCompatible()).toBe true packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-cached-incompatible-native-module') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) expect(pack.isCompatible()).toBe false it "caches the incompatible native modules in local storage", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module') - expect(new Package(packagePath).isCompatible()).toBe false + expect(new Package(path: packagePath, packageManager: atom.packages).isCompatible()).toBe false expect(global.localStorage.getItem.callCount).toBe 1 expect(global.localStorage.setItem.callCount).toBe 1 - expect(new Package(packagePath).isCompatible()).toBe false + expect(new Package(path: packagePath, packageManager: atom.packages).isCompatible()).toBe false expect(global.localStorage.getItem.callCount).toBe 2 expect(global.localStorage.setItem.callCount).toBe 1 @@ -49,7 +49,7 @@ describe "Package", -> it "returns a promise resolving to the results of `apm rebuild`", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) rebuildCallbacks = [] spyOn(pack, 'runRebuildProcess').andCallFake ((callback) -> rebuildCallbacks.push(callback)) @@ -63,7 +63,7 @@ describe "Package", -> it "persists build failures in local storage", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-index') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) expect(pack.isCompatible()).toBe true expect(pack.getBuildFailureOutput()).toBeNull() @@ -79,7 +79,7 @@ describe "Package", -> expect(pack.isCompatible()).toBe false # A different package instance has the same failure output (simulates reload) - pack2 = new Package(packagePath) + pack2 = new Package(path: packagePath, packageManager: atom.packages) expect(pack2.getBuildFailureOutput()).toBe 'It is broken' expect(pack2.isCompatible()).toBe false @@ -92,7 +92,7 @@ describe "Package", -> it "sets cached incompatible modules to an empty array when the rebuild completes (there may be a build error, but rebuilding *deletes* native modules)", -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-incompatible-native-module') - pack = new Package(packagePath) + pack = new Package(path: packagePath, packageManager: atom.packages) expect(pack.getIncompatibleNativeModules().length).toBeGreaterThan(0) @@ -118,14 +118,14 @@ describe "Package", -> it "loads and applies css", -> expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px" themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-css') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() expect(getComputedStyle(editorElement).paddingTop).toBe "1234px" it "parses, loads and applies less", -> expect(getComputedStyle(editorElement).paddingBottom).not.toBe "1234px" themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-index-less') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() expect(getComputedStyle(editorElement).paddingTop).toBe "4321px" @@ -136,7 +136,7 @@ describe "Package", -> expect(getComputedStyle(editorElement).paddingBottom).not.toBe("103px") themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() expect(getComputedStyle(editorElement).paddingTop).toBe("101px") expect(getComputedStyle(editorElement).paddingRight).toBe("102px") @@ -149,7 +149,7 @@ describe "Package", -> expect(getComputedStyle(editorElement).paddingBottom).not.toBe "30px" themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-without-package-file') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() expect(getComputedStyle(editorElement).paddingTop).toBe "10px" expect(getComputedStyle(editorElement).paddingRight).toBe "20px" @@ -158,7 +158,7 @@ describe "Package", -> describe "reloading a theme", -> beforeEach -> themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() it "reloads without readding to the stylesheets list", -> @@ -169,7 +169,7 @@ describe "Package", -> describe "events", -> beforeEach -> themePath = atom.project.getDirectories()[0]?.resolve('packages/theme-with-package-file') - theme = new ThemePackage(themePath) + theme = new ThemePackage(path: themePath, packageManager: atom.packages) theme.activate() it "deactivated event fires on .deactivate()", -> @@ -182,7 +182,7 @@ describe "Package", -> beforeEach -> packagePath = atom.project.getDirectories()[0]?.resolve('packages/package-with-different-directory-name') - metadata = Package.loadMetadata(packagePath, true) + metadata = atom.packages.loadPackageMetadata(packagePath, true) it "uses the package name defined in package.json", -> expect(metadata.name).toBe 'package-with-a-totally-different-name' diff --git a/src/package-manager.coffee b/src/package-manager.coffee index b6d708d3a..c75268339 100644 --- a/src/package-manager.coffee +++ b/src/package-manager.coffee @@ -1,8 +1,10 @@ path = require 'path' +normalizePackageData = null _ = require 'underscore-plus' {Emitter} = require 'event-kit' fs = require 'fs-plus' +CSON = require 'season' ServiceHub = require 'service-hub' Package = require './package' @@ -35,6 +37,7 @@ class PackageManager @packageDirPaths.push(path.join(configDirPath, "dev", "packages")) @packageDirPaths.push(path.join(configDirPath, "packages")) + @packagesCache = require('../package.json')?._atomPackages ? {} @loadedPackages = {} @activePackages = {} @packageStates = {} @@ -269,7 +272,7 @@ class PackageManager packages = [] for packagePath in @getAvailablePackagePaths() name = path.basename(packagePath) - metadata = @getLoadedPackage(name)?.metadata ? Package.loadMetadata(packagePath, true) + metadata = @getLoadedPackage(name)?.metadata ? @loadPackageMetadata(packagePath, true) packages.push(metadata) packages @@ -292,7 +295,7 @@ class PackageManager @packageDependencies hasAtomEngine: (packagePath) -> - metadata = Package.loadMetadata(packagePath, true) + metadata = @loadPackageMetadata(packagePath, true) metadata?.engines?.atom? unobserveDisabledPackages: -> @@ -340,7 +343,7 @@ class PackageManager return pack if pack = @getLoadedPackage(name) try - metadata = Package.loadMetadata(packagePath) ? {} + metadata = @loadPackageMetadata(packagePath) ? {} catch error @handleMetadataError(error, packagePath) return null @@ -351,9 +354,9 @@ class PackageManager return null if metadata.theme - pack = new ThemePackage(packagePath, metadata) + pack = new ThemePackage({path: packagePath, metadata, packageManager: this}) else - pack = new Package(packagePath, metadata) + pack = new Package({path: packagePath, metadata, packageManager: this}) pack.load() @loadedPackages[pack.name] = pack @emitter.emit 'did-load-package', pack @@ -461,3 +464,35 @@ class PackageManager for pack in @getActivePackages() when pack.getType() isnt 'theme' pack.reloadStylesheets?() return + + isBundledPackagePath: (packagePath) -> + if @devMode + return false unless @resourcePath.startsWith("#{process.resourcesPath}#{path.sep}") + + @resourcePathWithTrailingSlash ?= "#{@resourcePath}#{path.sep}" + packagePath?.startsWith(@resourcePathWithTrailingSlash) + + loadPackageMetadata: (packagePath, ignoreErrors=false) -> + packageName = path.basename(packagePath) + if @isBundledPackagePath(packagePath) + metadata = packagesCache[packageName]?.metadata + unless metadata? + if metadataPath = CSON.resolve(path.join(packagePath, 'package')) + try + metadata = CSON.readFileSync(metadataPath) + @normalizePackageMetadata(metadata) + catch error + throw error unless ignoreErrors + + metadata ?= {} + unless typeof metadata.name is 'string' and metadata.name.length > 0 + metadata.name = packageName + + metadata + + normalizePackageMetadata: (metadata) -> + unless metadata?._id + normalizePackageData ?= require 'normalize-package-data' + normalizePackageData(metadata) + if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string' + metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') diff --git a/src/package.coffee b/src/package.coffee index dcb188584..584000b57 100644 --- a/src/package.coffee +++ b/src/package.coffee @@ -1,5 +1,4 @@ path = require 'path' -normalizePackageData = null _ = require 'underscore-plus' async = require 'async' @@ -11,44 +10,10 @@ ModuleCache = require './module-cache' ScopedProperties = require './scoped-properties' BufferedProcess = require './buffered-process' -packagesCache = require('../package.json')?._atomPackages ? {} - # Extended: Loads and activates a package's main module and resources such as # stylesheets, keymaps, grammar, editor properties, and menus. module.exports = class Package - @isBundledPackagePath: (packagePath) -> - if atom.packages.devMode - return false unless atom.packages.resourcePath.startsWith("#{process.resourcesPath}#{path.sep}") - - @resourcePathWithTrailingSlash ?= "#{atom.packages.resourcePath}#{path.sep}" - packagePath?.startsWith(@resourcePathWithTrailingSlash) - - @normalizeMetadata: (metadata) -> - unless metadata?._id - normalizePackageData ?= require 'normalize-package-data' - normalizePackageData(metadata) - if metadata.repository?.type is 'git' and typeof metadata.repository.url is 'string' - metadata.repository.url = metadata.repository.url.replace(/^git\+/, '') - - @loadMetadata: (packagePath, ignoreErrors=false) -> - packageName = path.basename(packagePath) - if @isBundledPackagePath(packagePath) - metadata = packagesCache[packageName]?.metadata - unless metadata? - if metadataPath = CSON.resolve(path.join(packagePath, 'package')) - try - metadata = CSON.readFileSync(metadataPath) - @normalizeMetadata(metadata) - catch error - throw error unless ignoreErrors - - metadata ?= {} - unless typeof metadata.name is 'string' and metadata.name.length > 0 - metadata.name = packageName - - metadata - keymaps: null menus: null stylesheets: null @@ -64,10 +29,10 @@ class Package Section: Construction ### - constructor: (@path, @metadata) -> + constructor: ({@path, @metadata, @packageManager}) -> @emitter = new Emitter - @metadata ?= Package.loadMetadata(@path) - @bundledPackage = Package.isBundledPackagePath(@path) + @metadata ?= @packageManager.loadPackageMetadata(@path) + @bundledPackage = @packageManager.isBundledPackagePath(@path) @name = @metadata?.name ? path.basename(@path) ModuleCache.add(@path, @metadata) @reset() @@ -251,15 +216,15 @@ class Package return loadKeymaps: -> - if @bundledPackage and packagesCache[@name]? - @keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of packagesCache[@name].keymaps) + if @bundledPackage and @packageManager.packagesCache[@name]? + @keymaps = (["#{atom.packages.resourcePath}#{path.sep}#{keymapPath}", keymapObject] for keymapPath, keymapObject of @packageManager.packagesCache[@name].keymaps) else @keymaps = @getKeymapPaths().map (keymapPath) -> [keymapPath, CSON.readFileSync(keymapPath) ? {}] return loadMenus: -> - if @bundledPackage and packagesCache[@name]? - @menus = (["#{atom.packages.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of packagesCache[@name].menus) + if @bundledPackage and @packageManager.packagesCache[@name]? + @menus = (["#{atom.packages.resourcePath}#{path.sep}#{menuPath}", menuObject] for menuPath, menuObject of @packageManager.packagesCache[@name].menus) else @menus = @getMenuPaths().map (menuPath) -> [menuPath, CSON.readFileSync(menuPath) ? {}] return @@ -427,9 +392,9 @@ class Package return @mainModulePath if @resolvedMainModulePath @resolvedMainModulePath = true - if @bundledPackage and packagesCache[@name]? - if packagesCache[@name].main - @mainModulePath = "#{atom.packages.resourcePath}#{path.sep}#{packagesCache[@name].main}" + if @bundledPackage and @packageManager.packagesCache[@name]? + if @packageManager.packagesCache[@name].main + @mainModulePath = "#{atom.packages.resourcePath}#{path.sep}#{@packageManager.packagesCache[@name].main}" else @mainModulePath = null else