mirror of
https://github.com/samsonjs/arq_restore.git
synced 2026-03-25 09:25:53 +00:00
added reflog-printing function
This commit is contained in:
parent
395a17a05d
commit
ec0f06fbea
7 changed files with 224 additions and 13 deletions
|
|
@ -44,10 +44,12 @@
|
|||
#import "ArqSalt.h"
|
||||
#import "ArqRepo.h"
|
||||
#import "BackupSet.h"
|
||||
#import "ReflogPrinter.h"
|
||||
|
||||
|
||||
@interface ArqRestoreCommand (internal)
|
||||
- (BOOL)printArqFolders:(NSError **)error;
|
||||
- (BOOL)restorePath:(NSError **)error;
|
||||
- (BOOL)processPath:(NSError **)error;
|
||||
- (BOOL)validateS3Keys:(NSError **)error;
|
||||
@end
|
||||
|
||||
|
|
@ -112,7 +114,7 @@
|
|||
if (path == nil) {
|
||||
ret = [self printArqFolders:error];
|
||||
} else {
|
||||
ret = [self restorePath:error];
|
||||
ret = [self processPath:error];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -164,7 +166,7 @@
|
|||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)restorePath:(NSError **)error {
|
||||
- (BOOL)processPath:(NSError **)error {
|
||||
if (![self validateS3Keys:error]) {
|
||||
return NO;
|
||||
}
|
||||
|
|
@ -192,19 +194,13 @@
|
|||
NSString *computerUUID = [path substringWithRange:computerUUIDRange];
|
||||
NSString *bucketUUID = [path substringWithRange:bucketUUIDRange];
|
||||
NSString *bucketName = [[plist stringNodeForKey:@"BucketName"] stringValue];
|
||||
|
||||
printf("restoring %s from ", [bucketName UTF8String]);
|
||||
|
||||
NSError *uacError = nil;
|
||||
NSData *uacData = [s3 dataAtPath:[NSString stringWithFormat:@"/%@/%@/computerinfo", s3BucketName, computerUUID] error:&uacError];
|
||||
UserAndComputer *uac = nil;
|
||||
if (uacData != nil) {
|
||||
uac = [[[UserAndComputer alloc] initWithXMLData:uacData error:&uacError] autorelease];
|
||||
printf("%s (%s)", [[uac computerName] UTF8String], [[uac userName] UTF8String]);
|
||||
} else {
|
||||
printf("(unknown computer)");
|
||||
}
|
||||
printf(" to %s/%s\n", [[[NSFileManager defaultManager] currentDirectoryPath] UTF8String], [bucketName UTF8String]);
|
||||
|
||||
NSError *saltError = nil;
|
||||
ArqSalt *arqSalt = [[[ArqSalt alloc] initWithAccessKeyID:accessKey secretAccessKey:secretKey s3BucketName:s3BucketName computerUUID:computerUUID] autorelease];
|
||||
|
|
@ -222,11 +218,27 @@
|
|||
return NO;
|
||||
}
|
||||
|
||||
Restorer *restorer = [[[Restorer alloc] initWithRepo:repo bucketName:bucketName commitSHA1:commitSHA1] autorelease];
|
||||
if (![restorer restore:error]) {
|
||||
return NO;
|
||||
if ([commitSHA1 isEqualToString:@"reflog"]) {
|
||||
printf("printing reflog for %s\n", [bucketName UTF8String]);
|
||||
ReflogPrinter *printer = [[[ReflogPrinter alloc] initWithS3BucketName:s3BucketName computerUUID:computerUUID bucketUUID:bucketUUID s3:s3 repo:repo] autorelease];
|
||||
if (![printer printReflog:error]) {
|
||||
return NO;
|
||||
}
|
||||
} else {
|
||||
printf("restoring %s from ", [bucketName UTF8String]);
|
||||
if (uac != nil) {
|
||||
printf("%s (%s)", [[uac computerName] UTF8String], [[uac userName] UTF8String]);
|
||||
} else {
|
||||
printf("(unknown computer)");
|
||||
}
|
||||
printf(" to %s/%s\n", [[[NSFileManager defaultManager] currentDirectoryPath] UTF8String], [bucketName UTF8String]);
|
||||
|
||||
Restorer *restorer = [[[Restorer alloc] initWithRepo:repo bucketName:bucketName commitSHA1:commitSHA1] autorelease];
|
||||
if (![restorer restore:error]) {
|
||||
return NO;
|
||||
}
|
||||
printf("restored files are in %s\n", [bucketName fileSystemRepresentation]);
|
||||
}
|
||||
printf("restored files are in %s\n", [bucketName fileSystemRepresentation]);
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)validateS3Keys:(NSError **)error {
|
||||
|
|
|
|||
20
ReflogEntry.h
Normal file
20
ReflogEntry.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// ReflogEntry.h
|
||||
// arq_restore
|
||||
//
|
||||
// Created by Stefan Reitshamer on 11/20/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class BlobKey;
|
||||
|
||||
@interface ReflogEntry : NSObject {
|
||||
BlobKey *oldHeadBlobKey;
|
||||
BlobKey *newHeadBlobKey;
|
||||
}
|
||||
- (id)initWithData:(NSData *)theData error:(NSError **)error;
|
||||
|
||||
- (BlobKey *)oldHeadBlobKey;
|
||||
- (BlobKey *)newHeadBlobKey;
|
||||
@end
|
||||
51
ReflogEntry.m
Normal file
51
ReflogEntry.m
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// ReflogEntry.m
|
||||
// arq_restore
|
||||
//
|
||||
// Created by Stefan Reitshamer on 11/20/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ReflogEntry.h"
|
||||
#import "BlobKey.h"
|
||||
#import "DictNode.h"
|
||||
#import "SetNSError.h"
|
||||
|
||||
|
||||
@implementation ReflogEntry
|
||||
- (id)initWithData:(NSData *)theData error:(NSError **)error {
|
||||
if (self = [super init]) {
|
||||
DictNode *dictNode = [DictNode dictNodeWithXMLData:theData error:error];
|
||||
if (dictNode == nil) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if (![dictNode containsKey:@"oldHeadSHA1"]
|
||||
|| ![dictNode containsKey:@"oldHeadStretchKey"]
|
||||
|| ![dictNode containsKey:@"newHeadSHA1"]
|
||||
|| ![dictNode containsKey:@"newHeadStretchKey"]) {
|
||||
SETNSERROR(@"ReflogEntryErrorDomain", -1, @"missing values in reflog entry");
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
oldHeadBlobKey = [[BlobKey alloc] initWithSHA1:[[dictNode stringNodeForKey:@"oldHeadSHA1"] stringValue]
|
||||
stretchEncryptionKey:[[dictNode booleanNodeForKey:@"oldHeadStretchKey"] booleanValue]];
|
||||
|
||||
newHeadBlobKey = [[BlobKey alloc] initWithSHA1:[[dictNode stringNodeForKey:@"newHeadSHA1"] stringValue]
|
||||
stretchEncryptionKey:[[dictNode booleanNodeForKey:@"newHeadStretchKey"] booleanValue]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[oldHeadBlobKey release];
|
||||
[newHeadBlobKey release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BlobKey *)oldHeadBlobKey {
|
||||
return oldHeadBlobKey;
|
||||
}
|
||||
- (BlobKey *)newHeadBlobKey {
|
||||
return newHeadBlobKey;
|
||||
}
|
||||
@end
|
||||
22
ReflogPrinter.h
Normal file
22
ReflogPrinter.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ReflogPrinter.h
|
||||
// arq_restore
|
||||
//
|
||||
// Created by Stefan Reitshamer on 11/21/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
@class S3Service;
|
||||
@class ArqRepo;
|
||||
|
||||
@interface ReflogPrinter : NSObject {
|
||||
NSString *s3BucketName;
|
||||
NSString *computerUUID;
|
||||
NSString *bucketUUID;
|
||||
S3Service *s3;
|
||||
ArqRepo *repo;
|
||||
}
|
||||
- (id)initWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID bucketUUID:(NSString *)theBucketUUID s3:(S3Service *)theS3 repo:(ArqRepo *)theRepo;
|
||||
- (BOOL)printReflog:(NSError **)error;
|
||||
@end
|
||||
99
ReflogPrinter.m
Normal file
99
ReflogPrinter.m
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// ReflogPrinter.m
|
||||
// arq_restore
|
||||
//
|
||||
// Created by Stefan Reitshamer on 11/21/11.
|
||||
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ReflogPrinter.h"
|
||||
#import "S3Service.h"
|
||||
#import "ArqRepo.h"
|
||||
#import "ReflogEntry.h"
|
||||
#import "Commit.h"
|
||||
#import "BlobKey.h"
|
||||
|
||||
|
||||
@interface ReflogPrinter (internal)
|
||||
- (BOOL)printEntry:(NSString *)path error:(NSError **)error;
|
||||
@end
|
||||
|
||||
|
||||
@implementation ReflogPrinter
|
||||
- (id)initWithS3BucketName:(NSString *)theS3BucketName computerUUID:(NSString *)theComputerUUID bucketUUID:(NSString *)theBucketUUID s3:(S3Service *)theS3 repo:(ArqRepo *)theRepo {
|
||||
if (self = [super init]) {
|
||||
s3BucketName = [theS3BucketName retain];
|
||||
computerUUID = [theComputerUUID retain];
|
||||
bucketUUID = [theBucketUUID retain];
|
||||
s3 = [theS3 retain];
|
||||
repo = [theRepo retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[s3BucketName release];
|
||||
[computerUUID release];
|
||||
[bucketUUID release];
|
||||
[s3 release];
|
||||
[repo release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL)printReflog:(NSError **)error {
|
||||
NSString *prefix = [NSString stringWithFormat:@"/%@/%@/bucketdata/%@/refs/logs/master/", s3BucketName, computerUUID, bucketUUID];
|
||||
NSArray *paths = [s3 pathsWithPrefix:prefix error:error];
|
||||
if (paths == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSSortDescriptor *descriptor = [[[NSSortDescriptor alloc] initWithKey:@"description" ascending:NO] autorelease];
|
||||
NSArray *sortedPaths = [paths sortedArrayUsingDescriptors:[NSArray arrayWithObject:descriptor]];
|
||||
|
||||
BOOL ret = YES;
|
||||
NSAutoreleasePool *pool = nil;
|
||||
for (NSString *path in sortedPaths) {
|
||||
[pool drain];
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
if (![self printEntry:path error:error]) {
|
||||
ret = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ret && error != NULL) {
|
||||
[*error retain];
|
||||
}
|
||||
[pool drain];
|
||||
if (!ret && error != NULL) {
|
||||
[*error autorelease];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ReflogPrinter (internal)
|
||||
- (BOOL)printEntry:(NSString *)path error:(NSError **)error {
|
||||
printf("reflog %s\n", [path UTF8String]);
|
||||
|
||||
NSData *data = [s3 dataAtPath:path error:error];
|
||||
if (data == nil) {
|
||||
return NO;
|
||||
}
|
||||
NSError *myError = nil;
|
||||
ReflogEntry *entry = [[[ReflogEntry alloc] initWithData:data error:&myError] autorelease];
|
||||
if (entry == nil) {
|
||||
printf("\terror reading reflog entry: %s\n", [[myError description] UTF8String]);
|
||||
} else {
|
||||
Commit *commit = [repo commitForBlobKey:[entry newHeadBlobKey] error:&myError];
|
||||
if (commit == nil) {
|
||||
printf("\tcommit %s: %s\n", [[[entry newHeadBlobKey] description] UTF8String], [[myError localizedDescription] UTF8String]);
|
||||
} else {
|
||||
printf("\tblobkey: %s\n", [[[entry newHeadBlobKey] description] UTF8String]);
|
||||
printf("\tauthor: %s\n", [[commit author] UTF8String]);
|
||||
printf("\tdate: %s\n", [[[commit creationDate] description] UTF8String]);
|
||||
printf("\tlocation: %s\n", [[commit location] UTF8String]);
|
||||
printf("\trestore command: arq_restore /%s/%s/buckets/%s %s\n", [s3BucketName UTF8String], [computerUUID UTF8String], [bucketUUID UTF8String],
|
||||
[[[entry newHeadBlobKey] sha1] UTF8String]);
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
|
@ -39,6 +39,7 @@ static void printUsage(const char *exeName) {
|
|||
fprintf(stderr, "Usage:\n");
|
||||
fprintf(stderr, "\t%s [-l log_level]\n", exeName);
|
||||
fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID\n", exeName);
|
||||
fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID reflog\n", exeName);
|
||||
fprintf(stderr, "\t%s [-l log_level] /s3bucket/computerUUID/folderUUID <commitSHA1>\n", exeName);
|
||||
}
|
||||
int main (int argc, const char **argv) {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
F805B8CE1160ECD7007EC01E /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F805B8CD1160ECD7007EC01E /* CoreServices.framework */; };
|
||||
F81426D714541A6C00D7E50A /* BackupSet.m in Sources */ = {isa = PBXBuildFile; fileRef = F81426D614541A6C00D7E50A /* BackupSet.m */; };
|
||||
F8373E0F14794D01005AFBE6 /* ReflogEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = F8373E0E14794D01005AFBE6 /* ReflogEntry.m */; };
|
||||
F8373E5A147A8DEC005AFBE6 /* ReflogPrinter.m in Sources */ = {isa = PBXBuildFile; fileRef = F8373E59147A8DEC005AFBE6 /* ReflogPrinter.m */; };
|
||||
F83C1A7411CA7C170001958F /* ArqRestoreCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B54C1160D3E6007EC01E /* ArqRestoreCommand.m */; };
|
||||
F83C1A7711CA7C170001958F /* ArrayNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7421160DCFE007EC01E /* ArrayNode.m */; };
|
||||
F83C1A7811CA7C170001958F /* BooleanNode.m in Sources */ = {isa = PBXBuildFile; fileRef = F805B7441160DCFE007EC01E /* BooleanNode.m */; };
|
||||
|
|
@ -342,6 +343,8 @@
|
|||
F81426D614541A6C00D7E50A /* BackupSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BackupSet.m; sourceTree = "<group>"; };
|
||||
F8373E0D14794D01005AFBE6 /* ReflogEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflogEntry.h; sourceTree = "<group>"; };
|
||||
F8373E0E14794D01005AFBE6 /* ReflogEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReflogEntry.m; sourceTree = "<group>"; };
|
||||
F8373E58147A8DEC005AFBE6 /* ReflogPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReflogPrinter.h; sourceTree = "<group>"; };
|
||||
F8373E59147A8DEC005AFBE6 /* ReflogPrinter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReflogPrinter.m; sourceTree = "<group>"; };
|
||||
F83C1A5F11CA7A6B0001958F /* arq_verify.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = arq_verify.m; sourceTree = "<group>"; };
|
||||
F83C1A6111CA7BD20001958F /* ArqVerifyCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArqVerifyCommand.h; sourceTree = "<group>"; };
|
||||
F83C1A6211CA7BD20001958F /* ArqVerifyCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ArqVerifyCommand.m; sourceTree = "<group>"; };
|
||||
|
|
@ -552,6 +555,8 @@
|
|||
F89A1F3D13FAC6820071D321 /* UserLibrary_Arq.m */,
|
||||
F81426D514541A6C00D7E50A /* BackupSet.h */,
|
||||
F81426D614541A6C00D7E50A /* BackupSet.m */,
|
||||
F8373E58147A8DEC005AFBE6 /* ReflogPrinter.h */,
|
||||
F8373E59147A8DEC005AFBE6 /* ReflogPrinter.m */,
|
||||
F8373E0D14794D01005AFBE6 /* ReflogEntry.h */,
|
||||
F8373E0E14794D01005AFBE6 /* ReflogEntry.m */,
|
||||
);
|
||||
|
|
@ -986,6 +991,7 @@
|
|||
F89A205A13FAE3010071D321 /* DataOutputStream.m in Sources */,
|
||||
F81426D714541A6C00D7E50A /* BackupSet.m in Sources */,
|
||||
F8373E0F14794D01005AFBE6 /* ReflogEntry.m in Sources */,
|
||||
F8373E5A147A8DEC005AFBE6 /* ReflogPrinter.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue