Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Di/ios provider/file and logs/qa 16207 #119

Merged
merged 9 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion lib/units/ios-device/support/storage.js → lib/units/base-device/support/storage.js
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import request from 'postman-request'
import logger from '../../../util/logger.js'
export default syrup.serial()
.define(options => {
const log = logger.createLogger('ios-device:support:storage')
const log = logger.createLogger('device:support:storage')
let plugin = Object.create(null)
plugin.store = function(type, stream, meta) {
let resolver = Promise.defer()
let args = {
url: url.resolve(options.storageUrl, util.format('s/upload/%s', type))
, headers: {
internal: 'Internal ' + meta.jwt
}
}
let req = request.post(args, function(err, res, body) {
if (err) {
Expand Down
2 changes: 1 addition & 1 deletion lib/units/device/plugins/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import wireutil from '../../../wire/util.js'
import adb from '../support/adb.js'
import router from '../../base-device/support/router.js'
import push from '../../base-device/support/push.js'
import storage from '../support/storage.js'
import storage from '../../base-device/support/storage.js'
export default syrup.serial()
.dependency(adb)
.dependency(router)
Expand Down
2 changes: 1 addition & 1 deletion lib/units/device/plugins/screen/capture.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import wireutil from '../../../../wire/util.js'
import adb from '../../support/adb.js'
import router from '../../../base-device/support/router.js'
import push from '../../../base-device/support/push.js'
import storage from '../../support/storage.js'
import storage from '../../../base-device/support/storage.js'
import minicap from '../../resources/minicap.js'
import display from '../util/display.js'
export default syrup.serial()
Expand Down
47 changes: 0 additions & 47 deletions lib/units/device/support/storage.js

This file was deleted.

4 changes: 3 additions & 1 deletion lib/units/ios-device/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ import wda from './plugins/wda.js'
import push from '../base-device/support/push.js'
import sub from '../base-device/support/sub.js'
import group from './plugins/group.js'
import storage from './support/storage.js'
import storage from '../base-device/support/storage.js'
import devicelog from './plugins/devicelog.js'
import stream from './plugins/screen/stream.js'
import install from './plugins/install.js'
import reboot from './plugins/reboot.js'
import clipboard from './plugins/clipboard.js'
import remotedebug from './plugins/remotedebug.js'
import filesystem from './plugins/filesystem.js'
export default (function(options) {
// Show serial number in logs
logger.setGlobalIdentifier(options.serial)
Expand All @@ -39,6 +40,7 @@ export default (function(options) {
.dependency(reboot)
.dependency(clipboard)
.dependency(remotedebug)
.dependency(filesystem)
.define(function(options, heartbeat, solo, info, wda) {
if (process.send) {
process.send('ready')
Expand Down
83 changes: 73 additions & 10 deletions lib/units/ios-device/plugins/devicelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import push from '../../base-device/support/push.js'
import router from '../../base-device/support/router.js'
import sub from '../../base-device/support/sub.js'
import group from './group.js'
import {IncompleteJsonParser} from 'incomplete-json-parser'

export default syrup
.serial()
export default syrup.serial()
.dependency(push)
.dependency(router)
.dependency(sub)
.dependency(group)
.define(function(options, push, router, group) {
.define(function(options, push, router, sub, group) {
const log = logger.createLogger('device:plugins:devicelog')

let DeviceLogger = {
Expand All @@ -31,17 +31,79 @@ export default syrup
, startLogging: async function(channel) {
DeviceLogger.setChannel(channel)
try {
DeviceLogger.stream = spawn('idb logs --udid ' + options.serial, {shell: true})
const realGroup = await group.get()
const parser = new IncompleteJsonParser()

DeviceLogger.stream = spawn('idb', ['log', '--udid', options.serial, '--', '--style', 'json'])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--style json is unrecognized on an iphone with ios 18.1.1 and idb-companion 1.1.8


DeviceLogger.stream.stdout.on('data', data => {
push.send([
this.channel
, wireutil.envelope(new wire.DeviceLogcatEntryMessage(options.serial, new Date().getTime() / 1000, DeviceLogger.stream.pid, DeviceLogger.stream.pid, 1, 'device:log:cat', data.toString()))
])
parser.write(data.toString())
let logs = parser.getObjects()
let threadId = 0
let processId = 0
let subsystem = '*'
let timestamp = new Date().getTime() / 1000
let message
logs.forEach(log => {
let logLevel = 2
switch (log.messageType) {
case 'Fatal': { logLevel = 7; break }
case 'Error': { logLevel = 6; break }
case 'Warning': { logLevel = 5; break }
case 'Default': { logLevel = 4; break }
case 'Activity': { logLevel = 3; break }
}

if (log.eventMessage) {
message = log.eventMessage
}
else if (log.formatString) {
message = log.formatString
}
else {
return
}

if (log.threadID) {
threadId = log.threadID
}

if (log.processID) {
processId = log.processID
}

if (log.timestamp) {
timestamp = log.timestamp
}

if (log.subsystem) {
subsystem = log.subsystem
}
else {
subsystem = '*'
}

push.send([
realGroup.group
, wireutil.envelope(new wire.DeviceLogcatEntryMessage(
options.serial
, Date.parse(timestamp) / 1000

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value of timestamp in case no timestamp could be found from the log line entry is not parseable
image

, processId
, threadId
, logLevel
, subsystem
, message
))
])
})
})

DeviceLogger.stream.stderr.on('data', data => {
console.log(data.toString())
})

DeviceLogger.stream.on('close', err => {
log.fatal('Unable to get devicelog', err)
log.warn('Stream is closed', err)
DeviceLogger.killLoggingProcess()
})
}
Expand All @@ -52,7 +114,6 @@ export default syrup

, killLoggingProcess: () => {
if (DeviceLogger.stream) {
process.kill(-DeviceLogger.stream.pid)
irdkwmnsb marked this conversation as resolved.
Show resolved Hide resolved
DeviceLogger.stream.kill()
DeviceLogger.stream = null
DeviceLogger.channel = ''
Expand All @@ -76,7 +137,9 @@ export default syrup
}
})
.on(wire.LogcatStopMessage, function(channel, data) {
const reply = wireutil.reply(options.serial)
DeviceLogger.killLoggingProcess()
push.send([channel, reply.okay('success')])
})
.on(wire.GroupMessage, function(channel, data) {
DeviceLogger.channel = channel
Expand Down
133 changes: 133 additions & 0 deletions lib/units/ios-device/plugins/filesystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import syrup from '@devicefarmer/stf-syrup'
import logger from '../../../util/logger.js'
import wire from '../../../wire/index.js'
import wireutil from '../../../wire/util.js'
import router from '../../base-device/support/router.js'
import push from '../../base-device/support/push.js'
import storage from '../../base-device/support/storage.js'
import {execFile} from 'child_process'
import path from 'path'
import fs from 'fs'
import {v4 as uuidv4} from 'uuid'
export default syrup.serial()
.dependency(router)
.dependency(push)
.dependency(storage)
.define(function(options, router, push, storage) {
const log = logger.createLogger('device:plugins:filesystem')
let plugin = Object.create(null)

const getIdbTarget = dir => {
let currentPath = dir.split('/')
let rootDir = currentPath[1]
if (['root', 'application', 'crashes'].indexOf(rootDir) !== -1) {
return rootDir
}
else {
return 'media'
}
}

router.on(wire.FileSystemGetMessage, function(channel, message) {
let reply = wireutil.reply(options.serial)
let file = message.file
log.info('Retrieving file "%s"', file)
let currentPath = file.split('/')
let target = getIdbTarget(file)
let tempFileName = `tmp_${uuidv4()}`

if (currentPath.length === 2) {
currentPath = ''
}
else {
currentPath = currentPath.slice(2).join('/').replace(' ', '\\ ')
}

execFile('idb', ['file', 'pull', `--${target}`, currentPath, `/tmp/${tempFileName}`, '--json', '--udid', options.serial],
(error, stdout, stderr) => {
if (error) {
log.warn('Unable to list directory "%s"', file, stderr)
}

storage.store('blob', path.basename(file), {
filename: path.basename(file)
, contentType: 'application/octet-stream'
}).then((file) => {
try {
push.send([
channel
, reply.okay('success', file)
])
}
catch (e) {
push.send([
channel
, reply.fail('error', e)
])
}
fs.unlink(`/tmp/${tempFileName}`, (err) => {
log.warn('Error while deleting file "%s"', file, err)
})
})
}
)
})
router.on(wire.FileSystemListMessage, function(channel, message) {
let reply = wireutil.reply(options.serial)
let dirs = []
let rootDir = message.dir
if (rootDir === '/') {
dirs = [
{name: 'root', mtime: '1970-01-01T00:00:00.000Z', atime: null, ctime: null, birthtime: null, mode: 16877, size: 0}
irdkwmnsb marked this conversation as resolved.
Show resolved Hide resolved
, {name: 'application', mtime: '1970-01-01T00:00:00.000Z', atime: null, ctime: null, birthtime: null, mode: 16877, size: 0}
, {name: 'crashes', mtime: '1970-01-01T00:00:00.000Z', atime: null, ctime: null, birthtime: null, mode: 16877, size: 0}
, {name: 'media', mtime: '1970-01-01T00:00:00.000Z', atime: null, ctime: null, birthtime: null, mode: 16877, size: 0}
]
push.send([
channel
, reply.okay('success', dirs)
])
}
let currentPath = message.dir.split('/')
let target = getIdbTarget(message.dir)

if (currentPath.length === 2) {
currentPath = ''
}
else {
currentPath = currentPath.slice(2).join('/').replace(' ', '\\ ')
}

execFile('idb', ['file', 'list', `--${target}`, currentPath, '--json', '--udid', options.serial],
(error, stdout, stderr) => {
if (error) {
log.warn('Unable to list directory "%s"', message.dir, stderr)
push.send([
channel
, reply.fail(error.message)
])
return
}

let rawDirs = JSON.parse(stdout)
let entries = []
rawDirs.forEach(dir => {
let name = dir.path
let mode = 0o40365
if (name.includes('.')) {
mode = 0o555
}
entries.push({
name: name, mtime: '1970-01-01T00:00:00.000Z', atime: null, ctime: null, birthtime: null, mode: mode, size: 0
})
})

push.send([
channel
, reply.okay('success', entries)
])
}
)
})
return plugin
})
6 changes: 2 additions & 4 deletions lib/units/ios-device/plugins/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default syrup.serial()
const baseUrl = iosutil.getUri(options.wdaHost, options.wdaPort)
let currentGroup = null
let plugin = new events.EventEmitter()
plugin.get = Promise.method(() => {
plugin.get = Promise.method(function() {
if (!currentGroup) {
throw new grouputil.NoGroupError()
}
Expand Down Expand Up @@ -193,9 +193,7 @@ export default syrup.serial()
.on(wire.GroupMessage, (channel, message) => {
let reply = wireutil.reply(options.serial)
// grouputil.match(ident, message.requirements)
Promise.method(() => {
return plugin.join(message.owner, message.timeout, message.usage)
})()
plugin.join(message.owner, message.timeout, message.usage)
.then(() => {
push.send([
channel
Expand Down
Loading