const PackageManager = require('./PackageManager') class APTManager extends PackageManager { _command_install_package = 'apt-get install -y %%PACKAGE%%' _command_uninstall_package = 'apt-get purge -y %%PACKAGE%%' _command_update_package = 'apt-get upgrade -y %%PACKAGE%%' _command_reinstall_package = 'apt-get install -y --reinstall %%PACKAGE%%' _command_clear_cache = 'apt-get clean' _command_count_installed = 'dpkg --list | wc -l' _command_count_available = 'apt-cache pkgnames | wc -l' _command_add_repo = `add-apt-repository '%%URI%%` _command_preflight = 'apt-get update' _status_keymap = { package: 'name', filename: 'source', section: 'repository', 'description-en': 'summary', } async status(pkg) { await this.preflight() const result = await this._host.execute(`apt-cache show ${pkg}`) if ( ![0, 100].includes(result.exit_code) ) { throw new Error('Unable to determine package information: '+result.stderr.join('\n')) } if ( result.exit_code === 100 ) { return { name: pkg, state: this.constructor.PACKAGE_STATE_UNKNOWN, } } const data = {} let last_data_key = false for ( const line of result.clean_out ) { if ( last_data_key && line.startsWith(' ') ) { data[last_data_key] += line } else { const parts = line.trim().split(':') const key = parts[0].toLowerCase() const value = parts.slice(1).join(':').trim() data[key] = value last_data_key = key } } for ( const key in this._status_keymap ) { if ( !this._status_keymap.hasOwnProperty(key) ) continue if ( data[key] ) { data[this._status_keymap[key]] = data[key] delete data[key] } } // check installation state const install_result = await this._host.execute(`dpkg -s ${pkg}`) data.state = install_result.exit_code === 0 ? this.constructor.PACKAGE_STATE_INSTALLED : this.constructor.PACKAGE_STATE_AVAILABLE return data } async list_updates() { await this.preflight() const result = await this._host.execute(`apt-get --just-print upgrade`) if ( result.exit_code !== 0 ) { throw new Error('Unable to determine packages for update: '+result.stderr.join('\n')) } let start_index = -1 let end_index = -1 for ( let i in result.clean_out ) { const line = result.clean_out[i] if ( line.toLowerCase().indexOf('packages will be upgraded') > -1 ) { start_index = Number(i)+1 } else if ( start_index > -1 && i >= start_index ) { if ( line.indexOf('newly installed,') > -1 ) break else { end_index = Number(i) } } } const package_strings = result.clean_out.slice(start_index, end_index+1).join(' ').split(' ').filter(Boolean).map(x => x.trim()) const updates = result.clean_out.filter(x => x.startsWith('Inst ')).map(x => { x = x.substring(5) x = x.split(' ') const data = { name: x[0], version: x[1].slice(1, -1), repository: x[3].replace(/,/g, ''), architecture: x.reverse()[0].replace(/[\[\])(]/g, '') } return data }).filter(x => package_strings.includes(x.name)) return updates } async list_repos() { await this.preflight() const result = await this._host.execute(`apt-cache policy`) if ( result.exit_code !== 0 ) { throw new Error('Unable to read repository list: '+result.stderr.join('\n')) } const lines = [] for ( const line of result.clean_out ) { if ( line.trim().startsWith('500') ) { lines.push(line) } else if ( line.toLowerCase().startsWith('pinned packages') ) { break } } return lines.map(x => x.trim()).filter(x => x.startsWith('500')).map(x => x.split(' ')[2]) } async list_installed() { const result = await this._host.execute(`dpkg --list`) if ( result.exit_code !== 0 ) { throw new Error('Unable to determine installed packages: '+result.stderr.join('\n')) } let header_line = result.clean_out.filter(x => x.trim().startsWith('+'))[0] let drop_count = 0 while ( header_line.startsWith('+') ) { drop_count += 1 header_line = header_line.substring(1) } let start_at = 0 for ( let i in result.clean_out ) { if ( result.clean_out[i].startsWith('+') ) { start_at = Number(i)+1 break } } return result.clean_out.slice(start_at).map(x => { x = x.substring(drop_count).trim().split(' ').filter(Boolean) return { name: x[0], version: x[1], architecture: x[2], summary: x.slice(3).join(' ') } }) } async search(pkg) { await this.preflight() const result = await this._host.execute(`apt-cache search ${pkg}`) if ( result.exit_code !== 0 ) { throw new Error('Unable to search the package cache: '+result.stderr.join('\n')) } const results = [] for ( const line of result.clean_out ) { const parts = line.trim().split(' - ').map(x => x.trim()) results.push({ name: parts[0], summary: parts[1] }) } return results } async preflight() { const result = await this._host.execute(this._command_preflight) if ( result.exit_code !== 0 ) { throw new Error('Error encountered during preflight for APTManager: '+result.stderr.join('\n')) } } } module.exports = exports = APTManager