|
rpm-build |
0fba15 |
#!/usr/bin/env gjs
|
|
rpm-build |
0fba15 |
//
|
|
rpm-build |
0fba15 |
// Copyright (C) 2013 Colin Walters <walters@verbum.org>
|
|
rpm-build |
0fba15 |
//
|
|
rpm-build |
0fba15 |
// SPDX-License-Identifier: LGPL-2.0+
|
|
rpm-build |
0fba15 |
//
|
|
rpm-build |
0fba15 |
// This library is free software; you can redistribute it and/or
|
|
rpm-build |
0fba15 |
// modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
// License as published by the Free Software Foundation; either
|
|
rpm-build |
0fba15 |
// version 2 of the License, or (at your option) any later version.
|
|
rpm-build |
0fba15 |
//
|
|
rpm-build |
0fba15 |
// This library is distributed in the hope that it will be useful,
|
|
rpm-build |
0fba15 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
0fba15 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
0fba15 |
// Lesser General Public License for more details.
|
|
rpm-build |
0fba15 |
//
|
|
rpm-build |
0fba15 |
// You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
// License along with this library; if not, write to the
|
|
rpm-build |
0fba15 |
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
rpm-build |
0fba15 |
// Boston, MA 02111-1307, USA.
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
const GLib = imports.gi.GLib;
|
|
rpm-build |
0fba15 |
const Gio = imports.gi.Gio;
|
|
rpm-build |
0fba15 |
const OSTree = imports.gi.OSTree;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
function assertEquals(a, b) {
|
|
rpm-build |
0fba15 |
if (a != b)
|
|
rpm-build |
0fba15 |
throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
function assertGreater(a, b) {
|
|
rpm-build |
0fba15 |
if (a <= b)
|
|
rpm-build |
0fba15 |
throw new Error("assertion failed " + JSON.stringify(a) + " > " + JSON.stringify(b));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
function assertGreaterEquals(a, b) {
|
|
rpm-build |
0fba15 |
if (a < b)
|
|
rpm-build |
0fba15 |
throw new Error("assertion failed " + JSON.stringify(a) + " >= " + JSON.stringify(b));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// Adapted from _ostree_read_varuint64()
|
|
rpm-build |
0fba15 |
function readVarint(buffer) {
|
|
rpm-build |
0fba15 |
let result = 0;
|
|
rpm-build |
0fba15 |
let count = 0;
|
|
rpm-build |
0fba15 |
let len = buffer.length;
|
|
rpm-build |
0fba15 |
let cur;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
do {
|
|
rpm-build |
0fba15 |
assertGreater(len, 0);
|
|
rpm-build |
0fba15 |
cur = buffer[count];
|
|
rpm-build |
0fba15 |
result = result | ((cur & 0x7F) << (7 * count));
|
|
rpm-build |
0fba15 |
count++;
|
|
rpm-build |
0fba15 |
len--;
|
|
rpm-build |
0fba15 |
} while (cur & 0x80);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return [result, count];
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// There have been various bugs with byte array unpacking in GJS, so
|
|
rpm-build |
0fba15 |
// just do it manually.
|
|
rpm-build |
0fba15 |
function unpackByteArray(variant) {
|
|
rpm-build |
0fba15 |
let array = [];
|
|
rpm-build |
0fba15 |
let nBytes = variant.n_children();
|
|
rpm-build |
0fba15 |
for (let i = 0; i < nBytes; i++) {
|
|
rpm-build |
0fba15 |
array.push(variant.get_child_value(i).get_byte());
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
return array;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
function validateSizes(repo, commit, expectedObjects) {
|
|
rpm-build |
0fba15 |
let [,commitVariant] = repo.load_variant(OSTree.ObjectType.COMMIT, commit);
|
|
rpm-build |
0fba15 |
let metadata = commitVariant.get_child_value(0);
|
|
rpm-build |
0fba15 |
let sizes = metadata.lookup_value('ostree.sizes', GLib.VariantType.new('aay'));
|
|
rpm-build |
0fba15 |
let nObjects = sizes.n_children();
|
|
rpm-build |
0fba15 |
let expectedNObjects = Object.keys(expectedObjects).length
|
|
rpm-build |
0fba15 |
assertEquals(nObjects, expectedNObjects);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
for (let i = 0; i < nObjects; i++) {
|
|
rpm-build |
0fba15 |
let sizeEntry = sizes.get_child_value(i);
|
|
rpm-build |
0fba15 |
assertGreaterEquals(sizeEntry.n_children(), 34);
|
|
rpm-build |
0fba15 |
let entryBytes = unpackByteArray(sizeEntry);
|
|
rpm-build |
0fba15 |
let checksumBytes = entryBytes.slice(0, 32);
|
|
rpm-build |
0fba15 |
let checksumString = OSTree.checksum_from_bytes(checksumBytes);
|
|
rpm-build |
0fba15 |
print("checksum = " + checksumString);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// Read the sizes from the next 2 varints
|
|
rpm-build |
0fba15 |
let remainingBytes = entryBytes.slice(32);
|
|
rpm-build |
0fba15 |
assertGreaterEquals(remainingBytes.length, 2);
|
|
rpm-build |
0fba15 |
let varintRead;
|
|
rpm-build |
0fba15 |
let compressedSize;
|
|
rpm-build |
0fba15 |
let uncompressedSize;
|
|
rpm-build |
0fba15 |
[compressedSize, varintRead] = readVarint(remainingBytes);
|
|
rpm-build |
0fba15 |
remainingBytes = remainingBytes.slice(varintRead);
|
|
rpm-build |
0fba15 |
assertGreaterEquals(remainingBytes.length, 1);
|
|
rpm-build |
0fba15 |
[uncompressedSize, varintRead] = readVarint(remainingBytes);
|
|
rpm-build |
0fba15 |
remainingBytes = remainingBytes.slice(varintRead);
|
|
rpm-build |
0fba15 |
assertEquals(remainingBytes.length, 1);
|
|
rpm-build |
0fba15 |
let objectType = remainingBytes[0];
|
|
rpm-build |
0fba15 |
let objectTypeString = OSTree.object_type_to_string(objectType);
|
|
rpm-build |
0fba15 |
print("compressed = " + compressedSize);
|
|
rpm-build |
0fba15 |
print("uncompressed = " + uncompressedSize);
|
|
rpm-build |
0fba15 |
print("objtype = " + objectTypeString + " (" + objectType + ")");
|
|
rpm-build |
0fba15 |
let objectName = OSTree.object_to_string(checksumString, objectType);
|
|
rpm-build |
0fba15 |
print("object = " + objectName);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!(objectName in expectedObjects)) {
|
|
rpm-build |
0fba15 |
throw new Error("Object " + objectName + " not in " +
|
|
rpm-build |
0fba15 |
JSON.stringify(expectedObjects));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
let expectedSizes = expectedObjects[objectName];
|
|
rpm-build |
0fba15 |
let expectedCompressedSize = expectedSizes[0];
|
|
rpm-build |
0fba15 |
let expectedUncompressedSize = expectedSizes[1];
|
|
rpm-build |
0fba15 |
if (compressedSize != expectedCompressedSize) {
|
|
rpm-build |
0fba15 |
throw new Error("Compressed size " + compressedSize +
|
|
rpm-build |
0fba15 |
" for checksum " + checksumString +
|
|
rpm-build |
0fba15 |
" does not match expected " + expectedCompressedSize);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
if (uncompressedSize != expectedUncompressedSize) {
|
|
rpm-build |
0fba15 |
throw new Error("Uncompressed size " + uncompressedSize +
|
|
rpm-build |
0fba15 |
" for checksum " + checksumString +
|
|
rpm-build |
0fba15 |
" does not match expected " + expectedUncompressedSize);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
print('1..3')
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
let testDataDir = Gio.File.new_for_path('test-data');
|
|
rpm-build |
0fba15 |
testDataDir.make_directory(null);
|
|
rpm-build |
0fba15 |
testDataDir.get_child('some-file').replace_contents("hello world!", null, false, 0, null);
|
|
rpm-build |
0fba15 |
testDataDir.get_child('some-file').copy(testDataDir.get_child('duplicate-file'),
|
|
rpm-build |
0fba15 |
Gio.FileCopyFlags.OVERWRITE,
|
|
rpm-build |
0fba15 |
null, null);
|
|
rpm-build |
0fba15 |
testDataDir.get_child('link-file').make_symbolic_link('some-file', null);
|
|
rpm-build |
0fba15 |
testDataDir.get_child('another-file').replace_contents("hello world again!", null, false, 0, null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
let repoPath = Gio.File.new_for_path('repo');
|
|
rpm-build |
0fba15 |
let repo = OSTree.Repo.new(repoPath);
|
|
rpm-build |
0fba15 |
repo.create(OSTree.RepoMode.ARCHIVE_Z2, null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
repo.open(null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
let commitModifierFlags = (OSTree.RepoCommitModifierFlags.GENERATE_SIZES |
|
|
rpm-build |
0fba15 |
OSTree.RepoCommitModifierFlags.SKIP_XATTRS |
|
|
rpm-build |
0fba15 |
OSTree.RepoCommitModifierFlags.CANONICAL_PERMISSIONS);
|
|
rpm-build |
0fba15 |
let commitModifier = OSTree.RepoCommitModifier.new(commitModifierFlags, null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
assertEquals(repo.get_mode(), OSTree.RepoMode.ARCHIVE_Z2);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
repo.prepare_transaction(null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
let mtree = OSTree.MutableTree.new();
|
|
rpm-build |
0fba15 |
repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null);
|
|
rpm-build |
0fba15 |
let [,dirTree] = repo.write_mtree(mtree, null);
|
|
rpm-build |
0fba15 |
let [,commit] = repo.write_commit(null, 'Some subject', 'Some body', null, dirTree, null);
|
|
rpm-build |
0fba15 |
print("commit => " + commit);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
repo.commit_transaction(null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// Test the sizes metadata. The key is the object and the value is an
|
|
rpm-build |
0fba15 |
// array of compressed size and uncompressed size.
|
|
rpm-build |
0fba15 |
let expectedObjects = {
|
|
rpm-build |
0fba15 |
'f5ee222a21e2c96edbd6f2543c4bc8a039f827be3823d04777c9ee187778f1ad.file': [
|
|
rpm-build |
0fba15 |
54, 18
|
|
rpm-build |
0fba15 |
],
|
|
rpm-build |
0fba15 |
'd35bfc50864fca777dbeead3ba3689115b76674a093210316589b1fe5cc3ff4b.file': [
|
|
rpm-build |
0fba15 |
48, 12
|
|
rpm-build |
0fba15 |
],
|
|
rpm-build |
0fba15 |
'8322876a078e79d8c960b8b4658fe77e7b2f878f8a6cf89dbb87c6becc8128a0.file': [
|
|
rpm-build |
0fba15 |
43, 9
|
|
rpm-build |
0fba15 |
],
|
|
rpm-build |
0fba15 |
'1c77033ca06eae77ed99cb26472969964314ffd5b4e4c0fd3ff6ec4265c86e51.dirtree': [
|
|
rpm-build |
0fba15 |
185, 185
|
|
rpm-build |
0fba15 |
],
|
|
rpm-build |
0fba15 |
'446a0ef11b7cc167f3b603e585c7eeeeb675faa412d5ec73f62988eb0b6c5488.dirmeta': [
|
|
rpm-build |
0fba15 |
12, 12
|
|
rpm-build |
0fba15 |
],
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
validateSizes(repo, commit, expectedObjects);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
print("ok test-sizes");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// Remove a file to make sure that metadata is not reused from the
|
|
rpm-build |
0fba15 |
// previous commit. Remove that file from the expected metadata and
|
|
rpm-build |
0fba15 |
// replace the dirtree object.
|
|
rpm-build |
0fba15 |
testDataDir.get_child('another-file').delete(null);
|
|
rpm-build |
0fba15 |
delete expectedObjects['f5ee222a21e2c96edbd6f2543c4bc8a039f827be3823d04777c9ee187778f1ad.file'];
|
|
rpm-build |
0fba15 |
delete expectedObjects['1c77033ca06eae77ed99cb26472969964314ffd5b4e4c0fd3ff6ec4265c86e51.dirtree'];
|
|
rpm-build |
0fba15 |
expectedObjects['a384660cc18ffdb60296961dde9a2d6f78f4fec095165652cb53aa81f6dc7539.dirtree'] = [
|
|
rpm-build |
0fba15 |
138, 138
|
|
rpm-build |
0fba15 |
];
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
repo.prepare_transaction(null);
|
|
rpm-build |
0fba15 |
mtree = OSTree.MutableTree.new();
|
|
rpm-build |
0fba15 |
repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null);
|
|
rpm-build |
0fba15 |
[,dirTree] = repo.write_mtree(mtree, null);
|
|
rpm-build |
0fba15 |
[,commit] = repo.write_commit(null, 'Some subject', 'Some body', null, dirTree, null);
|
|
rpm-build |
0fba15 |
print("commit => " + commit);
|
|
rpm-build |
0fba15 |
repo.commit_transaction(null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
validateSizes(repo, commit, expectedObjects);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
print("ok test-sizes file deleted");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
// Repeat the commit now that all the objects are cached and ensure the
|
|
rpm-build |
0fba15 |
// metadata is still correct
|
|
rpm-build |
0fba15 |
repo.prepare_transaction(null);
|
|
rpm-build |
0fba15 |
mtree = OSTree.MutableTree.new();
|
|
rpm-build |
0fba15 |
repo.write_directory_to_mtree(testDataDir, mtree, commitModifier, null);
|
|
rpm-build |
0fba15 |
[,dirTree] = repo.write_mtree(mtree, null);
|
|
rpm-build |
0fba15 |
[,commit] = repo.write_commit(null, 'Another subject', 'Another body', null, dirTree, null);
|
|
rpm-build |
0fba15 |
print("commit => " + commit);
|
|
rpm-build |
0fba15 |
repo.commit_transaction(null);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
validateSizes(repo, commit, expectedObjects);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
print("ok test-sizes repeated");
|