Skip to content

Commit

Permalink
Add export import functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
milanvarady committed Jan 1, 2025
1 parent 3ea36bd commit 0ac1bc7
Show file tree
Hide file tree
Showing 17 changed files with 340 additions and 315 deletions.
34 changes: 25 additions & 9 deletions Applite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
41483CCD29101C9900BB10C2 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41483CCC29101C9900BB10C2 /* Category.swift */; };
41524B99295E352200D0046A /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41524B98295E352200D0046A /* SettingsView.swift */; };
41524B9E295FA36E00D0046A /* DebounceObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41524B9D295FA36E00D0046A /* DebounceObject.swift */; };
415563A02A9265CE00AE2F2E /* CaskExportType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4155639F2A9265CE00AE2F2E /* CaskExportType.swift */; };
415563A22A98BB2500AE2F2E /* ErrorWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 415563A12A98BB2500AE2F2E /* ErrorWindowView.swift */; };
415563A42A98C54300AE2F2E /* AppdirSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 415563A32A98C54300AE2F2E /* AppdirSelectorView.swift */; };
4166EE7028F5D4C900CE305A /* Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4166EE6F28F5D4C900CE305A /* Commands.swift */; };
Expand Down Expand Up @@ -104,6 +103,9 @@
4192569B2D24335900D9EF10 /* CaskTaskError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4192569A2D24335900D9EF10 /* CaskTaskError.swift */; };
4192569D2D2433E200D9EF10 /* CaskProgressState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4192569C2D2433E200D9EF10 /* CaskProgressState.swift */; };
419256A12D25ACC300D9EF10 /* CategoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256A02D25ACC300D9EF10 /* CategoryViewModel.swift */; };
419256A42D25CFE600D9EF10 /* AppMigrationView+ExportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256A32D25CFE600D9EF10 /* AppMigrationView+ExportView.swift */; };
419256A62D25D00200D9EF10 /* AppMigrationView+ImportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256A52D25D00200D9EF10 /* AppMigrationView+ImportView.swift */; };
419256A82D25D10F00D9EF10 /* ExportFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256A72D25D10F00D9EF10 /* ExportFile.swift */; };
419506A42964A27F00FE5802 /* SetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419506A32964A27F00FE5802 /* SetupView.swift */; };
419506A62964A5EF00FE5802 /* BrewPathSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419506A52964A5EF00FE5802 /* BrewPathSelectorView.swift */; };
4196C8F528F9CB2600EADDDA /* DiscoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4196C8F428F9CB2600EADDDA /* DiscoverView.swift */; };
Expand Down Expand Up @@ -141,7 +143,6 @@
41483CCC29101C9900BB10C2 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = "<group>"; };
41524B98295E352200D0046A /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
41524B9D295FA36E00D0046A /* DebounceObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebounceObject.swift; sourceTree = "<group>"; };
4155639F2A9265CE00AE2F2E /* CaskExportType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskExportType.swift; sourceTree = "<group>"; };
415563A12A98BB2500AE2F2E /* ErrorWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorWindowView.swift; sourceTree = "<group>"; };
415563A32A98C54300AE2F2E /* AppdirSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppdirSelectorView.swift; sourceTree = "<group>"; };
4166EE6F28F5D4C900CE305A /* Commands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Commands.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -212,6 +213,9 @@
4192569A2D24335900D9EF10 /* CaskTaskError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskTaskError.swift; sourceTree = "<group>"; };
4192569C2D2433E200D9EF10 /* CaskProgressState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskProgressState.swift; sourceTree = "<group>"; };
419256A02D25ACC300D9EF10 /* CategoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryViewModel.swift; sourceTree = "<group>"; };
419256A32D25CFE600D9EF10 /* AppMigrationView+ExportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppMigrationView+ExportView.swift"; sourceTree = "<group>"; };
419256A52D25D00200D9EF10 /* AppMigrationView+ImportView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppMigrationView+ImportView.swift"; sourceTree = "<group>"; };
419256A72D25D10F00D9EF10 /* ExportFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportFile.swift; sourceTree = "<group>"; };
419506A32964A27F00FE5802 /* SetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupView.swift; sourceTree = "<group>"; };
419506A52964A5EF00FE5802 /* BrewPathSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewPathSelectorView.swift; sourceTree = "<group>"; };
419506A729696A5300FE5802 /* Applite-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Applite-Info.plist"; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -439,7 +443,7 @@
children = (
412635422A77FB0000155034 /* Brew Installation */,
4126353F2A77C71F00155034 /* Shell */,
41B731352A878993008BF6B9 /* Import Export */,
41B731352A878993008BF6B9 /* App Migration */,
413E60B52BBAE58B00978F6A /* Network Proxy */,
418989B02A35D628004AC23B /* Verify Brew Installation */,
419256652D1E18A500D9EF10 /* Alert Manager */,
Expand Down Expand Up @@ -597,6 +601,17 @@
path = "Cask Manager";
sourceTree = "<group>";
};
419256A22D25CFBF00D9EF10 /* App Migration */ = {
isa = PBXGroup;
children = (
4192568B2D22D7FC00D9EF10 /* AppMigrationView.swift */,
419256A32D25CFE600D9EF10 /* AppMigrationView+ExportView.swift */,
419256A52D25D00200D9EF10 /* AppMigrationView+ImportView.swift */,
419256A72D25D10F00D9EF10 /* ExportFile.swift */,
);
path = "App Migration";
sourceTree = "<group>";
};
4196C8F628F9CB4100EADDDA /* App Views */ = {
isa = PBXGroup;
children = (
Expand All @@ -616,21 +631,20 @@
419256502D1E0CE000D9EF10 /* Discover */,
4192565C2D1E153D00D9EF10 /* Update */,
4196C8FF28F9E1F400EADDDA /* InstalledView.swift */,
41B731382A879353008BF6B9 /* ActiveTasksView.swift */,
419256A22D25CFBF00D9EF10 /* App Migration */,
41857B742912D94A004A1894 /* CategoryView.swift */,
418989AC2A33A5C4004AC23B /* BrewManagementView.swift */,
41B731382A879353008BF6B9 /* ActiveTasksView.swift */,
4192568B2D22D7FC00D9EF10 /* AppMigrationView.swift */,
);
path = "Detail Views";
sourceTree = "<group>";
};
41B731352A878993008BF6B9 /* Import Export */ = {
41B731352A878993008BF6B9 /* App Migration */ = {
isa = PBXGroup;
children = (
4178CF912A8689AF0037F270 /* ExportCasks.swift */,
4155639F2A9265CE00AE2F2E /* CaskExportType.swift */,
);
path = "Import Export";
path = "App Migration";
sourceTree = "<group>";
};
/* End PBXGroup section */
Expand Down Expand Up @@ -737,6 +751,7 @@
4166EE7028F5D4C900CE305A /* Commands.swift in Sources */,
419256312D1DF2B600D9EF10 /* SettingsView+GeneralSettings.swift in Sources */,
4166EE7D28F73B2300CE305A /* BrewAnalytics.swift in Sources */,
419256A82D25D10F00D9EF10 /* ExportFile.swift in Sources */,
4104D7432A8FC52C00F84F9B /* Preferences.swift in Sources */,
419256682D1E18D100D9EF10 /* AlertManagerViewModifier.swift in Sources */,
414074F728DF53E80073EB22 /* ContentView.swift in Sources */,
Expand Down Expand Up @@ -766,7 +781,6 @@
4192561E2D1DEBE700D9EF10 /* AppView+UninstallButton.swift in Sources */,
4192569B2D24335900D9EF10 /* CaskTaskError.swift in Sources */,
41524B99295E352200D0046A /* SettingsView.swift in Sources */,
415563A02A9265CE00AE2F2E /* CaskExportType.swift in Sources */,
41524B9E295FA36E00D0046A /* DebounceObject.swift in Sources */,
419256292D1DF1CF00D9EF10 /* SetupView+BrewPathSelection.swift in Sources */,
415563A22A98BB2500AE2F2E /* ErrorWindowView.swift in Sources */,
Expand Down Expand Up @@ -794,6 +808,7 @@
419256832D22055200D9EF10 /* CaskInfo.swift in Sources */,
4192560D2D1CA02C00D9EF10 /* ShellError.swift in Sources */,
4192566B2D1F286B00D9EF10 /* CaskManager+BrewFunctions.swift in Sources */,
419256A42D25CFE600D9EF10 /* AppMigrationView+ExportView.swift in Sources */,
4192561A2D1DEB2100D9EF10 /* AppView+OpenAndManageView.swift in Sources */,
4192562C2D1DF20600D9EF10 /* SetupView+BrewInstall.swift in Sources */,
41062C952A3794EA00FD48EA /* BrewPaths.swift in Sources */,
Expand Down Expand Up @@ -821,6 +836,7 @@
4192563E2D1DF3E900D9EF10 /* ContentView+DetailView.swift in Sources */,
419256162D1DEA0A00D9EF10 /* AppView+IconAndDescriptionView.swift in Sources */,
419256942D24255000D9EF10 /* CaskLoadError.swift in Sources */,
419256A62D25D00200D9EF10 /* AppMigrationView+ImportView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,14 @@ extension CaskManager {
}
}

/// Update all outdated casks
/// Installs multiple
func installAll(_ casks: [Cask]) {
for cask in casks {
self.install(cask)
}
}

/// Updates multiple casks
func updateAll(_ casks: [Cask]) {
for cask in casks {
self.update(cask)
Expand Down
2 changes: 1 addition & 1 deletion Applite/Model/Cask Models/Cask/Cask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import SwiftUI
import os
import OSLog

/// A view model that holds all essential data of a Homebrew cask and provides methods to run brew commands on it (e.g. install, uninstall, update)
@MainActor
Expand Down
8 changes: 3 additions & 5 deletions Applite/Utilities/Alert Manager/AlertManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,14 @@ final class AlertManager: ObservableObject {

/// Shows an alert based on an error
func show(
error: LocalizedError,
overrideTitle: String? = nil,
error: Error,
title: String,
primaryButtonTitle: String = "OK",
primaryAction: (() -> Void)? = nil
) {
let title = overrideTitle ?? error.errorDescription ?? error.localizedDescription

show(
title: title,
message: error.failureReason ?? "",
message: error.localizedDescription,
primaryButtonTitle: primaryButtonTitle,
primaryAction: primaryAction
)
Expand Down
52 changes: 52 additions & 0 deletions Applite/Utilities/App Migration/ExportCasks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// ExportCasks.swift
// Applite
//
// Created by Milán Várady on 2023. 08. 11..
//

import Foundation
import OSLog

enum CaskImportError: Error {
case EmptyFile
}

enum AppMigration {
static func export() async throws -> ExportFile {
let output = try await Shell.runBrewCommand("list")

let exportedCasks = output.trimmingCharacters(in: .whitespacesAndNewlines)

return ExportFile(initialText: exportedCasks)
}

static func readCaskFile(url: URL) throws -> [CaskId] {
let content = try String(contentsOf: url)
var casks: [CaskId] = []
let brewfileRegex = /cask "([\w-]+)"/

// Check if the file being imported is a Brewfile
// Brewfiles store casks as cask "caskName"
if content.contains("cask \"") {
// Brewfile
let matches = content.matches(of: brewfileRegex)
casks = matches.map({ String($0.1) })
} else {
// Try to load casks as an Applite txt file export
casks = content.components(separatedBy: .newlines)

// Trim whitespace
casks = casks.map({ $0.trimmingCharacters(in: .whitespaces) })
}

// Remove empty elements
casks = casks.filter({ !$0.isEmpty })

if casks.isEmpty {
throw CaskImportError.EmptyFile
}

return casks
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import Foundation
import os
import OSLog

/// Installs app dependecies: Homebrew and Xcode Command Line Tools
///
Expand Down
15 changes: 0 additions & 15 deletions Applite/Utilities/Import Export/CaskExportType.swift

This file was deleted.

82 changes: 0 additions & 82 deletions Applite/Utilities/Import Export/ExportCasks.swift

This file was deleted.

2 changes: 1 addition & 1 deletion Applite/Utilities/Shell/Shell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ enum Shell {
///
/// Using the `pty` option can leave unwanted characters in the output, use only when necessary
@discardableResult
static func runBrewCommand(_ brewCommand: String, arguments: [String], pty: Bool = false) async throws -> String {
static func runBrewCommand(_ brewCommand: String, arguments: [String] = [], pty: Bool = false) async throws -> String {
let command = "\(BrewPaths.currentBrewExecutable) \(brewCommand) --cask \(arguments.joined(separator: " "))"
return try await runAsync(command)
}
Expand Down
2 changes: 1 addition & 1 deletion Applite/Views/Content View/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//

import SwiftUI
import os
import OSLog

struct ContentView: View {
@EnvironmentObject var caskManager: CaskManager
Expand Down
Loading

0 comments on commit 0ac1bc7

Please sign in to comment.