I am developing mac application in that application I need to log to folder, where already some other application is also logging,so need to create only one file in that folder, when file rolling occurs the whole contents in that log folder are deleting .this code I am using .I don't want delete contents in log folder and is it possible to use only file with constant name .Please help me.
// Configure CocoaLumberjack
DDLog.addLogger(DDASLLogger.sharedInstance())
DDLog.addLogger(DDTTYLogger.sharedInstance())
// Initialize File Logger
let manager : BaseLogFileManager = BaseLogFileManager(logsDirectory:K.LogFileDir)
let fileLogger: DDFileLogger = DDFileLogger(logFileManager: manager) // File Logger
fileLogger.maximumFileSize = 1024*1024*20
fileLogger.doNotReuseLogFiles = false
fileLogger.logFileManager.maximumNumberOfLogFiles = 1
DDLog.addLogger(fileLogger)
class BaseLogFileManager : DDLogFileManagerDefault
{
override var newLogFileName: String! { get {
return K.LogFileName
}}
override func isLogFile(fileName: String!) -> Bool
{
return true
}
}
Work around is to disable rolling frequency, don't assign maximum size or rollingFrequency and check size using NSFileManager. If file size is greater than specific limit, remove and create new file.
// Configure CocoaLumberjack
DDLog.addLogger(DDASLLogger.sharedInstance())
DDLog.addLogger(DDTTYLogger.sharedInstance())
// Initialize File Logger
let manager : BaseLogFileManager = BaseLogFileManager(logsDirectory:K.LogFileDir)
let fileLogger: DDFileLogger = DDFileLogger(logFileManager: manager) // File Logger
do {
let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(K.LogFileDir+"/"+K.LogFileName)
if let _attr = attr {
if _attr.fileSize() > 1024*1024*10
{
NSFileManager.defaultManager().createFileAtPath(K.LogFileDir+"/"+K.LogFileName, contents: NSData(), attributes: nil)
}
}
} catch {
print("Error: \(error)")
}
fileLogger.doNotReuseLogFiles = false
fileLogger.logFileManager.maximumNumberOfLogFiles = 1
DDLog.addLogger(fileLogger)
Related
I am new to the Swift Package Manager but with its integration into Xcode 11 it is time to give it a try. I have a new application and SPM library within a new workspace. I have a working library with tests and have successfully imported the library into the application.
I need to extend the SPM library with new tests that parse json files. I have learned that a resources directory feature is not supported. The only workable scheme seems to be a file copy step added to the library build process so that the resource files can be discovered by the executable.
I could figure out how to do this from the command line but not with Xcode running the build and test. There is no Copy Bundle Resources, build phase for swift packages. In fact everything appears to be hidden by Xcode.
I have looked within the SPM for Makefile type files that would allow me to edit default command line actions thereby circumventing Xcode; but I am not seeing them.
Is there some way to interact/control how Xcode 11 builds SPM targets so that I can copy non-code files to test targets?
Got it working!!!
struct Resource {
let name: String
let type: String
let url: URL
init(name: String, type: String, sourceFile: StaticString = #file) throws {
self.name = name
self.type = type
// The following assumes that your test source files are all in the same directory, and the resources are one directory down and over
// <Some folder>
// - Resources
// - <resource files>
// - <Some test source folder>
// - <test case files>
let testCaseURL = URL(fileURLWithPath: "\(sourceFile)", isDirectory: false)
let testsFolderURL = testCaseURL.deletingLastPathComponent()
let resourcesFolderURL = testsFolderURL.deletingLastPathComponent().appendingPathComponent("Resources", isDirectory: true)
self.url = resourcesFolderURL.appendingPathComponent("\(name).\(type)", isDirectory: false)
}
}
Usage:
final class SPMTestDataTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(SPMTestData().text, "Hello, World!")
let file = try Resource(name: "image", type: "png")
let image = UIImage(contentsOfFile: file.url.path)
print(image)
}
}
I found the key of using #file here
This is another workaround to provide access to test resources. Hopefully an answer to the OP's question will be forthcoming.
Using the code below, an extension is created to allow callers to create URL's to test resources like this.
let url = URL(forResource: "payload", type: "json")
This code requires that all resource files be located in a flat directory named "Resources" just under the test target.
// MARK: - ./Resources/ Workaround
// URL of the directory containing non-code, test resource fi;es.
//
// It is required that a directory named "Resources" be contained immediately below the test target.
// Root
// Package.swift
// Tests
// (target)
// Resources
//
fileprivate let _resources: URL = {
func packageRoot(of file: String) -> URL? {
func isPackageRoot(_ url: URL) -> Bool {
let filename = url.appendingPathComponent("Package.swift", isDirectory: false)
return FileManager.default.fileExists(atPath: filename.path)
}
var url = URL(fileURLWithPath: file, isDirectory: false)
repeat {
url = url.deletingLastPathComponent()
if url.pathComponents.count <= 1 {
return nil
}
} while !isPackageRoot(url)
return url
}
guard let root = packageRoot(of: #file) else {
fatalError("\(#file) must be contained in a Swift Package Manager project.")
}
let fileComponents = URL(fileURLWithPath: #file, isDirectory: false).pathComponents
let rootComponenets = root.pathComponents
let trailingComponents = Array(fileComponents.dropFirst(rootComponenets.count))
let resourceComponents = rootComponenets + trailingComponents[0...1] + ["Resources"]
return URL(fileURLWithPath: resourceComponents.joined(separator: "/"), isDirectory: true)
}()
extension URL {
init(forResource name: String, type: String) {
let url = _resources.appendingPathComponent("\(name).\(type)", isDirectory: false)
self = url
}
}
Using the new shiny WKWebView and sandbox on os/x, require some intervening reset or clear as subsequent calls to load a file URL will be ignored; this is somewhat related to an earlier question on WKWebView loadFileURL works only once -
ios there, here on os/X I do
if loadURL.isFileURL {
webView.loadFileURL(loadURL, allowingReadAccessTo: loadURL)
}
else
{
webView.load(URLRequest(url: loadURL))
}
I've tried to pass loadURL.deletingLastPathComponent() as the second arg but then all breaks - no file URLs get loaded, nor does using the user's home path, or the entire root 'file:///', nor the 'temporary' exception re: absolute file paths. Finally, trying an intervening topLoading() has no affect.
The only solution (yuck) to get a subsequent file URL loaded is to first load a non file URL!
It seems within a sandbox environment this has unintended consequences?
Well, this works but ugly - webView subclass function, as you cannot reuse a webView when a file url was previously loaded. This workaround will instantiate a new window/doc tossing the old - unless as a user preference they want to keep the old window (newWindows flag is true):
func loadNext(url: URL) {
let doc = self.window?.windowController?.document as! Document
let newWindows = UserSettings.createNewWindows.value
var fileURL = url
if !url.isFileURL {
if newWindows {
do
{
let next = try NSDocumentController.shared().openUntitledDocumentAndDisplay(true) as! Document
let oldWindow = self.window
let newWindow = next.windowControllers.first?.window
(newWindow?.contentView?.subviews.first as! MyWebView).load(URLRequest(url: url))
newWindow?.offsetFromWindow(oldWindow!)
}
catch let error {
NSApp.presentError(error)
Swift.print("Yoink, unable to create new url doc for (\(url))")
return
}
}
else
{
self.load(URLRequest(url: url))
}
}
if let origURL = (fileURL as NSURL).resolvedFinderAlias() {
fileURL = origURL
}
if appDelegate.isSandboxed() && !appDelegate.storeBookmark(url: fileURL) {
Swift.print("Yoink, unable to sandbox \(fileURL))")
return
}
if !(self.url?.isFileURL)! && !newWindows {
self.loadFileURL(fileURL, allowingReadAccessTo: fileURL)
doc.update(to: fileURL, ofType: fileURL.pathExtension)
return
}
// We need or want a new window; if need, remove the old afterward
do {
let next = try NSDocumentController.shared().openUntitledDocumentAndDisplay(true) as! Document
let oldWindow = doc.windowControllers.first?.window
let newWindow = next.windowControllers.first?.window
(newWindow?.contentView?.subviews.first as! MyWebView).loadFileURL(fileURL, allowingReadAccessTo: fileURL)
if newWindows {
newWindow?.offsetFromWindow(oldWindow!)
}
else
{
newWindow?.overlayWindow(oldWindow!)
oldWindow?.orderOut(self)
}
next.update(to: fileURL, ofType: fileURL.pathExtension)
}
catch let error
{
NSApp.presentError(error)
Swift.print("Yoink, unable to new doc (\(fileURL))")
}
}
I'm trying to test some sqlite database calls through XCode's playground. I start with a database in my Playground's Resources folder and try to move it to the Playgrounds Documents folder, however what happens is that a symbolic link is generated pointing back to the file within the Resources folder so I am unable to write to that file. However, If I figure out where the Documents folder is and then copy the file there by hand from the terminal everything works just fine.
So why does the file manager copy command actually create a sym link to rather than copy? And is there any way to actually make this happen? It seems to only be a problem with the Playground. copy from Resource to Documents works fine in the app itself.
some code to test within the playground...
let dirPaths = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask, true)
let docsDir = dirPaths[0]
let destPath = (docsDir as NSString).appendingPathComponent("/data.sqlite")
print(destPath)
let fileMgr = FileManager.default
let srcPath = Bundle.main.path(forResource: "data", ofType:"sqlite")
// This copies the data.sqlite file from Resources to Documents
// ** However in the playground, only a symlink is generated
do {
try fileMgr.copyItem(atPath: srcPath!, toPath: destPath)
} catch let error {
print("Error (during copy): \(error.localizedDescription)")
}
Rod, It's too late but, I figure this out.
Context:
I add one playground to my project in the same workspace
To make the playground works with my project, I create a framework
I added the Store.db file to the framework target
I haven't added the Store.db to the Playground as a Resource
Swift 3
Playground
#testable import MyAppAsFramework
func copyMockDBToDocumentsFolder(dbPath: String) {
let localDBName = "Store.db"
let documentPath = dbPath / localDBName
let dbFile = Bundle(for: MyAppAsFrameworkSomeClass.self).path(forResource: localDBName.deletingPathExtension, ofType: localDBName.pathExtension)
FileManager.copyFile(dbFile, toFolderPath: documentPath)
}
copyMockDBToDocumentsFolder(dbPath: "The documents path")
Things like / copyFile(x) and the others are operator overloads and extensions
extension String {
public var pathExtension: String {
get {
return (self as NSString).pathExtension
}
}
public var deletingPathExtension: String {
get {
return (self as NSString).deletingPathExtension
}
}
public func appendingPath(_ path: String) -> String {
let nsSt = self as NSString
return nsSt.appendingPathComponent(path)
}
}
infix operator / : MultiplicationPrecedence
public func / (left: String, right: String) -> String {
return left.appendingPath(right)
}
extension FileManager {
class func copyFile(_ filePath: String?, toFolderPath: String?) -> Bool {
guard let file = filePath else { return false }
guard let toFolder = toFolderPath else { return false }
var posibleError: NSError?
do {
try FileManager.default.copyItem(atPath: file, toPath:toFolder)
} catch let error as NSError {
posibleError = error
print("CAN'T COPY \(error.localizedDescription)")
}
return posibleError == nil
}
}
I have a variable 'a' created, whose values for example are from a text file on my desktop. I want to read the data continuously and display the value of 'a' in my application.
Even if I change the value from the text file, it should reflect automatically on my application.
Any suggestions?
I'm using Swift 2.2
You can use GCD's Dispatch Source to monitor a file. What follows is simple example where we monitor a file and update an NSTextView with the file's content after every update.
class ViewController: NSViewController {
#IBOutlet var textView: NSTextView!
// Create a dispatch_source_t to monitor the file
func dispatchSoureForFile(at path: String) -> dispatch_source_t? {
let fileHandle = open(path.cStringUsingEncoding(NSUTF8StringEncoding)!, O_RDONLY)
// Cannot open file
guard fileHandle != -1 else {
return nil
}
// The queue where the event handler will execute. Don't set to the main queue
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
// The events we are interested in
let mask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND
return dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, UInt(fileHandle), mask, queue)
}
// The function to use for monitoring a file
func startMonitoringFile(at path: String) {
guard let dispatchSource = dispatchSoureForFile(at: path) else {
print("Cannot create dispatch source to monitor file at '\(path)'")
return
}
let eventHandler = {
let data = dispatch_source_get_data(dispatchSource)
// Tell what change happened to the file. Delete it if you want
if data & DISPATCH_VNODE_WRITE != 0 {
print("File is written to")
}
if data & DISPATCH_VNODE_EXTEND != 0 {
print("File is extended to")
}
if data & DISPATCH_VNODE_DELETE != 0 {
print("File is deleted")
}
// Sometimes the old version of the file is deleted before the new version is written
// to disk. This happens when you call `writeToFile(_, atomically: true)` for example.
// In that case, we want to stop monitoring at the old node and start at the new node
if data & DISPATCH_VNODE_DELETE == 1 {
dispatch_source_cancel(dispatchSource)
self.startMonitoringFile(at: path)
return
}
// Always update the GUI from the main queue
let fileContent = try! String(contentsOfFile: path)
dispatch_async(dispatch_get_main_queue()) {
self.textView.string = fileContent
}
}
// When we stop monitoring a vnode, close the file handle
let cancelHandler = {
let fileHandle = dispatch_source_get_handle(dispatchSource)
close(Int32(fileHandle))
}
dispatch_source_set_registration_handler(dispatchSource, eventHandler)
dispatch_source_set_event_handler(dispatchSource, eventHandler)
dispatch_source_set_cancel_handler(dispatchSource, cancelHandler)
dispatch_resume(dispatchSource)
}
override func viewDidLoad() {
super.viewDidLoad()
self.startMonitoringFile(at: "/path/to/file.txt")
}
}
To trigger a DISPATCH_VNODE_EXTEND event, you can try this at the Terminal:
echo "Hello world" >> /path/to/file.txt
I managed to get the following code to work (in Swift 3.x) for a very similar use case. Hope it helps.
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(ViewController.commandOutputNotification(_:)),
name: NSNotification.Name.NSFileHandleDataAvailable,
object: nil)
self.startTasks()
}
func startTasks() {
self.task = Process()
self.task!.terminationHandler = self.commandTerminationHandler
let argumentsString = "tail -n 1 -f /path/to/file/file.log"
self.task!.launchPath = "/bin/sh"
self.task!.arguments = ["-c", argumentsString]
let pipe = Pipe()
task!.standardOutput = pipe
task!.standardError = pipe
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
task!.launch()
}
func commandTerminationHandler(_ task: Process) -> Void {
// TODO: finish this
}
func commandOutputNotification(_ notification: Notification) {
let fileHandle = notification.object as! FileHandle
let data = fileHandle.availableData
if data.count > 0 {
processLogData(data:(String.init(data: data, encoding: String.Encoding.utf8)))
fileHandle.waitForDataInBackgroundAndNotify()
}
}
func processLogData(data:String?) {
// Handle data String
}
I just deleted an attribute of my entity inside CoreData and after that this error appears:
2016-02-02 21:37:54.499 toRep_Management[32110:4679391] CoreData: error: -addPersistentStoreWithType:XML configuration:(null) URL:file:///Users/Tom/Library/Application%20Support/de.toEducate.toRep_Management/CocoaAppCD.storedata options:{
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
} ... returned error Error Domain=NSCocoaErrorDomain Code=134130 "Persistent store migration failed, missing source managed object model." UserInfo={URL=file:///Users/Tom/Library/Application%20Support/de.toEducate.toRep_Management/CocoaAppCD.storedata, metadata={type = immutable dict, count = 6,
entries =>
0 : {contents = "NSStoreUUID"} = {contents = "A3FD787E-495C-493D-A3B9-2E7F7925EF7C"}
3 : {contents = "NSStoreModelVersionIdentifiers"} = (
""
)
4 : {contents = "NSStoreType"} = {contents = "XML"}
10 : {contents = "NSPersistenceFrameworkVersion"} = {value = +641, type = kCFNumberSInt64Type}
11 : {contents = "NSStoreModelVersionHashes"} = {type = mutable dict, count = 1,
entries =>
0 : Notice = {length = 32, capacity = 32, bytes = 0xd22eaaf9bb53e406e8914544584e0e72 ... 0899bacb36b735bd}
}
12 : {contents = "NSStoreModelVersionHashesVersion"} = {value = +3, type = kCFNumberSInt64Type}
}
, reason=Can't find model for source store} with userInfo dictionary {
URL = "file:///Users/Tom/Library/Application%20Support/de.toEducate.toRep_Management/CocoaAppCD.storedata";
metadata = {
NSPersistenceFrameworkVersion = 641;
NSStoreModelVersionHashes = {
Notice = ;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
""
);
NSStoreType = XML;
NSStoreUUID = "A3FD787E-495C-493D-A3B9-2E7F7925EF7C";
};
reason = "Can't find model for source store";
}
2016-02-02 21:37:54.499 toRep_Management[32110:4679391] CoreData: annotation: NSPersistentStoreCoordinator's current model hashes are {
Notice = <2465d170 cdc5f276 8e769b4d 25c03a0d 8efb193b 6707ab4d 46419c42 17733df1>;
}
I thought I implemented a lightweight migration correctly but now I´m not sure anymore.
My AppDelegate:
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: NSURL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "de.toEducate.toRep_Management" in the user's Application Support directory.
let urls = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask)
let appSupportURL = urls[urls.count - 1]
return appSupportURL.URLByAppendingPathComponent("de.toEducate.toRep_Management")
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = NSBundle.mainBundle().URLForResource("toRep_Management", withExtension: "momd")!
return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. (The directory for the store is created, if necessary.) This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
let fileManager = NSFileManager.defaultManager()
var failError: NSError? = nil
var shouldFail = false
var failureReason = "There was an error creating or loading the application's saved data."
// Make sure the application files directory is there
do {
let properties = try self.applicationDocumentsDirectory.resourceValuesForKeys([NSURLIsDirectoryKey])
if !properties[NSURLIsDirectoryKey]!.boolValue {
failureReason = "Expected a folder to store application data, found a file \(self.applicationDocumentsDirectory.path)."
shouldFail = true
}
} catch {
let nserror = error as NSError
if nserror.code == NSFileReadNoSuchFileError {
do {
try fileManager.createDirectoryAtPath(self.applicationDocumentsDirectory.path!, withIntermediateDirectories: true, attributes: nil)
} catch {
failError = nserror
}
} else {
failError = nserror
}
}
// Create the coordinator and store
var coordinator: NSPersistentStoreCoordinator? = nil
let migrateOptions = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
if failError == nil {
coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("CocoaAppCD.storedata")
do {
try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: migrateOptions)
} catch {
failError = error as NSError
}
}
if shouldFail || (failError != nil) {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
if failError != nil {
dict[NSUnderlyingErrorKey] = failError
}
let error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
NSApplication.sharedApplication().presentError(error)
abort()
} else {
return coordinator!
}
}()
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving and Undo support
#IBAction func saveAction(sender: AnyObject!) {
// Performs the save action for the application, which is to send the save: message to the application's managed object context. Any encountered errors are presented to the user.
if !managedObjectContext.commitEditing() {
NSLog("\(NSStringFromClass(self.dynamicType)) unable to commit editing before saving")
}
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
NSApplication.sharedApplication().presentError(nserror)
}
}
}
func windowWillReturnUndoManager(window: NSWindow) -> NSUndoManager? {
// Returns the NSUndoManager for the application. In this case, the manager returned is that of the managed object context for the application.
return managedObjectContext.undoManager
}
func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
// Save changes in the application's managed object context before the application terminates.
if !managedObjectContext.commitEditing() {
NSLog("\(NSStringFromClass(self.dynamicType)) unable to commit editing to terminate")
return .TerminateCancel
}
if !managedObjectContext.hasChanges {
return .TerminateNow
}
do {
try managedObjectContext.save()
} catch {
let nserror = error as NSError
// Customize this code block to include application-specific recovery steps.
let result = sender.presentError(nserror)
if (result) {
return .TerminateCancel
}
let question = NSLocalizedString("Could not save changes while quitting. Quit anyway?", comment: "Quit without saves error question message")
let info = NSLocalizedString("Quitting now will lose any changes you have made since the last successful save", comment: "Quit without saves error question info");
let quitButton = NSLocalizedString("Quit anyway", comment: "Quit anyway button title")
let cancelButton = NSLocalizedString("Cancel", comment: "Cancel button title")
let alert = NSAlert()
alert.messageText = question
alert.informativeText = info
alert.addButtonWithTitle(quitButton)
alert.addButtonWithTitle(cancelButton)
let answer = alert.runModal()
if answer == NSAlertFirstButtonReturn {
return .TerminateCancel
}
}
// If we got here, it is time to quit.
return .TerminateNow
}
Could anybody help with the error and how can I handle this in future with a better migration?
"Can't find model for source store" means that you're trying to do a model migration but that Core Data can't find the old version of the data model. For migration to work, you need to have both the old version and the new version. The error suggests that you only have the new version.
When you're going to change a data model and migrate data, you need to create a new version of the model in your project. You'd do this by selecting the model file in Xcode and using "Editor" menu --> "Add Model Version". Then you'd make your changes to the new version while leaving the old one in place.
You need to restore the old model. The best way to do that is to just look back through your SCM (git, probably) commits and get it.