Skip to content

Commit

Permalink
Merge pull request #4 from Yoshi2889/feature/start_watcher
Browse files Browse the repository at this point in the history
Directory watcher
  • Loading branch information
NanoSector authored Mar 13, 2021
2 parents 0d004ec + 5dbec90 commit 032069a
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 8 deletions.
4 changes: 4 additions & 0 deletions Brewed.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
CD6C478525FCF9E8004BA6DD /* RestartCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6C478425FCF9E8004BA6DD /* RestartCommand.swift */; };
CD6C478825FD0522004BA6DD /* GlobalAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6C478725FD0522004BA6DD /* GlobalAlert.swift */; };
CD6C478B25FD0B4F004BA6DD /* FileMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6C478A25FD0B4F004BA6DD /* FileMonitor.swift */; };
CD6C479525FD4721004BA6DD /* FolderMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6C479425FD4721004BA6DD /* FolderMonitor.swift */; };
CD85838725FABE8E00E3974F /* BrewedApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD85838625FABE8E00E3974F /* BrewedApp.swift */; };
CD85838925FABE8E00E3974F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD85838825FABE8E00E3974F /* ContentView.swift */; };
CD85838B25FABE9300E3974F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD85838A25FABE9300E3974F /* Assets.xcassets */; };
Expand All @@ -38,6 +39,7 @@
CD6C478425FCF9E8004BA6DD /* RestartCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RestartCommand.swift; sourceTree = "<group>"; };
CD6C478725FD0522004BA6DD /* GlobalAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalAlert.swift; sourceTree = "<group>"; };
CD6C478A25FD0B4F004BA6DD /* FileMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileMonitor.swift; sourceTree = "<group>"; };
CD6C479425FD4721004BA6DD /* FolderMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderMonitor.swift; sourceTree = "<group>"; };
CD85838325FABE8E00E3974F /* Brewed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Brewed.app; sourceTree = BUILT_PRODUCTS_DIR; };
CD85838625FABE8E00E3974F /* BrewedApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewedApp.swift; sourceTree = "<group>"; };
CD85838825FABE8E00E3974F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -186,6 +188,7 @@
CDCCCE4925FBED2C00C3590A /* Collection.swift */,
CDA7929025FBFBB3006FFAB1 /* Regex.swift */,
CD6C478A25FD0B4F004BA6DD /* FileMonitor.swift */,
CD6C479425FD4721004BA6DD /* FolderMonitor.swift */,
);
path = Helpers;
sourceTree = "<group>";
Expand Down Expand Up @@ -269,6 +272,7 @@
CDA7928D25FBFA58006FFAB1 /* AutostartService.swift in Sources */,
CD6C478525FCF9E8004BA6DD /* RestartCommand.swift in Sources */,
CD85838725FABE8E00E3974F /* BrewedApp.swift in Sources */,
CD6C479525FD4721004BA6DD /* FolderMonitor.swift in Sources */,
CDA7928725FBEFC9006FFAB1 /* ManagedServices.swift in Sources */,
CD6C477125FCE2AC004BA6DD /* ServiceInfo.swift in Sources */,
CDCCCE4725FBE6D500C3590A /* Service.swift in Sources */,
Expand Down
8 changes: 4 additions & 4 deletions Brewed/Helpers/FileMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
import Foundation

protocol FileMonitorDelegate: AnyObject {
func deleted(url: URL, event: DispatchSource.FileSystemEvent)
func fileEvent(url: URL, event: DispatchSource.FileSystemEvent)
}

final class FileMonitor {
final class FileMonitor: FilesystemMonitor {
let url: URL

let fileHandle: FileHandle
Expand All @@ -28,13 +28,13 @@ final class FileMonitor {

source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: fileHandle.fileDescriptor,
eventMask: .delete,
eventMask: [.write, .delete],
queue: DispatchQueue.main
)

source.setEventHandler {
let event = self.source.data
self.delegate?.deleted(url: url, event: event)
self.delegate?.fileEvent(url: url, event: event)
}

source.setCancelHandler {
Expand Down
60 changes: 60 additions & 0 deletions Brewed/Helpers/FolderMonitor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// FolderMonitor.swift
// Brewed
//
// Created by Rick Kerkhof on 13/03/2021.
//
// Code found from https://swiftrocks.com/dispatchsource-detecting-changes-in-files-and-folders-in-swift
// and altered.
//

import Foundation

protocol FolderMonitorDelegate: AnyObject {
func folderEvent(url: URL, event: DispatchSource.FileSystemEvent, additions: [URL])
}

protocol FilesystemMonitor {}

final class FolderMonitor: FilesystemMonitor {
let url: URL

let fileHandle: Int32
let source: DispatchSourceFileSystemObject

weak var delegate: FolderMonitorDelegate?

init(url: URL) throws {
self.url = url
fileHandle = open(url.path, O_EVTONLY)

source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: fileHandle,
eventMask: .write,
queue: DispatchQueue.main
)

var contents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)

source.setEventHandler {
let event = self.source.data
let oldContents = contents
contents = try! FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil)
self.delegate?.folderEvent(
url: url,
event: event,
additions: contents.filter { !oldContents.contains($0) }
)
}

source.setCancelHandler {
close(self.fileHandle)
}

source.resume()
}

deinit {
source.cancel()
}
}
16 changes: 16 additions & 0 deletions Brewed/Homebrew/Services/AutostartService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ struct AutostartDirectory {

return regex?.matches(url?.absoluteString ?? "") ?? false
}

static func urls() -> [URL] {
var urls = [
URL(fileURLWithPath: AutostartDirectory.global, isDirectory: true)
]

if let local = try? FileManager.default.url(for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
urls.append(local.appendingPathComponent("LaunchAgents"))
}

return urls
}
}

extension Service {
Expand All @@ -30,4 +42,8 @@ extension Service {
var startsAtLogin: Bool {
AutostartDirectory.isLocalPlist(plist)
}

var plistName: String {
"homebrew.mxcl.\(self.id).plist"
}
}
27 changes: 23 additions & 4 deletions Brewed/Model/ManagedServices.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@

import Foundation

class ManagedServices: ObservableObject, FileMonitorDelegate {

class ManagedServices: ObservableObject, FileMonitorDelegate, FolderMonitorDelegate {
@Published var services: [Service] = []

@Published var refreshing = false

private var monitors: [URL: FileMonitor] = [:]
private var monitors: [URL: FilesystemMonitor] = [:]

func update(service: Service) {
var services = self.services
Expand All @@ -34,6 +33,14 @@ class ManagedServices: ObservableObject, FileMonitorDelegate {
self.monitors.removeAll()

self.services = services

AutostartDirectory.urls().forEach { url in
if let monitor = try? FolderMonitor(url: url) {
self.monitors[url] = monitor
monitor.delegate = self
}
}

self.services.forEach { service in
guard let plist = service.plist else {
return
Expand All @@ -49,7 +56,19 @@ class ManagedServices: ObservableObject, FileMonitorDelegate {
}.cauterize()
}

func deleted(url: URL, event: DispatchSource.FileSystemEvent) {
func fileEvent(url: URL, event: DispatchSource.FileSystemEvent) {
DispatchQueue.main.async {
self.refresh()
}
}

func folderEvent(url: URL, event: DispatchSource.FileSystemEvent, additions: [URL]) {
let wantedPlistNames = services.map { $0.plistName }

if !additions.contains(where: { wantedPlistNames.contains($0.lastPathComponent) }) {
return
}

DispatchQueue.main.async {
self.refresh()
}
Expand Down

0 comments on commit 032069a

Please sign in to comment.