mirror of
https://github.com/atom/atom.git
synced 2026-01-26 07:19:06 -05:00
Merge pull request #18104 from atom/migrate-incompatible-packages-package
➡️ Migrate core package 'incompatible-packages' into ./packages
This commit is contained in:
3
package-lock.json
generated
3
package-lock.json
generated
@@ -2771,8 +2771,7 @@
|
||||
}
|
||||
},
|
||||
"incompatible-packages": {
|
||||
"version": "https://www.atom.io/api/packages/incompatible-packages/versions/0.27.3/tarball",
|
||||
"integrity": "sha512-OlkFBSpvHH7dUfYQTlcgTXEa+sjr9Es8d2lNPGPS2O5Rp5MiRKcnovQoMtaF3fkcuV2O7onim45ldFjbl4qdog==",
|
||||
"version": "file:packages/incompatible-packages",
|
||||
"requires": {
|
||||
"etch": "^0.12.2"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"grammar-selector": "https://www.atom.io/api/packages/grammar-selector/versions/0.50.1/tarball",
|
||||
"grim": "1.5.0",
|
||||
"image-view": "https://www.atom.io/api/packages/image-view/versions/0.63.1/tarball",
|
||||
"incompatible-packages": "https://www.atom.io/api/packages/incompatible-packages/versions/0.27.3/tarball",
|
||||
"incompatible-packages": "file:packages/incompatible-packages",
|
||||
"jasmine-json": "~0.0",
|
||||
"jasmine-reporters": "1.1.0",
|
||||
"jasmine-tagged": "^1.1.4",
|
||||
@@ -207,7 +207,7 @@
|
||||
"go-to-line": "0.33.0",
|
||||
"grammar-selector": "0.50.1",
|
||||
"image-view": "0.63.1",
|
||||
"incompatible-packages": "0.27.3",
|
||||
"incompatible-packages": "file:./packages/incompatible-packages",
|
||||
"keybinding-resolver": "0.38.4",
|
||||
"line-ending-selector": "0.7.7",
|
||||
"link": "0.31.6",
|
||||
|
||||
@@ -38,7 +38,7 @@ See [RFC 003](https://github.com/atom/atom/blob/master/docs/rfcs/003-consolidate
|
||||
| **go-to-line** | [`atom/go-to-line`][go-to-line] | [#17844](https://github.com/atom/atom/issues/17844) |
|
||||
| **grammar-selector** | [`atom/grammar-selector`][grammar-selector] | [#17845](https://github.com/atom/atom/issues/17845) |
|
||||
| **image-view** | [`atom/image-view`][image-view] | |
|
||||
| **incompatible-packages** | [`atom/incompatible-packages`][incompatible-packages] | [#17846](https://github.com/atom/atom/issues/17846) |
|
||||
| **incompatible-packages** | [`./packages/incompatible-packages`][./incompatible-packages] | [#17846](https://github.com/atom/atom/issues/17846) |
|
||||
| **keybinding-resolver** | [`atom/keybinding-resolver`][keybinding-resolver] | |
|
||||
| **language-c** | [`atom/language-c`][language-c] | |
|
||||
| **language-clojure** | [`atom/language-clojure`][language-clojure] | |
|
||||
|
||||
3
packages/incompatible-packages/.gitignore
vendored
Normal file
3
packages/incompatible-packages/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
node_modules
|
||||
20
packages/incompatible-packages/LICENSE.md
Normal file
20
packages/incompatible-packages/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2014 GitHub Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
6
packages/incompatible-packages/README.md
Normal file
6
packages/incompatible-packages/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Incompatible Packages package
|
||||
|
||||
Displays a list of installed Atom packages that have native module
|
||||
dependencies that are not compatible with the current version of Atom.
|
||||
|
||||

|
||||
@@ -0,0 +1,228 @@
|
||||
/** @babel */
|
||||
/** @jsx etch.dom */
|
||||
|
||||
import {BufferedProcess} from 'atom'
|
||||
import etch from 'etch'
|
||||
|
||||
import VIEW_URI from './view-uri'
|
||||
const REBUILDING = 'rebuilding'
|
||||
const REBUILD_FAILED = 'rebuild-failed'
|
||||
const REBUILD_SUCCEEDED = 'rebuild-succeeded'
|
||||
|
||||
export default class IncompatiblePackagesComponent {
|
||||
constructor (packageManager) {
|
||||
this.rebuildStatuses = new Map
|
||||
this.rebuildFailureOutputs = new Map
|
||||
this.rebuildInProgress = false
|
||||
this.rebuiltPackageCount = 0
|
||||
this.packageManager = packageManager
|
||||
this.loaded = false
|
||||
etch.initialize(this)
|
||||
|
||||
if (this.packageManager.getActivePackages().length > 0) {
|
||||
this.populateIncompatiblePackages()
|
||||
} else {
|
||||
global.setImmediate(this.populateIncompatiblePackages.bind(this))
|
||||
}
|
||||
|
||||
this.element.addEventListener('click', (event) => {
|
||||
if (event.target === this.refs.rebuildButton) {
|
||||
this.rebuildIncompatiblePackages()
|
||||
} else if (event.target === this.refs.reloadButton) {
|
||||
atom.reload()
|
||||
} else if (event.target.classList.contains('view-settings')) {
|
||||
atom.workspace.open(`atom://config/packages/${event.target.package.name}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
update () {}
|
||||
|
||||
render () {
|
||||
if (!this.loaded) {
|
||||
return <div className='incompatible-packages padded'>Loading...</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='incompatible-packages padded native-key-bindings' tabIndex='-1'>
|
||||
{this.renderHeading()}
|
||||
{this.renderIncompatiblePackageList()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderHeading () {
|
||||
if (this.incompatiblePackages.length > 0) {
|
||||
if (this.rebuiltPackageCount > 0) {
|
||||
let alertClass =
|
||||
(this.rebuiltPackageCount === this.incompatiblePackages.length)
|
||||
? 'alert-success icon-check'
|
||||
: 'alert-warning icon-bug'
|
||||
|
||||
return (
|
||||
<div className={'alert icon ' + alertClass}>
|
||||
{this.rebuiltPackageCount} of {this.incompatiblePackages.length} packages
|
||||
were rebuilt successfully. Reload Atom to activate them.
|
||||
|
||||
<button ref='reloadButton' className='btn pull-right'>
|
||||
Reload Atom
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div className='alert alert-danger icon icon-bug'>
|
||||
Some installed packages could not be loaded because they contain native
|
||||
modules that were compiled for an earlier version of Atom.
|
||||
|
||||
<button ref='rebuildButton' className='btn pull-right' disabled={this.rebuildInProgress}>
|
||||
Rebuild Packages
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<div className='alert alert-success icon icon-check'>
|
||||
None of your packages contain incompatible native modules.
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
renderIncompatiblePackageList () {
|
||||
return (
|
||||
<div>{
|
||||
this.incompatiblePackages.map(this.renderIncompatiblePackage.bind(this))
|
||||
}</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderIncompatiblePackage (pack) {
|
||||
let rebuildStatus = this.rebuildStatuses.get(pack)
|
||||
|
||||
return (
|
||||
<div className={'incompatible-package'}>
|
||||
{this.renderRebuildStatusIndicator(rebuildStatus)}
|
||||
<button className='btn view-settings icon icon-gear pull-right' package={pack}>Package Settings</button>
|
||||
<h4 className='heading'>
|
||||
{pack.name} {pack.metadata.version}
|
||||
</h4>
|
||||
{
|
||||
rebuildStatus
|
||||
? this.renderRebuildOutput(pack)
|
||||
: this.renderIncompatibleModules(pack)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderRebuildStatusIndicator (rebuildStatus) {
|
||||
if (rebuildStatus === REBUILDING) {
|
||||
return (
|
||||
<div className='badge badge-info pull-right icon icon-gear'>
|
||||
Rebuilding
|
||||
</div>
|
||||
)
|
||||
} else if (rebuildStatus === REBUILD_SUCCEEDED) {
|
||||
return (
|
||||
<div className='badge badge-success pull-right icon icon-check'>
|
||||
Rebuild Succeeded
|
||||
</div>
|
||||
)
|
||||
} else if (rebuildStatus === REBUILD_FAILED) {
|
||||
return (
|
||||
<div className='badge badge-error pull-right icon icon-x'>
|
||||
Rebuild Failed
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
renderRebuildOutput (pack) {
|
||||
if (this.rebuildStatuses.get(pack) === REBUILD_FAILED) {
|
||||
return <pre>{this.rebuildFailureOutputs.get(pack)}</pre>
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
renderIncompatibleModules (pack) {
|
||||
return (
|
||||
<ul>{
|
||||
pack.incompatibleModules.map((nativeModule) =>
|
||||
<li>
|
||||
<div className='icon icon-file-binary'>
|
||||
{nativeModule.name}@{nativeModule.version || 'unknown'} – <span className='text-warning'>{nativeModule.error}</span>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}</ul>
|
||||
)
|
||||
}
|
||||
|
||||
populateIncompatiblePackages () {
|
||||
this.incompatiblePackages =
|
||||
this.packageManager
|
||||
.getLoadedPackages()
|
||||
.filter(pack => !pack.isCompatible())
|
||||
|
||||
for (let pack of this.incompatiblePackages) {
|
||||
let buildFailureOutput = pack.getBuildFailureOutput()
|
||||
if (buildFailureOutput) {
|
||||
this.setPackageStatus(pack, REBUILD_FAILED)
|
||||
this.setRebuildFailureOutput(pack, buildFailureOutput)
|
||||
}
|
||||
}
|
||||
|
||||
this.loaded = true
|
||||
etch.update(this)
|
||||
}
|
||||
|
||||
async rebuildIncompatiblePackages () {
|
||||
this.rebuildInProgress = true
|
||||
let rebuiltPackageCount = 0
|
||||
for (let pack of this.incompatiblePackages) {
|
||||
this.setPackageStatus(pack, REBUILDING)
|
||||
let {code, stderr} = await pack.rebuild()
|
||||
if (code === 0) {
|
||||
this.setPackageStatus(pack, REBUILD_SUCCEEDED)
|
||||
rebuiltPackageCount++
|
||||
} else {
|
||||
this.setRebuildFailureOutput(pack, stderr)
|
||||
this.setPackageStatus(pack, REBUILD_FAILED)
|
||||
}
|
||||
}
|
||||
this.rebuildInProgress = false
|
||||
this.rebuiltPackageCount = rebuiltPackageCount
|
||||
etch.update(this)
|
||||
}
|
||||
|
||||
setPackageStatus (pack, status) {
|
||||
this.rebuildStatuses.set(pack, status)
|
||||
etch.update(this)
|
||||
}
|
||||
|
||||
setRebuildFailureOutput (pack, output) {
|
||||
this.rebuildFailureOutputs.set(pack, output)
|
||||
etch.update(this)
|
||||
}
|
||||
|
||||
getTitle () {
|
||||
return 'Incompatible Packages'
|
||||
}
|
||||
|
||||
getURI () {
|
||||
return VIEW_URI
|
||||
}
|
||||
|
||||
getIconName () {
|
||||
return 'package'
|
||||
}
|
||||
|
||||
serialize () {
|
||||
return {deserializer: 'IncompatiblePackagesComponent'}
|
||||
}
|
||||
}
|
||||
52
packages/incompatible-packages/lib/main.js
Normal file
52
packages/incompatible-packages/lib/main.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/** @babel */
|
||||
|
||||
import {Disposable, CompositeDisposable} from 'atom'
|
||||
import VIEW_URI from './view-uri'
|
||||
|
||||
let disposables = null
|
||||
|
||||
export function activate () {
|
||||
disposables = new CompositeDisposable()
|
||||
|
||||
disposables.add(atom.workspace.addOpener((uri) => {
|
||||
if (uri === VIEW_URI) {
|
||||
return deserializeIncompatiblePackagesComponent()
|
||||
}
|
||||
}))
|
||||
|
||||
disposables.add(atom.commands.add('atom-workspace', {
|
||||
'incompatible-packages:view': () => {
|
||||
atom.workspace.open(VIEW_URI)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
export function deactivate () {
|
||||
disposables.dispose()
|
||||
}
|
||||
|
||||
export function consumeStatusBar (statusBar) {
|
||||
let incompatibleCount = 0
|
||||
for (let pack of atom.packages.getLoadedPackages()) {
|
||||
if (!pack.isCompatible()) incompatibleCount++
|
||||
}
|
||||
|
||||
if (incompatibleCount > 0) {
|
||||
let icon = createIcon(incompatibleCount)
|
||||
let tile = statusBar.addRightTile({item: icon, priority: 200})
|
||||
icon.element.addEventListener('click', () => {
|
||||
atom.commands.dispatch(icon.element, 'incompatible-packages:view')
|
||||
})
|
||||
disposables.add(new Disposable(() => tile.destroy()))
|
||||
}
|
||||
}
|
||||
|
||||
export function deserializeIncompatiblePackagesComponent () {
|
||||
const IncompatiblePackagesComponent = require('./incompatible-packages-component')
|
||||
return new IncompatiblePackagesComponent(atom.packages)
|
||||
}
|
||||
|
||||
function createIcon (count) {
|
||||
const StatusIconComponent = require('./status-icon-component')
|
||||
return new StatusIconComponent({count})
|
||||
}
|
||||
22
packages/incompatible-packages/lib/status-icon-component.js
Normal file
22
packages/incompatible-packages/lib/status-icon-component.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/** @babel */
|
||||
/** @jsx etch.dom */
|
||||
|
||||
import etch from 'etch'
|
||||
|
||||
export default class StatusIconComponent {
|
||||
constructor ({count}) {
|
||||
this.count = count
|
||||
etch.initialize(this)
|
||||
}
|
||||
|
||||
update () {}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<div className='incompatible-packages-status inline-block text text-error'>
|
||||
<span className='icon icon-bug'></span>
|
||||
<span className='incompatible-packages-count'>{this.count}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
3
packages/incompatible-packages/lib/view-uri.js
Normal file
3
packages/incompatible-packages/lib/view-uri.js
Normal file
@@ -0,0 +1,3 @@
|
||||
/** @babel */
|
||||
|
||||
export default 'atom://incompatible-packages'
|
||||
24
packages/incompatible-packages/package.json
Normal file
24
packages/incompatible-packages/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "incompatible-packages",
|
||||
"main": "./lib/main",
|
||||
"version": "0.27.3",
|
||||
"description": "Show incompatible packages",
|
||||
"repository": "https://github.com/atom/atom",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"atom": ">0.50.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"etch": "^0.12.2"
|
||||
},
|
||||
"consumedServices": {
|
||||
"status-bar": {
|
||||
"versions": {
|
||||
"^1.0.0": "consumeStatusBar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"deserializers": {
|
||||
"IncompatiblePackagesComponent": "deserializeIncompatiblePackagesComponent"
|
||||
}
|
||||
}
|
||||
0
packages/incompatible-packages/spec/fixtures/incompatible-package/bad.js
vendored
Normal file
0
packages/incompatible-packages/spec/fixtures/incompatible-package/bad.js
vendored
Normal file
5
packages/incompatible-packages/spec/fixtures/incompatible-package/package.json
vendored
Normal file
5
packages/incompatible-packages/spec/fixtures/incompatible-package/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "incompatible-package",
|
||||
"version": "1.0.0",
|
||||
"main": "./bad.js"
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/** @babel */
|
||||
|
||||
import etch from 'etch'
|
||||
import IncompatiblePackagesComponent from '../lib/incompatible-packages-component'
|
||||
|
||||
describe('IncompatiblePackagesComponent', () => {
|
||||
let packages, etchScheduler
|
||||
|
||||
beforeEach(() => {
|
||||
etchScheduler = etch.getScheduler()
|
||||
|
||||
packages = [
|
||||
{
|
||||
name: 'incompatible-1',
|
||||
isCompatible () {
|
||||
return false
|
||||
},
|
||||
rebuild: function () {
|
||||
return new Promise((resolve) => this.resolveRebuild = resolve)
|
||||
},
|
||||
getBuildFailureOutput () {
|
||||
return null
|
||||
},
|
||||
path: '/Users/joe/.atom/packages/incompatible-1',
|
||||
metadata: {
|
||||
repository: 'https://github.com/atom/incompatible-1',
|
||||
version: '1.0.0'
|
||||
},
|
||||
incompatibleModules: [
|
||||
{name: 'x', version: '1.0.0', error: 'Expected version X, got Y'},
|
||||
{name: 'y', version: '1.0.0', error: 'Expected version X, got Z'}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'incompatible-2',
|
||||
isCompatible () {
|
||||
return false
|
||||
},
|
||||
rebuild () {
|
||||
return new Promise((resolve) => this.resolveRebuild = resolve)
|
||||
},
|
||||
getBuildFailureOutput () {
|
||||
return null
|
||||
},
|
||||
path: '/Users/joe/.atom/packages/incompatible-2',
|
||||
metadata: {
|
||||
repository: 'https://github.com/atom/incompatible-2',
|
||||
version: '1.0.0'
|
||||
},
|
||||
incompatibleModules: [
|
||||
{name: 'z', version: '1.0.0', error: 'Expected version X, got Y'}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'compatible',
|
||||
isCompatible () {
|
||||
return true
|
||||
},
|
||||
rebuild () {
|
||||
throw new Error('Should not rebuild a compatible package')
|
||||
},
|
||||
getBuildFailureOutput () {
|
||||
return null
|
||||
},
|
||||
path: '/Users/joe/.atom/packages/b',
|
||||
metadata: {
|
||||
repository: 'https://github.com/atom/b',
|
||||
version: '1.0.0'
|
||||
},
|
||||
incompatibleModules: [],
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
describe('when packages have not finished loading', () => {
|
||||
it('delays rendering incompatible packages until the end of the tick', () => {
|
||||
waitsForPromise(async () => {
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => [],
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
|
||||
expect(element.querySelectorAll('.incompatible-package').length).toEqual(0)
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
|
||||
expect(element.querySelectorAll('.incompatible-package').length).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no incompatible packages', () => {
|
||||
it('does not render incompatible packages or the rebuild button', () => {
|
||||
waitsForPromise(async () => {
|
||||
expect(packages[2].isCompatible()).toBe(true)
|
||||
let compatiblePackages = [packages[2]]
|
||||
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => compatiblePackages,
|
||||
getLoadedPackages: () => compatiblePackages
|
||||
})
|
||||
let {element} = component
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
|
||||
expect(element.querySelectorAll('.incompatible-package').length).toBe(0)
|
||||
expect(element.querySelector('button')).toBeNull()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when some packages previously failed to rebuild', () => {
|
||||
it('renders them with failed build status and error output', () => {
|
||||
waitsForPromise(async () => {
|
||||
packages[1].getBuildFailureOutput = function () {
|
||||
return 'The build failed'
|
||||
}
|
||||
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => packages,
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
let packageElement = element.querySelector('.incompatible-package:nth-child(2)')
|
||||
|
||||
expect(packageElement.querySelector('.badge').textContent).toBe('Rebuild Failed')
|
||||
expect(packageElement.querySelector('pre').textContent).toBe('The build failed')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are incompatible packages', () => {
|
||||
it('renders incompatible packages and the rebuild button', () => {
|
||||
waitsForPromise(async () => {
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => packages,
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
|
||||
expect(element.querySelectorAll('.incompatible-package').length).toEqual(2)
|
||||
expect(element.querySelector('button')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the "Rebuild All" button is clicked', () => {
|
||||
it('rebuilds every incompatible package, updating each package\'s view with status', () => {
|
||||
waitsForPromise(async () => {
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => packages,
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
|
||||
component.refs.rebuildButton.dispatchEvent(new CustomEvent('click', {bubbles: true}))
|
||||
await etchScheduler.getNextUpdatePromise() // view update
|
||||
|
||||
expect(component.refs.rebuildButton.disabled).toBe(true)
|
||||
|
||||
expect(packages[0].resolveRebuild).toBeDefined()
|
||||
|
||||
expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuilding')
|
||||
expect(element.querySelector('.incompatible-package:nth-child(2) .badge')).toBeNull()
|
||||
|
||||
packages[0].resolveRebuild({code: 0}) // simulate rebuild success
|
||||
await etchScheduler.getNextUpdatePromise() // view update
|
||||
|
||||
expect(packages[1].resolveRebuild).toBeDefined()
|
||||
|
||||
expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuild Succeeded')
|
||||
expect(element.querySelector('.incompatible-package:nth-child(2) .badge').textContent).toBe('Rebuilding')
|
||||
|
||||
packages[1].resolveRebuild({code: 12, stderr: 'This is an error from the test!'}) // simulate rebuild failure
|
||||
await etchScheduler.getNextUpdatePromise() // view update
|
||||
|
||||
expect(element.querySelector('.incompatible-package:nth-child(1) .badge').textContent).toBe('Rebuild Succeeded')
|
||||
expect(element.querySelector('.incompatible-package:nth-child(2) .badge').textContent).toBe('Rebuild Failed')
|
||||
expect(element.querySelector('.incompatible-package:nth-child(2) pre').textContent).toBe('This is an error from the test!')
|
||||
})
|
||||
})
|
||||
|
||||
it('displays a prompt to reload Atom when the packages finish rebuilding', () => {
|
||||
waitsForPromise(async () => {
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => packages,
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
jasmine.attachToDOM(element)
|
||||
await etchScheduler.getNextUpdatePromise() // view update
|
||||
|
||||
component.refs.rebuildButton.dispatchEvent(new CustomEvent('click', {bubbles: true}))
|
||||
expect(packages[0].resolveRebuild({code: 0}))
|
||||
await new Promise(global.setImmediate)
|
||||
expect(packages[1].resolveRebuild({code: 0}))
|
||||
|
||||
await etchScheduler.getNextUpdatePromise() // view update
|
||||
|
||||
expect(component.refs.reloadButton).toBeDefined()
|
||||
expect(element.querySelector('.alert').textContent).toMatch(/2 of 2/)
|
||||
|
||||
spyOn(atom, 'reload')
|
||||
component.refs.reloadButton.dispatchEvent(new CustomEvent('click', {bubbles: true}))
|
||||
expect(atom.reload).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the "Package Settings" button is clicked', () => {
|
||||
it('opens the settings panel for the package', () => {
|
||||
waitsForPromise(async () => {
|
||||
let component =
|
||||
new IncompatiblePackagesComponent({
|
||||
getActivePackages: () => packages,
|
||||
getLoadedPackages: () => packages
|
||||
})
|
||||
let {element} = component
|
||||
jasmine.attachToDOM(element)
|
||||
|
||||
await etchScheduler.getNextUpdatePromise()
|
||||
|
||||
spyOn(atom.workspace, 'open')
|
||||
element.querySelector('.incompatible-package:nth-child(2) button').dispatchEvent(new CustomEvent('click', {bubbles: true}))
|
||||
expect(atom.workspace.open).toHaveBeenCalledWith('atom://config/packages/incompatible-2')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,77 @@
|
||||
/** @babel */
|
||||
|
||||
import path from 'path'
|
||||
import IncompatiblePackagesComponent from '../lib/incompatible-packages-component'
|
||||
import StatusIconComponent from '../lib/status-icon-component'
|
||||
|
||||
// This exists only so that CI passes on both Atom 1.6 and Atom 1.8+.
|
||||
function findStatusBar () {
|
||||
if (typeof atom.workspace.getFooterPanels === 'function') {
|
||||
const footerPanels = atom.workspace.getFooterPanels()
|
||||
if (footerPanels.length > 0) {
|
||||
return footerPanels[0].getItem()
|
||||
}
|
||||
}
|
||||
|
||||
return atom.workspace.getBottomPanels()[0].getItem()
|
||||
}
|
||||
|
||||
describe('Incompatible packages', () => {
|
||||
let statusBar
|
||||
|
||||
beforeEach(() => {
|
||||
atom.views.getView(atom.workspace)
|
||||
|
||||
waitsForPromise(() => atom.packages.activatePackage('status-bar'))
|
||||
|
||||
runs(() => {
|
||||
statusBar = findStatusBar()
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are packages with incompatible native modules', () => {
|
||||
beforeEach(() => {
|
||||
let incompatiblePackage = atom.packages.loadPackage(
|
||||
path.join(__dirname, 'fixtures', 'incompatible-package')
|
||||
)
|
||||
spyOn(incompatiblePackage, 'isCompatible').andReturn(false)
|
||||
incompatiblePackage.incompatibleModules = []
|
||||
waitsForPromise(() => atom.packages.activatePackage("incompatible-packages"))
|
||||
|
||||
waits(1)
|
||||
})
|
||||
|
||||
it('adds an icon to the status bar', () => {
|
||||
let statusBarIcon = statusBar.getRightTiles()[0].getItem()
|
||||
expect(statusBarIcon.constructor).toBe(StatusIconComponent)
|
||||
})
|
||||
|
||||
describe('clicking the icon', () => {
|
||||
it('displays the incompatible packages view in a pane', () => {
|
||||
let statusBarIcon = statusBar.getRightTiles()[0].getItem()
|
||||
statusBarIcon.element.dispatchEvent(new MouseEvent('click'))
|
||||
|
||||
let activePaneItem
|
||||
waitsFor(() => (activePaneItem = atom.workspace.getActivePaneItem()))
|
||||
|
||||
runs(() => {
|
||||
expect(activePaneItem.constructor).toBe(IncompatiblePackagesComponent)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are no packages with incompatible native modules', () => {
|
||||
beforeEach(() => {
|
||||
waitsForPromise(() => atom.packages.activatePackage("incompatible-packages"))
|
||||
})
|
||||
|
||||
it('does not add an icon to the status bar', () => {
|
||||
let statusBarItemClasses = statusBar
|
||||
.getRightTiles()
|
||||
.map((tile) => tile.getItem().className)
|
||||
|
||||
expect(statusBarItemClasses).not.toContain('incompatible-packages')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,42 @@
|
||||
@import "ui-variables";
|
||||
|
||||
.incompatible-packages {
|
||||
background-color: @pane-item-background-color;
|
||||
overflow-y: scroll;
|
||||
|
||||
.incompatible-package {
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #d1d1d2;
|
||||
background-color: #fafafa;
|
||||
overflow: hidden;
|
||||
|
||||
.badge {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 2em;
|
||||
max-height: 25em;
|
||||
overflow: scroll;
|
||||
color: @text-color-error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.incompatible-packages-status {
|
||||
padding-left: 2px;
|
||||
}
|
||||
Reference in New Issue
Block a user