-
Notifications
You must be signed in to change notification settings - Fork 52
Creating A Report
First, I'd recommend extracting the contents of interest that you would like to build your report on using the backup.files
export function:
ibackuptool -b $UDID -r 'backup.files' --extract ~/Desktop
Next, we can start with a basic module. This one doesn't do much, but it shows the anatomy of how they should work.
module.exports = {
/**
* The reporting API version. This should be set to 4.
*/
version: 4,
/**
* Report name. This should match the nesting found in the reports.js file.
*/
name: 'ibackuptool.example',
/**
* Human readable description of the file
*/
description: `Example Report module.`,
/**
* Optional flag requiring a backup parameter to be present in order to run this report.
*/
requiresBackup: true,
/**
* Run on a v4 lib / backup object.
* The run() function must return a promise, which always resolves to valid data.
* If the files aren't in the backup or aren't formatted in a known way, we reject
* and print the error message for the user.
* @param {object} lib standard lib, contains lib.run() function.
* @param {object} options options object.
* @returns {Promise.<Object>}
*/
run (lib, { backup }) {
return new Promise((resolve, reject) => {
// resolve to valid data.
// Typically, this would be "raw" data containing as much info as possible.
// Se below for data formatting.
resolve([{
name: 'example1',
data: {
code: 33,
values: [1, 2, 3, 4, 5]
}
}])
})
/* lib exposes two properties:
- lib.run(reportName, params)
This allows us to run other reports such as getting file lists in the backup, etc.
- lib.base
This is the base path for where backups are stored on the system.
*/
/*
the backup object exposes a few different properties:
- backup.id (backup id string)
- backup.base (same as lib.base)
- backup.path (root directory of the backup)
- backup.getFileID(path, domain)
This derives a file's id from the path, domain.
- backup.getFileName(fileID)
get the local filesystem path to a backup file given an ID.
this does lookups to find it.
- backup.openDatabase(fileID)
returns a promise with the sqlite3 database object.
*/
},
/**
* The "output" property declares the public interface for most operations.
* This provides a level of abstraction from the datatypes that are stored in the
* backups since they may vary between versions, or need normalization.
*
* This collection of functions allows that to occur.
*/
output: {
name: el => el.name,
code: el => el.data.code
}
}
For the above example, if run() resolved to:
resolve([{
name: 'example1',
data: {
code: 33,
values: [1, 2, 3, 4, 5]
}
}])
The actual module output when using a normal json, csv, table formatter would be the following, due to the output declaration:
await lib.run('ibackuptool.example', { backup: '<backup id>' })
= [{
name: 'example1',
code: 33
}]
Running using { raw: true }
would give the following output. As a note however, raw output does not provide any guarentees about the formatting of the data, so you may need to add extra logic to handle cases where the data you are looking for does not exist.
await lib.run('ibackuptool.example', { backup: '<backup id>', raw: true })
= [{
name: 'example1',
data: {
code: 33,
values: [1, 2, 3, 4, 5]
}
}]
Consider a new report, named ibackuptool.example2
. We can also resolve the promise to a single raw object:
resolve({
Name: 'test',
Version: '1.0',
BackupData: [104, 101, 108, 108, 111, 044, 119, 111, 114, 108, 100]
})
And map it using the following output declaration:
output: {
name: el => el.Name,
version: el => el.Version
}
Running the report would provide the following output:
await lib.run('ibackuptool.example2', { backup: '<backup id>' })
= {
name: 'test',
version: '1.0'
}
IF we specify a "raw" formatter, or run using the { raw: true } parameter to lib.run(), We'd get back the original raw object.
await lib.run('ibackuptool.example2', { backup: '<backup id>', raw: true })
= {
Name: 'test',
Version: '1.0',
BackupData: [104, 101, 108, 108, 111, 044, 119, 111, 114, 108, 100]
}