From 083f8ebec89c35790d4bcbe0d1a8eb660146dd1c Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Sat, 19 Mar 2022 15:13:46 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Add=20marketing=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 12 ++ .../xcschemes/PHP Monitor.xcscheme | 7 ++ .../Integrations/Valet/SiteScanner.swift | 118 ++++++++++++++++++ phpmon/Domain/Integrations/Valet/Valet.swift | 86 +++---------- .../Integrations/Valet/ValetSite+Fake.swift | 37 ++++++ .../Domain/Integrations/Valet/ValetSite.swift | 19 ++- 6 files changed, 208 insertions(+), 71 deletions(-) create mode 100644 phpmon/Domain/Integrations/Valet/SiteScanner.swift create mode 100644 phpmon/Domain/Integrations/Valet/ValetSite+Fake.swift diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index b7442a4..b561b6a 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -62,6 +62,10 @@ C417DC75277614690015E6EE /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C417DC73277614690015E6EE /* Helpers.swift */; }; C4188989275FE8CB001EF227 /* Filesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4188988275FE8CB001EF227 /* Filesystem.swift */; }; C418898A275FE8CB001EF227 /* Filesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4188988275FE8CB001EF227 /* Filesystem.swift */; }; + C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A527E60D7A009F26CB /* SiteScanner.swift */; }; + C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */; }; + C41C02AA27E61CA3009F26CB /* SiteScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A527E60D7A009F26CB /* SiteScanner.swift */; }; + C41C02AB27E61CB3009F26CB /* ValetSite+Fake.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */; }; C41C1B3722B0097F00E7CF16 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */; }; C41C1B3B22B0098000E7CF16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3A22B0098000E7CF16 /* Assets.xcassets */; }; C41C1B3E22B0098000E7CF16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C41C1B3C22B0098000E7CF16 /* Main.storyboard */; }; @@ -267,6 +271,8 @@ C4168F4427ADB4A3003B6C39 /* DEVELOPER.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = DEVELOPER.md; sourceTree = ""; }; C417DC73277614690015E6EE /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; C4188988275FE8CB001EF227 /* Filesystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Filesystem.swift; sourceTree = ""; }; + C41C02A527E60D7A009F26CB /* SiteScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteScanner.swift; sourceTree = ""; }; + C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ValetSite+Fake.swift"; sourceTree = ""; }; C41C1B3322B0097F00E7CF16 /* PHP Monitor.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "PHP Monitor.app"; sourceTree = BUILT_PRODUCTS_DIR; }; C41C1B3622B0097F00E7CF16 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; C41C1B3A22B0098000E7CF16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -656,6 +662,8 @@ children = ( C4AF9F792754499000D44ED0 /* Valet.swift */, C4E4404527C56F4700D225E1 /* ValetSite.swift */, + C41C02A827E61A65009F26CB /* ValetSite+Fake.swift */, + C41C02A527E60D7A009F26CB /* SiteScanner.swift */, C4D5CFC927E0F9CD00035329 /* NginxConfigParser.swift */, ); path = Valet; @@ -978,6 +986,7 @@ C48D0CA325CC992000CC7490 /* StatsView.swift in Sources */, C40C7F2827721FF600DDDCDC /* ActivePhpInstallation+Checks.swift in Sources */, C4EE55A927708B9E001DF387 /* PMHeaderView.swift in Sources */, + C41C02A927E61A65009F26CB /* ValetSite+Fake.swift in Sources */, C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */, C4CCBA6C275C567B008C7055 /* PMWindowController.swift in Sources */, C4B585442770FE3900DA4FBE /* Command.swift in Sources */, @@ -1043,6 +1052,7 @@ C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */, C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */, C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */, + C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */, C464ADAC275A7A3F003FCD53 /* SiteListWC.swift in Sources */, C464ADB2275A87CA003FCD53 /* SiteListCellProtocol.swift in Sources */, C4EE188422D3386B00E126E5 /* Constants.swift in Sources */, @@ -1066,6 +1076,7 @@ C4F780C825D80B75000DBC97 /* DateExtension.swift in Sources */, C493084B279F331F009C240B /* AddSiteVC.swift in Sources */, C4D9ADC0277610E1007277F4 /* PhpSwitcher.swift in Sources */, + C41C02AA27E61CA3009F26CB /* SiteScanner.swift in Sources */, C4080FFB27BD956700BF2C6B /* BetterAlertVC.swift in Sources */, C4F780CC25D80B75000DBC97 /* ActivePhpInstallation.swift in Sources */, 54D9E0BB27E4F51E003B9AD9 /* ModifierFlagsExtension.swift in Sources */, @@ -1139,6 +1150,7 @@ C4E4404727C56F4700D225E1 /* ValetSite.swift in Sources */, C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */, C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */, + C41C02AB27E61CB3009F26CB /* ValetSite+Fake.swift in Sources */, C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */, C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */, C481F79A26164A7C004FBCFF /* Preferences.swift in Sources */, diff --git a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor.xcscheme b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor.xcscheme index b4996e7..1dedb84 100644 --- a/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor.xcscheme +++ b/PHP Monitor.xcodeproj/xcshareddata/xcschemes/PHP Monitor.xcscheme @@ -62,6 +62,13 @@ ReferencedContainer = "container:PHP Monitor.xcodeproj"> + + + + Int + + func resolveSitesFrom(paths: [String]) -> [ValetSite] +} + +class FakeSiteScanner: SiteScanner +{ + let fakes = [ + ValetSite(fakeWithName: "laravel", tld: "test", secure: true, path: "~/Code/laravel/framework", linked: true), + + ValetSite(fakeWithName: "tailwind", tld: "test", secure: true, path: "~/Code/tailwind/site", linked: true), + + ValetSite(fakeWithName: "forge", tld: "test", secure: true, path: "~/Code/laravel/forge", linked: true), + + ValetSite(fakeWithName: "wordpress", tld: "test", secure: false, + path: "~/Code/wordpress", linked: false, driver: "Wordpress", constraint: "^7.4", isolated: "7.4") + ] + + func resolveSiteCount(paths: [String]) -> Int { + return fakes.count + } + + func resolveSitesFrom(paths: [String]) -> [ValetSite] { + return fakes + } +} + +class ValetSiteScanner: SiteScanner +{ + func resolveSiteCount(paths: [String]) -> Int { + return paths.map { path in + + let entries = try! FileManager.default + .contentsOfDirectory(atPath: path) + + return entries + .map { self.isSite($0, forPath: path) } + .filter{ $0 == true} + .count + + }.reduce(0, +) + } + + func resolveSitesFrom(paths: [String]) -> [ValetSite] { + var sites: [ValetSite] = [] + + paths.forEach { path in + let entries = try! FileManager.default + .contentsOfDirectory(atPath: path) + + return entries.forEach { + if let site = self.getSite($0, forPath: path, tld: Valet.shared.config.tld) { + sites.append(site) + } + } + } + + return sites + } + + /** + Determines whether the site can be resolved as a symbolic link or as a directory. + Regular files are ignored. Returns true if the path can be parsed. + */ + private func isSite(_ entry: String, forPath path: String) -> Bool { + let siteDir = path + "/" + entry + + let attrs = try! FileManager.default.attributesOfItem(atPath: siteDir) + + let type = attrs[FileAttributeKey.type] as! FileAttributeType + + if type == FileAttributeType.typeSymbolicLink || type == FileAttributeType.typeDirectory { + return true + } + + return false + } + + /** + Determines whether the site can be resolved as a symbolic link or as a directory. + Regular files are ignored, and the site is added to Valet's list of sites. + */ + private func getSite(_ entry: String, forPath path: String, tld: String) -> ValetSite? { + let siteDir = path + "/" + entry + + // See if the file is a symlink, if so, resolve it + let attrs = try! FileManager.default.attributesOfItem(atPath: siteDir) + + // We can also determine whether the thing at the path is a directory, too + let type = attrs[FileAttributeKey.type] as! FileAttributeType + + // We should also check that we can interpret the path correctly + if URL(fileURLWithPath: siteDir).lastPathComponent == "" { + Log.warn("Could not parse the site: \(siteDir), skipping!") + return nil + } + + if type == FileAttributeType.typeSymbolicLink { + return ValetSite(aliasPath: siteDir, tld: tld) + } else if type == FileAttributeType.typeDirectory { + return ValetSite(absolutePath: siteDir, tld: tld) + } + + return nil + } +} diff --git a/phpmon/Domain/Integrations/Valet/Valet.swift b/phpmon/Domain/Integrations/Valet/Valet.swift index 92c9b95..5c9f264 100644 --- a/phpmon/Domain/Integrations/Valet/Valet.swift +++ b/phpmon/Domain/Integrations/Valet/Valet.swift @@ -38,6 +38,19 @@ class Valet { self.sites = [] } + /** + If marketing mode is enabled, show a list of sites that are used for promotional screenshots. + This can be done by swapping out the real Valet scanner with one that always returns a fixed + list of fake sites. You should not interact with these sites! + */ + static var siteScanner: SiteScanner { + if ProcessInfo.processInfo.environment["PHPMON_MARKETING_MODE"] != nil { + return FakeSiteScanner() + } + + return ValetSiteScanner() + } + /** Check if a particular feature is enabled. */ @@ -89,7 +102,7 @@ class Valet { return } - resolvePaths(tld: config.tld) + resolvePaths() } /** @@ -128,82 +141,23 @@ class Valet { Returns a count of how many sites are linked and parked. */ private func countPaths() -> Int { - var count = 0 - for path in config.paths { - let entries = try! FileManager.default.contentsOfDirectory(atPath: path) - for entry in entries { - if resolveSite(entry, forPath: path) { - count += 1 - } - } - } - return count + return Self.siteScanner + .resolveSiteCount(paths: config.paths) } /** Resolves all paths and creates linked or parked site instances that can be referenced later. */ - private func resolvePaths(tld: String) { + private func resolvePaths() { isBusy = true - sites = [] - - for path in config.paths { - let entries = try! FileManager.default.contentsOfDirectory(atPath: path) - for entry in entries { - resolvePath(entry, forPath: path, tld: tld) - } - } - - sites = sites.sorted { $0.absolutePath < $1.absolutePath } + sites = Self.siteScanner + .resolveSitesFrom(paths: config.paths) + .sorted { $0.absolutePath < $1.absolutePath } isBusy = false } - /** - Determines whether the site can be resolved as a symbolic link or as a directory. - Regular files are ignored. Returns true if the path can be parsed. - */ - private func resolveSite(_ entry: String, forPath path: String) -> Bool { - let siteDir = path + "/" + entry - - let attrs = try! FileManager.default.attributesOfItem(atPath: siteDir) - - let type = attrs[FileAttributeKey.type] as! FileAttributeType - - if type == FileAttributeType.typeSymbolicLink || type == FileAttributeType.typeDirectory { - return true - } - - return false - } - - /** - Determines whether the site can be resolved as a symbolic link or as a directory. - Regular files are ignored, and the site is added to Valet's list of sites. - */ - private func resolvePath(_ entry: String, forPath path: String, tld: String) { - let siteDir = path + "/" + entry - - // See if the file is a symlink, if so, resolve it - let attrs = try! FileManager.default.attributesOfItem(atPath: siteDir) - - // We can also determine whether the thing at the path is a directory, too - let type = attrs[FileAttributeKey.type] as! FileAttributeType - - // We should also check that we can interpret the path correctly - if URL(fileURLWithPath: siteDir).lastPathComponent == "" { - Log.warn("Could not parse the site: \(siteDir), skipping!") - return - } - - if type == FileAttributeType.typeSymbolicLink { - sites.append(ValetSite(aliasPath: siteDir, tld: tld)) - } else if type == FileAttributeType.typeDirectory { - sites.append(ValetSite(absolutePath: siteDir, tld: tld)) - } - } - struct Configuration: Decodable { /// Top level domain suffix. Usually "test" but can be set to something else. /// - Important: Does not include the actual dot. ("test", not ".test"!) diff --git a/phpmon/Domain/Integrations/Valet/ValetSite+Fake.swift b/phpmon/Domain/Integrations/Valet/ValetSite+Fake.swift new file mode 100644 index 0000000..777361a --- /dev/null +++ b/phpmon/Domain/Integrations/Valet/ValetSite+Fake.swift @@ -0,0 +1,37 @@ +// +// ValetSite+Fake.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 19/03/2022. +// Copyright © 2022 Nico Verbruggen. All rights reserved. +// + +import Foundation + +extension ValetSite { + + convenience init( + fakeWithName name: String, + tld: String, + secure: Bool, + path: String, + linked: Bool, + driver: String = "Laravel (^9.0)", + constraint: String = "^8.1", + isolated: String? = nil + ) { + self.init(name: name, tld: tld, absolutePath: path, aliasPath: nil, makeDeterminations: false) + self.secured = secure + self.composerPhp = constraint + + self.driver = driver + self.driverDeterminedByComposer = true + if linked { + self.aliasPath = self.absolutePath + } + if let isolated = isolated { + self.isolatedPhpVersion = PhpInstallation(isolated) + } + } + +} diff --git a/phpmon/Domain/Integrations/Valet/ValetSite.swift b/phpmon/Domain/Integrations/Valet/ValetSite.swift index 968e48a..5538d8a 100644 --- a/phpmon/Domain/Integrations/Valet/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/ValetSite.swift @@ -60,16 +60,25 @@ class ValetSite { case valetphprc = "valetphprc" } - init(name: String, tld: String, absolutePath: String, aliasPath: String? = nil) { + init( + name: String, + tld: String, + absolutePath: String, + aliasPath: String? = nil, + makeDeterminations: Bool = true + ) { self.name = name self.tld = tld self.absolutePath = absolutePath self.aliasPath = aliasPath + self.secured = false - determineSecured() - determineComposerPhpVersion() - determineDriver() - determineIsolated() + if makeDeterminations { + determineSecured() + determineComposerPhpVersion() + determineDriver() + determineIsolated() + } } convenience init(absolutePath: String, tld: String) {