Skip to content

Commit e361e7c

Browse files
committed
~ Work on new backups
1 parent 6a58c86 commit e361e7c

File tree

8 files changed

+184
-46
lines changed

8 files changed

+184
-46
lines changed

Cork/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ private extension View
439439
SudoRequiredForRemovalSheet()
440440

441441
case .brewfileExport:
442-
BrewfileManager.BrewfileExportStage.exporting
442+
BrewfileExportSheet()
443443

444444
case .brewfileImport:
445445
BrewfileImportProgressView()
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>CFBundleDevelopmentRegion</key>
6+
<string>$(DEVELOPMENT_LANGUAGE)</string>
7+
<key>CFBundleIdentifier</key>
8+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
9+
<key>CFBundleInfoDictionaryVersion</key>
10+
<string>6.0</string>
11+
<key>CFBundleName</key>
12+
<string>$(PRODUCT_NAME)</string>
13+
<key>CFBundlePackageType</key>
14+
<string>BNDL</string>
15+
<key>CFBundleShortVersionString</key>
16+
<string>1.0</string>
17+
<key>CFBundleVersion</key>
18+
<string>1</string>
19+
<key>NSHumanReadableCopyright</key>
20+
<string>Copyright ©. All rights reserved.</string>
21+
</dict>
22+
</plist>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// periphery:ignore:all
2+
// swiftlint:disable:this file_name
3+
// swiftlint:disable all
4+
// swift-format-ignore-file
5+
// swiftformat:disable all
6+
#if hasFeature(InternalImportsByDefault)
7+
public import Foundation
8+
#else
9+
import Foundation
10+
#endif
11+
// MARK: - Swift Bundle Accessor - for SPM
12+
private class BundleFinder {}
13+
extension Foundation.Bundle {
14+
/// Since CorkFeature_Brewfiles is a static library, the bundle containing the resources is copied into the final product.
15+
static let module: Bundle = {
16+
let bundleName = "Cork_CorkFeature_Brewfiles"
17+
let bundleFinderResourceURL = Bundle(for: BundleFinder.self).resourceURL
18+
var candidates = [
19+
Bundle.main.resourceURL,
20+
bundleFinderResourceURL,
21+
Bundle.main.bundleURL,
22+
]
23+
// This is a fix to make Previews work with bundled resources.
24+
// Logic here is taken from SPM's generated `resource_bundle_accessors.swift` file,
25+
// which is located under the derived data directory after building the project.
26+
if let override = ProcessInfo.processInfo.environment["PACKAGE_RESOURCE_BUNDLE_PATH"] {
27+
candidates.append(URL(fileURLWithPath: override))
28+
// Deleting derived data and not rebuilding the frameworks containing resources may result in a state
29+
// where the bundles are only available in the framework's directory that is actively being previewed.
30+
// Since we don't know which framework this is, we also need to look in all the framework subpaths.
31+
if let subpaths = try? Foundation.FileManager.default.contentsOfDirectory(atPath: override) {
32+
for subpath in subpaths {
33+
if subpath.hasSuffix(".framework") {
34+
candidates.append(URL(fileURLWithPath: override + "/" + subpath))
35+
}
36+
}
37+
}
38+
}
39+
40+
// This is a fix to make unit tests work with bundled resources.
41+
// Making this change allows unit tests to search one directory up for a bundle.
42+
// More context can be found in this PR: https://github.com/tuist/tuist/pull/6895
43+
#if canImport(XCTest)
44+
candidates.append(bundleFinderResourceURL?.appendingPathComponent(".."))
45+
#endif
46+
47+
for candidate in candidates {
48+
let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
49+
if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
50+
return bundle
51+
}
52+
}
53+
fatalError("unable to find bundle named Cork_CorkFeature_Brewfiles")
54+
}()
55+
}
56+
// MARK: - Objective-C Bundle Accessor
57+
@objc
58+
public class CorkFeatureBrewfilesResources: NSObject {
59+
@objc public class var bundle: Bundle {
60+
return .module
61+
}
62+
}
63+
// swiftformat:enable all
64+
// swiftlint:enable all

Modules/Features/Brewfiles/Logic/Export Brewfile.swift

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@ public extension BrewfileManager
1414
{
1515
enum BrewfileDumpingError: LocalizedError
1616
{
17-
case couldNotDetermineWorkingDirectory, errorWhileDumpingBrewfile(error: String), couldNotReadBrewfile(error: String)
17+
case couldNotDetermineWorkingDirectory
18+
case errorWhileDumpingBrewfile(errors: [String])
19+
case couldNotReadBrewfile(error: String)
1820

1921
public var errorDescription: String?
2022
{
2123
switch self
2224
{
2325
case .couldNotDetermineWorkingDirectory:
2426
return String(localized: "error.brewfile.export.could-not-determine-working-directory")
25-
case .errorWhileDumpingBrewfile(let error):
26-
return String(localized: "error.brewfile.export.could-not-dump-with-error.\(error)")
27+
case .errorWhileDumpingBrewfile:
28+
return String(localized: "error.brewfile.export.could-not-dump-with-error")
2729
case .couldNotReadBrewfile(let error):
2830
return error
2931
}
@@ -34,46 +36,38 @@ public extension BrewfileManager
3436
@MainActor
3537
func exportBrewfile() async throws(BrewfileDumpingError) -> BrewbakFile
3638
{
37-
let brewfileParentLocation: URL = URL.temporaryDirectory
38-
39-
let pathRawOutput: [TerminalOutput] = await shell(URL(string: "/bin/pwd")!, ["-L"])
40-
41-
let brewfileDumpingResult: [TerminalOutput] = await shell(AppConstants.shared.brewExecutablePath, ["bundle", "-f", "dump"], workingDirectory: brewfileParentLocation)
42-
43-
/// Throw an error if the working directory could not be determined
44-
if pathRawOutput.containsErrors
45-
{
46-
throw BrewfileDumpingError.couldNotDetermineWorkingDirectory
47-
}
39+
let brewfileParentLocation: URL = URL.temporaryDirectory.resolvingSymlinksInPath()
4840

49-
guard let finalPathOutput: String = pathRawOutput.standardOutputs.first else
50-
{
51-
throw BrewfileDumpingError.couldNotDetermineWorkingDirectory
52-
}
53-
54-
/// Throw an error if the working directory is so fucked up it's unusable
55-
guard let workingDirectory: URL = URL(string: finalPathOutput.trimmingCharacters(in: .whitespacesAndNewlines)) else
56-
{
57-
throw BrewfileDumpingError.couldNotDetermineWorkingDirectory
58-
}
41+
let finalBrewfileLocation: URL = brewfileParentLocation.appendingPathComponent("Brewfile", conformingTo: .fileURL)
42+
43+
AppConstants.shared.logger.info("Brewfile parent location: \(brewfileParentLocation)")
44+
45+
let brewfileDumpingResult: [TerminalOutput] = await shell(AppConstants.shared.brewExecutablePath, ["bundle", "dump", "--file", finalBrewfileLocation.path])
5946

60-
if brewfileDumpingResult.standardErrors.contains("(E|e)rror")
47+
guard !brewfileDumpingResult.contains("Error", in: .standardErrors, .standardOutputs) else
6148
{
62-
throw BrewfileDumpingError.errorWhileDumpingBrewfile(error: brewfileDumpingResult.standardErrors.formatted(.list(type: .and)))
49+
AppConstants.shared.logger.error("There was an error in the dumping result")
50+
51+
throw BrewfileDumpingError.errorWhileDumpingBrewfile(errors: brewfileDumpingResult.standardErrors)
6352
}
6453

65-
AppConstants.shared.logger.info("Path: \(workingDirectory.path(), privacy: .auto)")
66-
6754
print("Brewfile dumping result: \(brewfileDumpingResult)")
6855

69-
let brewfileLocation: URL = brewfileParentLocation.appendingPathComponent("Brewfile", conformingTo: .fileURL)
70-
56+
let doesBrewfileExist: Bool = FileManager.default.fileExists(atPath: finalBrewfileLocation.path())
57+
58+
AppConstants.shared.logger.info("Does brewfile exist an expected location? \(doesBrewfileExist)")
59+
7160
do
7261
{
73-
let brewfileContents: String = try String(contentsOf: brewfileLocation)
62+
let brewfileContents: String = try String(contentsOf: finalBrewfileLocation)
7463

7564
/// Delete the brewfile
76-
try? FileManager.default.removeItem(at: brewfileLocation)
65+
do
66+
{
67+
try FileManager.default.removeItem(at: finalBrewfileLocation)
68+
} catch let tempBrewfileDeletionError {
69+
AppConstants.shared.logger.error("Fialed while deleting old brewfile: \(tempBrewfileDeletionError)")
70+
}
7771

7872
return .init(text: brewfileContents)
7973
}

Modules/Features/Brewfiles/Views/Brewbak Icon Proxy.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public struct BrewfileIconProxy: View
2222
{
2323
Image(nsImage: NSWorkspace.shared.icon(for: .brewbak))
2424
.resizable()
25-
.frame(width: 32, height: 32)
25+
.frame(width: 50, height: 50)
2626

2727
Text("backup.brewbak-file.name")
2828
.font(.caption)

Modules/Features/Brewfiles/Views/Brewfile Export Sheet.swift

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@
77

88
import FactoryKit
99
import SwiftUI
10+
import CorkShared
1011

1112
public struct BrewfileExportSheet: View
1213
{
1314
@InjectedObservable(\.brewfileManager) var brewfileManager: BrewfileManager
1415

16+
public init()
17+
{
18+
brewfileManager.exportStage = .exporting
19+
}
20+
1521
public var body: some View
1622
{
17-
brewfileManager.exportStage.body
18-
.padding()
23+
NavigationStack
24+
{
25+
brewfileManager.exportStage.body
26+
.padding()
27+
.navigationTitle("brewfile.export.title")
28+
}
1929
}
2030
}
2131

@@ -37,6 +47,7 @@ struct ExportingView: View
3747
}
3848
}
3949

50+
@MainActor
4051
func performStageAction() async
4152
{
4253
do
@@ -47,18 +58,41 @@ struct ExportingView: View
4758
}
4859
catch let brewfileExportError
4960
{
61+
AppConstants.shared.logger.error("Caught error from export function: \(brewfileExportError)")
5062
brewfileManager.exportStage = .erroredOut(withError: brewfileExportError)
5163
}
5264
}
5365
}
5466

5567
struct FinishedView: View
5668
{
69+
@Environment(\.dismiss) var dismiss: DismissAction
70+
5771
let brewbakFile: BrewbakFile
5872

5973
var body: some View
6074
{
61-
BrewfileIconProxy(brewbak: brewbakFile)
75+
HStack(alignment: .top, spacing: 10)
76+
{
77+
BrewfileIconProxy(brewbak: brewbakFile)
78+
79+
VStack(alignment: .leading)
80+
{
81+
Text("brewfile.export.success.title")
82+
.font(.headline)
83+
Text("brewfile.export.success.instructions")
84+
}
85+
}
86+
.toolbar {
87+
ToolbarItem(placement: .cancellationAction) {
88+
Button {
89+
dismiss()
90+
} label: {
91+
Text("action.close")
92+
}
93+
94+
}
95+
}
6296
}
6397
}
6498

@@ -68,14 +102,35 @@ struct ErroredOutView: View
68102

69103
var body: some View
70104
{
71-
switch error
105+
106+
HStack(alignment: .top, spacing: 10)
72107
{
73-
case .couldNotDetermineWorkingDirectory:
74-
Text(BrewfileManager.BrewfileDumpingError.couldNotDetermineWorkingDirectory.localizedDescription)
75-
case .errorWhileDumpingBrewfile(let error):
76-
Text(error)
77-
case .couldNotReadBrewfile(let error):
78-
Text(error)
108+
Image(systemName: "xmark.seal")
109+
.resizable()
110+
.frame(width: 50, height: 50)
111+
.foregroundColor(.secondary)
112+
113+
VStack(alignment: .leading)
114+
{
115+
Text("error.brewfile.export.could-not-dump")
116+
.font(.headline)
117+
118+
switch error
119+
{
120+
case .couldNotDetermineWorkingDirectory:
121+
Text(BrewfileManager.BrewfileDumpingError.couldNotDetermineWorkingDirectory.localizedDescription)
122+
case .errorWhileDumpingBrewfile(let errors):
123+
List(errors, id: \.self)
124+
{ error in
125+
Text(error)
126+
}
127+
.listStyle(.bordered)
128+
.alternatingRowBackgrounds()
129+
.frame(minHeight: 200)
130+
case .couldNotReadBrewfile(let error):
131+
Text(error)
132+
}
133+
}
79134
}
80135
}
81136
}

Modules/TerminalSupport/Models/Terminal Output.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,14 @@ public extension [TerminalOutput]
7777
public extension [TerminalOutput]
7878
{
7979
/// Whether to look for the particular string in outputs or errors
80-
enum ContainsLookupType
80+
public enum ContainsLookupType
8181
{
8282
case standardOutputs
8383
case standardErrors
8484
}
8585

8686
/// Return a boolean value that indicates whether a String is present in the specified output type for this ``TerminalOutput`` array
87-
func contains(
87+
public func contains(
8888
_ searchString: String,
8989
in outputTypes: ContainsLookupType...
9090
) -> Bool

Project.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ let corkFeature_brewfiles: ProjectDescription.Target = .target(
210210
sources: [
211211
"Modules/Features/Brewfiles/**/*.swift"
212212
],
213+
resources: [
214+
"Cork/Localizable.xcstrings"
215+
],
213216
dependencies: [
214217
.target(corkSharedTarget),
215218
.target(corkModelsTarget),

0 commit comments

Comments
 (0)