diff --git a/README.md b/README.md
index bf744f8..300920c 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,7 @@
- Search recipes content to find processors usage
- Open autopkg cache folder
- Create your own buttons
+ - Check and verify recipes files
System requirements: 10.14 or later
diff --git a/RecipeBuilder.xcodeproj/project.pbxproj b/RecipeBuilder.xcodeproj/project.pbxproj
index df2e25a..71fd2b6 100644
--- a/RecipeBuilder.xcodeproj/project.pbxproj
+++ b/RecipeBuilder.xcodeproj/project.pbxproj
@@ -12,8 +12,11 @@
7300825F245308B600F4909F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7300825D245308B600F4909F /* MainMenu.xib */; };
73008268245309F200F4909F /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73008267245309F200F4909F /* Buttons.swift */; };
734EF16724B2582200C203C9 /* UserButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734EF16624B2582200C203C9 /* UserButtons.swift */; };
+ 7352335927CBF82C004FAA8C /* Buttons3rdParty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7352335827CBF82C004FAA8C /* Buttons3rdParty.swift */; };
+ 7352335B27D2981C004FAA8C /* JamfUploaderHelpTexts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7352335A27D2981C004FAA8C /* JamfUploaderHelpTexts.swift */; };
73631C1024587182008A6491 /* Highlightr in Frameworks */ = {isa = PBXBuildFile; productRef = 73631C0F24587182008A6491 /* Highlightr */; };
73A9CE74247A5D2600627DA8 /* Functions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A9CE73247A5D2600627DA8 /* Functions.swift */; };
+ 73B2E40D27D51F9800CFEA88 /* CheckAndVerify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73B2E40C27D51F9800CFEA88 /* CheckAndVerify.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -25,7 +28,10 @@
73008261245308B600F4909F /* RecipeBuilder.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RecipeBuilder.entitlements; sourceTree = ""; };
73008267245309F200F4909F /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = ""; };
734EF16624B2582200C203C9 /* UserButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserButtons.swift; sourceTree = ""; };
+ 7352335827CBF82C004FAA8C /* Buttons3rdParty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons3rdParty.swift; sourceTree = ""; };
+ 7352335A27D2981C004FAA8C /* JamfUploaderHelpTexts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JamfUploaderHelpTexts.swift; sourceTree = ""; };
73A9CE73247A5D2600627DA8 /* Functions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; };
+ 73B2E40C27D51F9800CFEA88 /* CheckAndVerify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckAndVerify.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -60,9 +66,12 @@
isa = PBXGroup;
children = (
73008259245308B100F4909F /* AppDelegate.swift */,
+ 7352335A27D2981C004FAA8C /* JamfUploaderHelpTexts.swift */,
734EF16624B2582200C203C9 /* UserButtons.swift */,
73008267245309F200F4909F /* Buttons.swift */,
+ 7352335827CBF82C004FAA8C /* Buttons3rdParty.swift */,
73A9CE73247A5D2600627DA8 /* Functions.swift */,
+ 73B2E40C27D51F9800CFEA88 /* CheckAndVerify.swift */,
7300825B245308B600F4909F /* Assets.xcassets */,
7300825D245308B600F4909F /* MainMenu.xib */,
73008260245308B600F4909F /* Info.plist */,
@@ -101,7 +110,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1130;
- LastUpgradeCheck = 1130;
+ LastUpgradeCheck = 1320;
ORGANIZATIONNAME = "Mikael Löfgren";
TargetAttributes = {
73008255245308B100F4909F = {
@@ -149,6 +158,9 @@
files = (
7300825A245308B100F4909F /* AppDelegate.swift in Sources */,
73008268245309F200F4909F /* Buttons.swift in Sources */,
+ 73B2E40D27D51F9800CFEA88 /* CheckAndVerify.swift in Sources */,
+ 7352335927CBF82C004FAA8C /* Buttons3rdParty.swift in Sources */,
+ 7352335B27D2981C004FAA8C /* JamfUploaderHelpTexts.swift in Sources */,
734EF16724B2582200C203C9 /* UserButtons.swift in Sources */,
73A9CE74247A5D2600627DA8 /* Functions.swift in Sources */,
);
@@ -194,6 +206,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -255,6 +268,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -291,14 +305,15 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- DEVELOPMENT_TEAM = 543LXU387V;
+ DEVELOPMENT_TEAM = F489D96499;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/RecipeBuilder/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = se.dicom.RecipeBuilder;
+ MARKETING_VERSION = 1.04;
+ PRODUCT_BUNDLE_IDENTIFIER = se.mikaellofgren.RecipeBuilder;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
@@ -310,17 +325,18 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = RecipeBuilder/RecipeBuilder.entitlements;
- CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
- DEVELOPMENT_TEAM = 543LXU387V;
+ DEVELOPMENT_TEAM = F489D96499;
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = "$(SRCROOT)/RecipeBuilder/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = se.dicom.RecipeBuilder;
+ MARKETING_VERSION = 1.04;
+ PRODUCT_BUNDLE_IDENTIFIER = se.mikaellofgren.RecipeBuilder;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
diff --git a/RecipeBuilder.xcodeproj/project.xcworkspace/xcuserdata/mikael.xcuserdatad/UserInterfaceState.xcuserstate b/RecipeBuilder.xcodeproj/project.xcworkspace/xcuserdata/mikael.xcuserdatad/UserInterfaceState.xcuserstate
index 5eebecd..7ef85e2 100644
Binary files a/RecipeBuilder.xcodeproj/project.xcworkspace/xcuserdata/mikael.xcuserdatad/UserInterfaceState.xcuserstate and b/RecipeBuilder.xcodeproj/project.xcworkspace/xcuserdata/mikael.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/RecipeBuilder.xcodeproj/xcshareddata/xcschemes/RecipeBuilder.xcscheme b/RecipeBuilder.xcodeproj/xcshareddata/xcschemes/RecipeBuilder.xcscheme
index cb92c23..eb74559 100644
--- a/RecipeBuilder.xcodeproj/xcshareddata/xcschemes/RecipeBuilder.xcscheme
+++ b/RecipeBuilder.xcodeproj/xcshareddata/xcschemes/RecipeBuilder.xcscheme
@@ -1,6 +1,6 @@
-
+
-
+
@@ -15,63 +15,30 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
@@ -753,23 +720,23 @@
-
+
-
+
-
+
-
+
-
+
@@ -781,7 +748,7 @@
-
+
@@ -797,9 +764,9 @@
-
+
-
+
@@ -813,7 +780,7 @@
-
+
@@ -822,9 +789,9 @@
-
+
-
+
@@ -833,9 +800,9 @@
-
+
-
+
@@ -847,10 +814,10 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -923,11 +900,11 @@
-
-
+
+
-
+
-
+
+
+
+
@@ -954,535 +935,46 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -1491,7 +983,7 @@ For xar it also optionally skips extracting the payload.
-
+
@@ -1532,7 +1024,7 @@ For xar it also optionally skips extracting the payload.
-
+
@@ -1561,7 +1053,7 @@ For xar it also optionally skips extracting the payload.
-
+
@@ -1581,5 +1073,27 @@ For xar it also optionally skips extracting the payload.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RecipeBuilder/Buttons.swift b/RecipeBuilder/Buttons.swift
index 5047c41..e03ddd1 100644
--- a/RecipeBuilder/Buttons.swift
+++ b/RecipeBuilder/Buttons.swift
@@ -17,6 +17,62 @@ func appDelegate() -> AppDelegate {
return NSApplication.shared.delegate as! AppDelegate
}
+// Function calling every button function to create defaults buttons
+func createAllDefaultButtons () {
+ createButtonAppDMGVersioner ()
+ createButtonAppPkgCreator ()
+ createButtonCodeSignatureVerifierApp ()
+ createButtonCodeSignatureVerifierPKG ()
+ createButtonCopier ()
+ createButtonDeprecationWarning ()
+ createButtonDmgCreator ()
+ createButtonEndOfCheckPhase ()
+ createButtonFileCreator ()
+ createButtonFileFinder ()
+ createButtonFileMover ()
+ createButtonFlatPkgPacker ()
+ createButtonFlatPkgUnpacker ()
+ createButtonGitHubReleasesInfoProvider ()
+ createButtonInstaller ()
+ createButtonInstallFromDMG ()
+ createButtonMunkiCatalogBuilder ()
+ createButtonMunkiImporter ()
+ createButtonMunkiInfoCreator ()
+ createButtonMunkiInstallsItemsCreator ()
+ createButtonMunkiPkginfoMerger ()
+ createButtonPackageRequired ()
+ createButtonpathDeleter ()
+ createButtonPkgCopier ()
+ createButtonPkgCreator ()
+ createButtonPkgExtractor ()
+ createButtonPkgInfoCreator ()
+ createButtonPkgPayloadUnpacker ()
+ createButtonPkgRootCreator ()
+ createButtonPlistEditor ()
+ createButtonPlistReader ()
+ createButtonSparkleUpdateInfoProvider ()
+ createButtonStopProcessingIf ()
+ createButtonSymlinker ()
+ createButtonUnarchiver ()
+ createButtonUrlDownloader ()
+ createButtonUrlTextSearcher ()
+ createButtonVersioner ()
+}
+
+// 21 pixels between every button
+func createButtonAppDMGVersioner () {
+let appDMGVersioner = NSButton(frame: NSRect(x: 17, y: 855, width: 191, height: 17))
+ appDMGVersioner.title = "AppDmgVersioner"
+ appDMGVersioner.bezelStyle = NSButton.BezelStyle.inline
+ appDMGVersioner.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ appDMGVersioner.isBordered = true
+ appDMGVersioner.font = .boldSystemFont(ofSize: 11)
+ appDMGVersioner.toolTip = "Extracts bundle ID and version of app inside a dmg"
+ appDMGVersioner.action = #selector(appDelegate().appDMGVersionerAction)
+appDelegate().processorsView.addSubview(appDMGVersioner)
+}
+
+
func appDMGVersioner () {
output = """
@@ -33,6 +89,19 @@ func appDMGVersioner () {
}
+func createButtonAppPkgCreator () {
+let appPkgCreator = NSButton(frame: NSRect(x: 17, y: 834, width: 191, height: 17))
+ appPkgCreator.title = "AppPkgCreator"
+ appPkgCreator.bezelStyle = NSButton.BezelStyle.inline
+ appPkgCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ appPkgCreator.isBordered = true
+ appPkgCreator.font = .boldSystemFont(ofSize: 11)
+ appPkgCreator.toolTip = "Calls autopkgserver to create a package from an application"
+ appPkgCreator.action = #selector(appDelegate().appPkgCreatorAction)
+appDelegate().processorsView.addSubview(appPkgCreator)
+}
+
+
func appPkgCreator () {
output = """
@@ -51,6 +120,17 @@ func appPkgCreator () {
writeOutput ()
}
+func createButtonCodeSignatureVerifierApp () {
+let codeSignatureVerifierApp = NSButton(frame: NSRect(x: 17, y: 813, width: 191, height: 17))
+ codeSignatureVerifierApp.title = "CodeSignatureVerifier App "
+ codeSignatureVerifierApp.bezelStyle = NSButton.BezelStyle.inline
+ codeSignatureVerifierApp.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ codeSignatureVerifierApp.isBordered = true
+ codeSignatureVerifierApp.font = .boldSystemFont(ofSize: 11)
+ codeSignatureVerifierApp.toolTip = "Verifies application bundle signature"
+ codeSignatureVerifierApp.action = #selector(appDelegate().codeSignatureVerifierAppAction)
+appDelegate().processorsView.addSubview(codeSignatureVerifierApp)
+}
func codeSignatureVerifierApp () {
@@ -114,6 +194,17 @@ if (dialog.runModal() == NSApplication.ModalResponse.OK) {
writeOutput ()
}
+func createButtonCodeSignatureVerifierPKG () {
+let codeSignatureVerifierPKG = NSButton(frame: NSRect(x: 17, y: 792, width: 191, height: 17))
+ codeSignatureVerifierPKG.title = "CodeSignatureVerifier PKG"
+ codeSignatureVerifierPKG.bezelStyle = NSButton.BezelStyle.inline
+ codeSignatureVerifierPKG.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ codeSignatureVerifierPKG.isBordered = true
+ codeSignatureVerifierPKG.font = .boldSystemFont(ofSize: 11)
+ codeSignatureVerifierPKG.toolTip = "Verifies installer package signature"
+ codeSignatureVerifierPKG.action = #selector(appDelegate().codeSignatureVerifierPkgAction)
+appDelegate().processorsView.addSubview(codeSignatureVerifierPKG)
+}
func codeSignatureVerifierPKG () {
@@ -148,11 +239,17 @@ func codeSignatureVerifierPKG () {
}
var codeSignPkg = shell("pkgutil --check-signature '\(path)'")
- let codeSignPkgArrayTemp = codeSignPkg.components(separatedBy: CharacterSet.newlines)
- if codeSignPkgArrayTemp.isEmpty {
+ var codeSignPkgArrayTemp = codeSignPkg.components(separatedBy: CharacterSet.newlines)
+ codeSignPkgArrayTemp = codeSignPkgArrayTemp.map { $0.trimmingCharacters(in: .whitespaces) }
+ // Get only matching line 1.
+ codeSignPkgArrayTemp = codeSignPkgArrayTemp.filter({ $0.hasPrefix("1. ") })
+
+
+ if codeSignPkgArrayTemp.isEmpty {
} else {
- codeSignPkg = codeSignPkgArrayTemp[3].replacingOccurrences(of: "1. ", with: "", options: [.regularExpression, .caseInsensitive])
- codeSignPkg = codeSignPkg.trimmingCharacters(in: .whitespacesAndNewlines)
+ codeSignPkg = codeSignPkgArrayTemp.joined(separator: "")
+ codeSignPkg = codeSignPkg.replacingOccurrences(of: "1. ", with: "", options: [.regularExpression, .caseInsensitive])
+ //codeSignPkg = codeSignPkg.trimmingCharacters(in: .whitespacesAndNewlines)
}
@@ -177,6 +274,18 @@ func codeSignatureVerifierPKG () {
writeOutput ()
}
+func createButtonCopier () {
+let copier = NSButton(frame: NSRect(x: 17, y: 771, width: 191, height: 17))
+ copier.title = "Copier"
+ copier.bezelStyle = NSButton.BezelStyle.inline
+ copier.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ copier.isBordered = true
+ copier.font = .boldSystemFont(ofSize: 11)
+ copier.toolTip = "Copies source_path to destination_path"
+ copier.action = #selector(appDelegate().copierAction)
+appDelegate().processorsView.addSubview(copier)
+}
+
func copier () {
output = """
@@ -195,7 +304,19 @@ func copier () {
writeOutput ()
}
-
+
+func createButtonDeprecationWarning () {
+let deprecationWarning = NSButton(frame: NSRect(x: 17, y: 750, width: 191, height: 17))
+ deprecationWarning.title = "DeprecationWarning"
+ deprecationWarning.bezelStyle = NSButton.BezelStyle.inline
+ deprecationWarning.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ deprecationWarning.isBordered = true
+ deprecationWarning.font = .boldSystemFont(ofSize: 11)
+ deprecationWarning.toolTip = "This processor outputs a warning that the recipe has been deprecated"
+ deprecationWarning.action = #selector(appDelegate().deprecationWarningAction)
+appDelegate().processorsView.addSubview(deprecationWarning)
+}
+
func deprecationWarning () {
output = """
@@ -211,7 +332,19 @@ func deprecationWarning () {
writeOutput ()
}
-
+
+func createButtonDmgCreator () {
+let dmgCreator = NSButton(frame: NSRect(x: 17, y: 729, width: 191, height: 17))
+ dmgCreator.title = "DmgCreator"
+ dmgCreator.bezelStyle = NSButton.BezelStyle.inline
+ dmgCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ dmgCreator.isBordered = true
+ dmgCreator.font = .boldSystemFont(ofSize: 11)
+ dmgCreator.toolTip = "Creates a disk image from a directory"
+ dmgCreator.action = #selector(appDelegate().dmgCreatorAction)
+appDelegate().processorsView.addSubview(dmgCreator)
+}
+
func dmgCreator () {
output = """
@@ -229,10 +362,25 @@ func dmgCreator () {
writeOutput ()
}
-
+
+
func dmgMounter () {
}
-
+
+
+func createButtonEndOfCheckPhase () {
+let endOfCheckPhase = NSButton(frame: NSRect(x: 17, y: 708, width: 191, height: 17))
+ endOfCheckPhase.title = "EndOfCheckPhase"
+ endOfCheckPhase.bezelStyle = NSButton.BezelStyle.inline
+ endOfCheckPhase.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ endOfCheckPhase.isBordered = true
+ endOfCheckPhase.font = .boldSystemFont(ofSize: 11)
+ endOfCheckPhase.toolTip = "This processor does nothing at all"
+ endOfCheckPhase.action = #selector(appDelegate().endOfCheckPhaseAction)
+appDelegate().processorsView.addSubview(endOfCheckPhase)
+}
+
+
func endOfCheckPhase () {
output = """
@@ -244,6 +392,20 @@ func endOfCheckPhase () {
writeOutput ()
}
+
+func createButtonFileCreator () {
+let fileCreator = NSButton(frame: NSRect(x: 17, y: 687, width: 191, height: 17))
+ fileCreator.title = "FileCreator"
+ fileCreator.bezelStyle = NSButton.BezelStyle.inline
+ fileCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ fileCreator.isBordered = true
+ fileCreator.font = .boldSystemFont(ofSize: 11)
+ fileCreator.toolTip = "Create a file"
+ fileCreator.action = #selector(appDelegate().fileCreatorAction)
+appDelegate().processorsView.addSubview(fileCreator)
+}
+
+
func fileCreator () {
output = """
@@ -265,6 +427,19 @@ func fileCreator () {
}
+func createButtonFileFinder () {
+let fileFinder = NSButton(frame: NSRect(x: 17, y: 666, width: 191, height: 17))
+ fileFinder.title = "FileFinder"
+ fileFinder.bezelStyle = NSButton.BezelStyle.inline
+ fileFinder.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ fileFinder.isBordered = true
+ fileFinder.font = .boldSystemFont(ofSize: 11)
+ fileFinder.toolTip = "Finds a filename for use in other Processors"
+ fileFinder.action = #selector(appDelegate().fileFinderAction)
+appDelegate().processorsView.addSubview(fileFinder)
+}
+
+
func fileFinder () {
output = """
@@ -282,6 +457,19 @@ func fileFinder () {
}
+func createButtonFileMover () {
+let fileMover = NSButton(frame: NSRect(x: 17, y: 645, width: 191, height: 17))
+ fileMover.title = "FileMover"
+ fileMover.bezelStyle = NSButton.BezelStyle.inline
+ fileMover.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ fileMover.isBordered = true
+ fileMover.font = .boldSystemFont(ofSize: 11)
+ fileMover.toolTip = "Moves/renames a file"
+ fileMover.action = #selector(appDelegate().fileMoverAction)
+appDelegate().processorsView.addSubview(fileMover)
+}
+
+
func fileMover () {
output = """
@@ -302,6 +490,20 @@ func fileMover () {
writeOutput ()
}
+
+func createButtonFlatPkgPacker () {
+let flatPkgPacker = NSButton(frame: NSRect(x: 17, y: 624, width: 191, height: 17))
+ flatPkgPacker.title = "FlatPkgPacker"
+ flatPkgPacker.bezelStyle = NSButton.BezelStyle.inline
+ flatPkgPacker.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ flatPkgPacker.isBordered = true
+ flatPkgPacker.font = .boldSystemFont(ofSize: 11)
+ flatPkgPacker.toolTip = "Flatten an expanded package using pkgutil"
+ flatPkgPacker.action = #selector(appDelegate().flatPkgPackerAction)
+appDelegate().processorsView.addSubview(flatPkgPacker)
+}
+
+
func flatPkgPacker () {
output = """
@@ -321,6 +523,19 @@ func flatPkgPacker () {
}
+func createButtonFlatPkgUnpacker () {
+let flatPkgUnpacker = NSButton(frame: NSRect(x: 17, y: 603, width: 191, height: 17))
+ flatPkgUnpacker.title = "FlatPkgPacker"
+ flatPkgUnpacker.bezelStyle = NSButton.BezelStyle.inline
+ flatPkgUnpacker.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ flatPkgUnpacker.isBordered = true
+ flatPkgUnpacker.font = .boldSystemFont(ofSize: 11)
+ flatPkgUnpacker.toolTip = "Expands a flat package using pkgutil or xar. For xar it also optionally skips extracting the payload"
+ flatPkgUnpacker.action = #selector(appDelegate().flatPkgUnpackerAction)
+appDelegate().processorsView.addSubview(flatPkgUnpacker)
+}
+
+
func flatPkgUnpacker () {
output = """
@@ -342,6 +557,19 @@ func flatPkgUnpacker () {
}
+func createButtonGitHubReleasesInfoProvider () {
+let gitHubReleasesInfoProvider = NSButton(frame: NSRect(x: 17, y: 582, width: 191, height: 17))
+ gitHubReleasesInfoProvider.title = "GitHubReleasesInfoProvider"
+ gitHubReleasesInfoProvider.bezelStyle = NSButton.BezelStyle.inline
+ gitHubReleasesInfoProvider.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ gitHubReleasesInfoProvider.isBordered = true
+ gitHubReleasesInfoProvider.font = .boldSystemFont(ofSize: 11)
+ gitHubReleasesInfoProvider.toolTip = "Get metadata from the latest release from a GitHub project using the GitHub Releases API. Requires version 0.5.0"
+ gitHubReleasesInfoProvider.action = #selector(appDelegate().gitHubReleasesInfoProviderAction)
+appDelegate().processorsView.addSubview(gitHubReleasesInfoProvider)
+}
+
+
func gitHubReleasesInfoProvider () {
output = """
@@ -358,22 +586,18 @@ func gitHubReleasesInfoProvider () {
writeOutput ()
}
+func createButtonInstallFromDMG () {
+let installFromDMG = NSButton(frame: NSRect(x: 17, y: 561, width: 191, height: 17))
+ installFromDMG.title = "InstallFromDMG"
+ installFromDMG.bezelStyle = NSButton.BezelStyle.inline
+ installFromDMG.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ installFromDMG.isBordered = true
+ installFromDMG.font = .boldSystemFont(ofSize: 11)
+ installFromDMG.toolTip = "Calls autopkginstalld to copy items from a disk image to the root filesystem"
+ installFromDMG.action = #selector(appDelegate().installFromDMGAction)
+appDelegate().processorsView.addSubview(installFromDMG)
+}
-func installer () {
- output = """
-
- Arguments
-
- pkg_path
- %RECIPE_CACHE_DIR%/%NAME%.pkg
-
- Processor
- Installer
-
- """
-
- writeOutput ()
- }
func installFromDMG () {
output = """
@@ -400,6 +624,80 @@ func installFromDMG () {
writeOutput ()
}
+
+func createButtonInstaller () {
+let installer = NSButton(frame: NSRect(x: 17, y: 540, width: 191, height: 17))
+ installer.title = "Installer"
+ installer.bezelStyle = NSButton.BezelStyle.inline
+ installer.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ installer.isBordered = true
+ installer.font = .boldSystemFont(ofSize: 11)
+ installer.toolTip = "Calls autopkginstalld to install a package"
+ installer.action = #selector(appDelegate().installerAction)
+appDelegate().processorsView.addSubview(installer)
+}
+
+
+func installer () {
+ output = """
+
+ Arguments
+
+ pkg_path
+ %RECIPE_CACHE_DIR%/%NAME%.pkg
+
+ Processor
+ Installer
+
+ """
+
+ writeOutput ()
+ }
+
+
+func createButtonMunkiCatalogBuilder () {
+let munkiCatalogBuilder = NSButton(frame: NSRect(x: 17, y: 519, width: 191, height: 17))
+ munkiCatalogBuilder.title = "MunkiCatalogBuilder"
+ munkiCatalogBuilder.bezelStyle = NSButton.BezelStyle.inline
+ munkiCatalogBuilder.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ munkiCatalogBuilder.isBordered = true
+ munkiCatalogBuilder.font = .boldSystemFont(ofSize: 11)
+ munkiCatalogBuilder.toolTip = "Rebuilds Munki catalogs"
+ munkiCatalogBuilder.action = #selector(appDelegate().munkiCatalogBuilderAction)
+appDelegate().processorsView.addSubview(munkiCatalogBuilder)
+}
+
+
+func munkiCatalogBuilder () {
+ output = """
+
+ Arguments
+
+ MUNKI_REPO
+ /path/to/munki/repo
+
+ Processor
+ MunkiCatalogBuilder
+
+ """
+
+ writeOutput ()
+}
+
+
+func createButtonMunkiImporter () {
+let munkiImporter = NSButton(frame: NSRect(x: 17, y: 498, width: 191, height: 17))
+ munkiImporter.title = "MunkiImporter"
+ munkiImporter.bezelStyle = NSButton.BezelStyle.inline
+ munkiImporter.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ munkiImporter.isBordered = true
+ munkiImporter.font = .boldSystemFont(ofSize: 11)
+ munkiImporter.toolTip = "Imports a pkg or dmg to the Munki repo"
+ munkiImporter.action = #selector(appDelegate().munkiImporterAction)
+appDelegate().processorsView.addSubview(munkiImporter)
+}
+
+
func munkiImporter () {
output = """
@@ -418,6 +716,20 @@ func munkiImporter () {
writeOutput ()
}
+
+func createButtonMunkiInfoCreator () {
+let munkiInfoCreator = NSButton(frame: NSRect(x: 17, y: 477, width: 191, height: 17))
+ munkiInfoCreator.title = "MunkiInfoCreator"
+ munkiInfoCreator.bezelStyle = NSButton.BezelStyle.inline
+ munkiInfoCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ munkiInfoCreator.isBordered = true
+ munkiInfoCreator.font = .boldSystemFont(ofSize: 11)
+ munkiInfoCreator.toolTip = "Creates a pkginfo file for a munki package"
+ munkiInfoCreator.action = #selector(appDelegate().munkiInfoCreatorAction)
+appDelegate().processorsView.addSubview(munkiInfoCreator)
+}
+
+
func munkiInfoCreator () {
output = """
@@ -435,6 +747,19 @@ func munkiInfoCreator () {
}
+func createButtonMunkiInstallsItemsCreator () {
+let munkiInstallsItemsCreator = NSButton(frame: NSRect(x: 17, y: 456, width: 191, height: 17))
+ munkiInstallsItemsCreator.title = "MunkiInstallsItemsCreator"
+ munkiInstallsItemsCreator.bezelStyle = NSButton.BezelStyle.inline
+ munkiInstallsItemsCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ munkiInstallsItemsCreator.isBordered = true
+ munkiInstallsItemsCreator.font = .boldSystemFont(ofSize: 11)
+ munkiInstallsItemsCreator.toolTip = "Generates an installs array for a pkginfo file"
+ munkiInstallsItemsCreator.action = #selector(appDelegate().MunkiInstallsItemsCreatorAction)
+appDelegate().processorsView.addSubview(munkiInstallsItemsCreator)
+}
+
+
func munkiInstallsItemsCreator () {
output = """
@@ -456,6 +781,19 @@ func munkiInstallsItemsCreator () {
}
+func createButtonMunkiPkginfoMerger () {
+let munkiPkginfoMerger = NSButton(frame: NSRect(x: 17, y: 435, width: 191, height: 17))
+ munkiPkginfoMerger.title = "MunkiPkginfoMerger"
+ munkiPkginfoMerger.bezelStyle = NSButton.BezelStyle.inline
+ munkiPkginfoMerger.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ munkiPkginfoMerger.isBordered = true
+ munkiPkginfoMerger.font = .boldSystemFont(ofSize: 11)
+ munkiPkginfoMerger.toolTip = "Merges two pkginfo dictionaries"
+ munkiPkginfoMerger.action = #selector(appDelegate().munkiPkginfoMergerAction)
+appDelegate().processorsView.addSubview(munkiPkginfoMerger)
+}
+
+
func munkiPkginfoMerger () {
output = """
@@ -476,6 +814,19 @@ func munkiPkginfoMerger () {
}
+func createButtonPackageRequired () {
+let packageRequired = NSButton(frame: NSRect(x: 17, y: 414, width: 191, height: 17))
+ packageRequired.title = "PackageRequired"
+ packageRequired.bezelStyle = NSButton.BezelStyle.inline
+ packageRequired.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ packageRequired.isBordered = true
+ packageRequired.font = .boldSystemFont(ofSize: 11)
+ packageRequired.toolTip = "Raises a ProcessorError if the PKG variable doesn't exist"
+ packageRequired.action = #selector(appDelegate().packageRequiredAction)
+appDelegate().processorsView.addSubview(packageRequired)
+}
+
+
func packageRequired () {
output = """
@@ -488,6 +839,19 @@ func packageRequired () {
}
+func createButtonpathDeleter () {
+let pathDeleter = NSButton(frame: NSRect(x: 17, y: 393, width: 191, height: 17))
+ pathDeleter.title = "PathDeleter"
+ pathDeleter.bezelStyle = NSButton.BezelStyle.inline
+ pathDeleter.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pathDeleter.isBordered = true
+ pathDeleter.font = .boldSystemFont(ofSize: 11)
+ pathDeleter.toolTip = "Deletes file paths"
+ pathDeleter.action = #selector(appDelegate().pathDeleterAction)
+appDelegate().processorsView.addSubview(pathDeleter)
+}
+
+
func pathDeleter () {
output = """
@@ -507,6 +871,19 @@ func pathDeleter () {
}
+func createButtonPkgCopier () {
+let pkgCopier = NSButton(frame: NSRect(x: 17, y: 372, width: 191, height: 17))
+ pkgCopier.title = "PkgCopier"
+ pkgCopier.bezelStyle = NSButton.BezelStyle.inline
+ pkgCopier.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgCopier.isBordered = true
+ pkgCopier.font = .boldSystemFont(ofSize: 11)
+ pkgCopier.toolTip = "Copies source_pkg to pkg_path"
+ pkgCopier.action = #selector(appDelegate().pkgCopierAction)
+appDelegate().processorsView.addSubview(pkgCopier)
+}
+
+
func pkgCopier () {
output = """
@@ -526,6 +903,69 @@ func pkgCopier () {
}
+func createButtonPkgCreator () {
+let pkgCreator = NSButton(frame: NSRect(x: 17, y: 351, width: 191, height: 17))
+ pkgCreator.title = "PkgCreator"
+ pkgCreator.bezelStyle = NSButton.BezelStyle.inline
+ pkgCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgCreator.isBordered = true
+ pkgCreator.font = .boldSystemFont(ofSize: 11)
+ pkgCreator.toolTip = "Calls autopkgserver to create a package"
+ pkgCreator.action = #selector(appDelegate().pkgCreatorAction)
+appDelegate().processorsView.addSubview(pkgCreator)
+}
+
+
+func pkgCreator () {
+ output = """
+
+ Arguments
+
+ pkg_request
+
+ pkgname
+ %NAME%-%version%
+ pkgdir
+ %RECIPE_CACHE_DIR%/%NAME%
+ id
+ com.yourdomain.%NAME%
+ options
+ purge_ds_store
+ chown
+
+
+ path
+ Applications
+ user
+ root
+ group
+ admin
+
+
+
+
+ Processor
+ PkgCreator
+
+ """
+
+ writeOutput ()
+ }
+
+
+func createButtonPkgExtractor () {
+let pkgExtractor = NSButton(frame: NSRect(x: 17, y: 330, width: 191, height: 17))
+ pkgExtractor.title = "PkgExtractor"
+ pkgExtractor.bezelStyle = NSButton.BezelStyle.inline
+ pkgExtractor.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgExtractor.isBordered = true
+ pkgExtractor.font = .boldSystemFont(ofSize: 11)
+ pkgExtractor.toolTip = "Extracts the contents of a bundle-style pkg (possibly on a disk image) to pkgroot"
+ pkgExtractor.action = #selector(appDelegate().pkgExtractorAction)
+appDelegate().processorsView.addSubview(pkgExtractor)
+}
+
+
func pkgExtractor () {
output = """
@@ -545,6 +985,19 @@ func pkgExtractor () {
}
+func createButtonPkgInfoCreator () {
+let pkgInfoCreator = NSButton(frame: NSRect(x: 17, y: 309, width: 191, height: 17))
+ pkgInfoCreator.title = "PkgInfoCreator"
+ pkgInfoCreator.bezelStyle = NSButton.BezelStyle.inline
+ pkgInfoCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgInfoCreator.isBordered = true
+ pkgInfoCreator.font = .boldSystemFont(ofSize: 11)
+ pkgInfoCreator.toolTip = "Creates an PackageInfo file for a package"
+ pkgInfoCreator.action = #selector(appDelegate().pkgInfoCreatorAction)
+appDelegate().processorsView.addSubview(pkgInfoCreator)
+}
+
+
func pkgInfoCreator () {
output = """
@@ -566,6 +1019,19 @@ func pkgInfoCreator () {
}
+func createButtonPkgPayloadUnpacker () {
+let pkgPayloadUnpacker = NSButton(frame: NSRect(x: 17, y: 288, width: 191, height: 17))
+ pkgPayloadUnpacker.title = "PkgPayloadUnpacker"
+ pkgPayloadUnpacker.bezelStyle = NSButton.BezelStyle.inline
+ pkgPayloadUnpacker.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgPayloadUnpacker.isBordered = true
+ pkgPayloadUnpacker.font = .boldSystemFont(ofSize: 11)
+ pkgPayloadUnpacker.toolTip = "Unpacks a package payload"
+ pkgPayloadUnpacker.action = #selector(appDelegate().pkgPayloadUnpackerAction)
+appDelegate().processorsView.addSubview(pkgPayloadUnpacker)
+}
+
+
func pkgPayloadUnpacker () {
output = """
@@ -586,6 +1052,20 @@ func pkgPayloadUnpacker () {
writeOutput ()
}
+
+func createButtonPkgRootCreator () {
+let pkgRootCreator = NSButton(frame: NSRect(x: 17, y: 267, width: 191, height: 17))
+ pkgRootCreator.title = "PkgRootCreator"
+ pkgRootCreator.bezelStyle = NSButton.BezelStyle.inline
+ pkgRootCreator.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ pkgRootCreator.isBordered = true
+ pkgRootCreator.font = .boldSystemFont(ofSize: 11)
+ pkgRootCreator.toolTip = "Creates a package root and a directory structure. (Can also be used to create directory structures for other purposes.)"
+ pkgRootCreator.action = #selector(appDelegate().pkgRootCreatorAction)
+appDelegate().processorsView.addSubview(pkgRootCreator)
+}
+
+
func pkgRootCreator () {
output = """
@@ -597,7 +1077,7 @@ func pkgRootCreator () {
0755
pkgroot
- %RECIPE_CACHE_DIR%/
+ %RECIPE_CACHE_DIR%/%NAME%
Processor
PkgRootCreator
@@ -608,6 +1088,19 @@ func pkgRootCreator () {
}
+func createButtonPlistEditor () {
+let plistEditor = NSButton(frame: NSRect(x: 17, y: 246, width: 191, height: 17))
+ plistEditor.title = "PlistEditor"
+ plistEditor.bezelStyle = NSButton.BezelStyle.inline
+ plistEditor.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ plistEditor.isBordered = true
+ plistEditor.font = .boldSystemFont(ofSize: 11)
+ plistEditor.toolTip = "Merges data with an input plist (which can be empty) and writes a new plist"
+ plistEditor.action = #selector(appDelegate().plistEditorAction)
+appDelegate().processorsView.addSubview(plistEditor)
+}
+
+
func plistEditor () {
output = """
@@ -632,6 +1125,19 @@ func plistEditor () {
}
+func createButtonPlistReader () {
+let plistReader = NSButton(frame: NSRect(x: 17, y: 225, width: 191, height: 17))
+ plistReader.title = "PlistReader"
+ plistReader.bezelStyle = NSButton.BezelStyle.inline
+ plistReader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ plistReader.isBordered = true
+ plistReader.font = .boldSystemFont(ofSize: 11)
+ plistReader.toolTip = "Extracts values from top-level keys in a plist file, and assigns to arbitrary output variables. This behavior is different from other processors that pre-define all their possible output variables. As it is often used for versioning, it defaults to extracting 'CFBundleShortVersionString' to 'version'. This can be used as a replacement for both the AppDmgVersioner and Versioner processors"
+ plistReader.action = #selector(appDelegate().plistReaderAction)
+appDelegate().processorsView.addSubview(plistReader)
+}
+
+
func plistReader () {
output = """
@@ -656,6 +1162,19 @@ func plistReader () {
}
+func createButtonSparkleUpdateInfoProvider () {
+let sparkleUpdateInfoProvider = NSButton(frame: NSRect(x: 17, y: 204, width: 191, height: 17))
+ sparkleUpdateInfoProvider.title = "SparkleUpdateInfoProvider"
+ sparkleUpdateInfoProvider.bezelStyle = NSButton.BezelStyle.inline
+ sparkleUpdateInfoProvider.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ sparkleUpdateInfoProvider.isBordered = true
+ sparkleUpdateInfoProvider.font = .boldSystemFont(ofSize: 11)
+ sparkleUpdateInfoProvider.toolTip = "Provides URL to the highest version number or latest update"
+ sparkleUpdateInfoProvider.action = #selector(appDelegate().sparkleUpdateInfoProviderAction)
+appDelegate().processorsView.addSubview(sparkleUpdateInfoProvider)
+}
+
+
func sparkleUpdateInfoProvider () {
output = """
@@ -673,6 +1192,19 @@ func sparkleUpdateInfoProvider () {
}
+func createButtonStopProcessingIf () {
+let stopProcessingIf = NSButton(frame: NSRect(x: 17, y: 183, width: 191, height: 17))
+ stopProcessingIf.title = "StopProcessingIf"
+ stopProcessingIf.bezelStyle = NSButton.BezelStyle.inline
+ stopProcessingIf.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ stopProcessingIf.isBordered = true
+ stopProcessingIf.font = .boldSystemFont(ofSize: 11)
+ stopProcessingIf.toolTip = "Sets a variable to tell AutoPackager to stop processing a recipe if a predicate comparison evaluates to true"
+ stopProcessingIf.action = #selector(appDelegate().stopProcessingIfAction)
+appDelegate().processorsView.addSubview(stopProcessingIf)
+}
+
+
func stopProcessingIf () {
output = """
@@ -690,6 +1222,19 @@ func stopProcessingIf () {
}
+func createButtonSymlinker () {
+let symlinker = NSButton(frame: NSRect(x: 17, y: 162, width: 191, height: 17))
+ symlinker.title = "Symlinker"
+ symlinker.bezelStyle = NSButton.BezelStyle.inline
+ symlinker.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ symlinker.isBordered = true
+ symlinker.font = .boldSystemFont(ofSize: 11)
+ symlinker.toolTip = "Copies source_path to destination_path"
+ symlinker.action = #selector(appDelegate().symlinkerAction)
+appDelegate().processorsView.addSubview(symlinker)
+}
+
+
func symlinker () {
output = """
@@ -709,6 +1254,19 @@ func symlinker () {
}
+func createButtonUnarchiver () {
+let unarchiver = NSButton(frame: NSRect(x: 17, y: 141, width: 191, height: 17))
+ unarchiver.title = "Unarchiver"
+ unarchiver.bezelStyle = NSButton.BezelStyle.inline
+ unarchiver.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ unarchiver.isBordered = true
+ unarchiver.font = .boldSystemFont(ofSize: 11)
+ unarchiver.toolTip = "Archive decompressor for zip and common tar-compressed formats"
+ unarchiver.action = #selector(appDelegate().unarchiverAction)
+appDelegate().processorsView.addSubview(unarchiver)
+}
+
+
func unarchiver () {
output = """
@@ -730,6 +1288,19 @@ func unarchiver () {
}
+func createButtonUrlDownloader () {
+let urlDownloader = NSButton(frame: NSRect(x: 17, y: 120, width: 191, height: 17))
+ urlDownloader.title = "URLDownloader"
+ urlDownloader.bezelStyle = NSButton.BezelStyle.inline
+ urlDownloader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ urlDownloader.isBordered = true
+ urlDownloader.font = .boldSystemFont(ofSize: 11)
+ urlDownloader.toolTip = "Downloads a URL to the specified download_dir using curl"
+ urlDownloader.action = #selector(appDelegate().urlDownloaderAction)
+appDelegate().processorsView.addSubview(urlDownloader)
+}
+
+
func urlDownloader () {
output = """
@@ -749,6 +1320,19 @@ func urlDownloader () {
}
+func createButtonUrlTextSearcher () {
+let urlTextSearcher = NSButton(frame: NSRect(x: 17, y: 99, width: 191, height: 17))
+ urlTextSearcher.title = "URLTextSearcher"
+ urlTextSearcher.bezelStyle = NSButton.BezelStyle.inline
+ urlTextSearcher.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ urlTextSearcher.isBordered = true
+ urlTextSearcher.font = .boldSystemFont(ofSize: 11)
+ urlTextSearcher.toolTip = "Downloads a URL using curl and performs a regular expression match on the text"
+ urlTextSearcher.action = #selector(appDelegate().urlTextSearcherAction)
+appDelegate().processorsView.addSubview(urlTextSearcher)
+}
+
+
func urlTextSearcher () {
output = """
@@ -770,6 +1354,19 @@ func urlTextSearcher () {
}
+func createButtonVersioner () {
+let versioner = NSButton(frame: NSRect(x: 17, y: 78, width: 191, height: 17))
+ versioner.title = "Versioner"
+ versioner.bezelStyle = NSButton.BezelStyle.inline
+ versioner.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ versioner.isBordered = true
+ versioner.font = .boldSystemFont(ofSize: 11)
+ versioner.toolTip = "Returns version information from a plist"
+ versioner.action = #selector(appDelegate().versionerAction)
+appDelegate().processorsView.addSubview(versioner)
+}
+
+
func versioner () {
output = """
diff --git a/RecipeBuilder/Buttons3rdParty.swift b/RecipeBuilder/Buttons3rdParty.swift
new file mode 100644
index 0000000..498ce20
--- /dev/null
+++ b/RecipeBuilder/Buttons3rdParty.swift
@@ -0,0 +1,476 @@
+//
+// Buttons3rdParty.swift
+// RecipeBuilder
+//
+// Created by Mikael Löfgren on 2022-02-27.
+// Copyright © 2022 Mikael Löfgren. All rights reserved.
+//
+
+import Cocoa
+import AppKit
+import Foundation
+import Highlightr
+
+func createAll3rdPartyButtons () {
+ createButtonJamfCategoryUploader ()
+ createButtonJamfComputerGroupUploader ()
+ createButtonJamfComputerProfileUploader ()
+ createButtonJamfDockItemUploader ()
+ createButtonJamfExtensionAttributeUploader ()
+ createButtonJamfMacAppUploader ()
+ createButtonJamfPackageUploader ()
+ createButtonJamfPatchUploader ()
+ createButtonJamfPolicyDeleter ()
+ createButtonJamfPolicyLogFlusher ()
+ createButtonJamfPolicyUploader ()
+ createButtonJamfScriptUploader ()
+ createButtonJamfSoftwareRestrictionUploader ()
+ createButtonJamfUploaderSlacker ()
+ createButtonJamfUploaderTeamsNotifier ()
+}
+
+// https://github.com/autopkg/grahampugh-recipes/blob/main/JamfUploaderProcessors/READMEs/JamfCategoryUploader.md
+
+func createButtonJamfCategoryUploader () {
+let JamfCategoryUploader = NSButton(frame: NSRect(x: 17, y: 324, width: 191, height: 17))
+ JamfCategoryUploader.title = "JamfCategoryUploader"
+ JamfCategoryUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfCategoryUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfCategoryUploader.isBordered = true
+ JamfCategoryUploader.font = .boldSystemFont(ofSize: 11)
+ JamfCategoryUploader.toolTip = "Upload a category to Jamf"
+ JamfCategoryUploader.action = #selector(appDelegate().JamfCategoryUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfCategoryUploader)
+}
+
+
+func JamfCategoryUploader () {
+ output = """
+
+ Arguments
+
+ category_name
+ %CATEGORY%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfCategoryUploader
+
+"""
+ writeOutput ()
+ }
+
+func createButtonJamfComputerGroupUploader () {
+let JamfComputerGroupUploader = NSButton(frame: NSRect(x: 17, y: 303, width: 191, height: 17))
+ JamfComputerGroupUploader.title = "JamfComputerGroupUploader"
+ JamfComputerGroupUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfComputerGroupUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfComputerGroupUploader.isBordered = true
+ JamfComputerGroupUploader.font = .boldSystemFont(ofSize: 11)
+ JamfComputerGroupUploader.toolTip = "Upload a computer group to Jamf"
+ JamfComputerGroupUploader.action = #selector(appDelegate().JamfComputerGroupUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfComputerGroupUploader)
+}
+
+func JamfComputerGroupUploader () {
+ output = """
+
+ Arguments
+
+ computergroup_name
+ %GROUP_NAME%
+ computergroup_template
+ %GROUP_TEMPLATE%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfComputerGroupUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfComputerProfileUploader () {
+let JamfComputerProfileUploader = NSButton(frame: NSRect(x: 17, y: 282, width: 191, height: 17))
+ JamfComputerProfileUploader.title = "JamfComputerProfileUploader"
+ JamfComputerProfileUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfComputerProfileUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfComputerProfileUploader.isBordered = true
+ JamfComputerProfileUploader.font = .boldSystemFont(ofSize: 11)
+ JamfComputerProfileUploader.toolTip = "Upload computer configuration profiles to Jamf"
+ JamfComputerProfileUploader.action = #selector(appDelegate().JamfComputerProfileUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfComputerProfileUploader)
+}
+
+func JamfComputerProfileUploader () {
+ output = """
+
+ Arguments
+
+ profile_name
+ %PROFILE_NAME%
+ mobileconfig
+ /path/to/mobileconfig
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfComputerProfileUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfDockItemUploader () {
+let JamfDockItemUploader = NSButton(frame: NSRect(x: 17, y: 261, width: 191, height: 17))
+ JamfDockItemUploader.title = "JamfDockItemUploader"
+ JamfDockItemUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfDockItemUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfDockItemUploader.isBordered = true
+ JamfDockItemUploader.font = .boldSystemFont(ofSize: 11)
+ JamfDockItemUploader.toolTip = "Upload a dock item to Jamf"
+ JamfDockItemUploader.action = #selector(appDelegate().JamfDockItemUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfDockItemUploader)
+}
+
+func JamfDockItemUploader () {
+ output = """
+
+ Arguments
+
+ dock_item_name
+ %NAME%
+ dock_item_type
+ App
+ dock_item_path
+ file:///Applications/AppName.app/
+ replace_dock_item
+ False
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfDockItemUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfExtensionAttributeUploader () {
+let JamfExtensionAttributeUploader = NSButton(frame: NSRect(x: 17, y: 240, width: 191, height: 17))
+ JamfExtensionAttributeUploader.title = "JamfExtensionAttributeUploader"
+ JamfExtensionAttributeUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfExtensionAttributeUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfExtensionAttributeUploader.isBordered = true
+ JamfExtensionAttributeUploader.font = .boldSystemFont(ofSize: 11)
+ JamfExtensionAttributeUploader.toolTip = "Upload a extension attribute to Jamf"
+ JamfExtensionAttributeUploader.action = #selector(appDelegate().JamfExtensionAttributeUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfExtensionAttributeUploader)
+}
+
+func JamfExtensionAttributeUploader () {
+ output = """
+
+ Arguments
+
+ ea_name
+ %EXTENSION_ATTRIBUTE_NAME%
+ ea_script_path
+ %EXTENSION_ATTRIBUTE_SCRIPT%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfExtensionAttributeUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfMacAppUploader () {
+ let JamfMacAppUploader = NSButton(frame: NSRect(x: 17, y: 219, width: 191, height: 17))
+ JamfMacAppUploader.title = "JamfMacAppUploader"
+ JamfMacAppUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfMacAppUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfMacAppUploader.isBordered = true
+ JamfMacAppUploader.font = .boldSystemFont(ofSize: 11)
+ JamfMacAppUploader.toolTip = "Upload a Mac App Store app to a Jamf"
+ JamfMacAppUploader.action = #selector(appDelegate().JamfMacAppUploaderAction)
+ appDelegate().processorsView3rdParty.addSubview(JamfMacAppUploader)
+ }
+
+func JamfMacAppUploader () {
+ output = """
+
+ Arguments
+
+ macapp_name
+ Mac App Store app name
+ macapp_template
+ /path/to/template.xml
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfMacAppUploader
+
+"""
+ writeOutput ()
+}
+
+
+
+func createButtonJamfPackageUploader () {
+let JamfPackageUploader = NSButton(frame: NSRect(x: 17, y: 198, width: 191, height: 17))
+ JamfPackageUploader.title = "JamfPackageUploader"
+ JamfPackageUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfPackageUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfPackageUploader.isBordered = true
+ JamfPackageUploader.font = .boldSystemFont(ofSize: 11)
+ JamfPackageUploader.toolTip = "Upload a package to Jamf"
+ JamfPackageUploader.action = #selector(appDelegate().JamfPackageUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfPackageUploader)
+}
+
+func JamfPackageUploader () {
+ output = """
+
+ Arguments
+
+ pkg_category
+ %CATEGORY%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfPackageUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfPatchUploader () {
+let JamfPatchUploader = NSButton(frame: NSRect(x: 17, y: 177, width: 191, height: 17))
+ JamfPatchUploader.title = "JamfPatchUploader"
+ JamfPatchUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfPatchUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfPatchUploader.isBordered = true
+ JamfPatchUploader.font = .boldSystemFont(ofSize: 11)
+ JamfPatchUploader.toolTip = "Upload a patch defination to Jamf"
+ JamfPatchUploader.action = #selector(appDelegate().JamfPatchUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfPatchUploader)
+}
+
+func JamfPatchUploader () {
+ output = """
+
+ Arguments
+
+ patch_softwaretitle
+ %NAME%
+ patch_name
+ %PATCH_NAME%
+ patch_template
+ PatchTemplate-selfservice.xml
+ patch_icon_policy_name
+ Install Latest %NAME%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfPatchUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfPolicyDeleter () {
+let JamfPolicyDeleter = NSButton(frame: NSRect(x: 17, y: 156, width: 191, height: 17))
+ JamfPolicyDeleter.title = "JamfPolicyDeleter"
+ JamfPolicyDeleter.bezelStyle = NSButton.BezelStyle.inline
+ JamfPolicyDeleter.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfPolicyDeleter.isBordered = true
+ JamfPolicyDeleter.font = .boldSystemFont(ofSize: 11)
+ JamfPolicyDeleter.toolTip = "Delete a policy from Jamf"
+ JamfPolicyDeleter.action = #selector(appDelegate().JamfPolicyDeleterAction)
+appDelegate().processorsView3rdParty.addSubview(JamfPolicyDeleter)
+}
+
+func JamfPolicyDeleter() {
+ output = """
+
+ Arguments
+
+ policy_name
+ %POLICY_NAME%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfPolicyDeleter
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfPolicyLogFlusher () {
+let JamfPolicyLogFlusher = NSButton(frame: NSRect(x: 17, y: 135, width: 191, height: 17))
+ JamfPolicyLogFlusher.title = "JamfPolicyLogFlusher"
+ JamfPolicyLogFlusher.bezelStyle = NSButton.BezelStyle.inline
+ JamfPolicyLogFlusher.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfPolicyLogFlusher.isBordered = true
+ JamfPolicyLogFlusher.font = .boldSystemFont(ofSize: 11)
+ JamfPolicyLogFlusher.toolTip = "Flush a policy log from Jamf"
+ JamfPolicyLogFlusher.action = #selector(appDelegate().JamfPolicyLogFlusherAction)
+appDelegate().processorsView3rdParty.addSubview(JamfPolicyLogFlusher)
+}
+
+func JamfPolicyLogFlusher() {
+ output = """
+
+ Arguments
+
+ policy_name
+ %POLICY_NAME%
+ logflush_interval
+ Zero Days
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfPolicyLogFlusher
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfPolicyUploader () {
+let JamfPolicyUploader = NSButton(frame: NSRect(x: 17, y: 114, width: 191, height: 17))
+ JamfPolicyUploader.title = "JamfPolicyUploader"
+ JamfPolicyUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfPolicyUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfPolicyUploader.isBordered = true
+ JamfPolicyUploader.font = .boldSystemFont(ofSize: 11)
+ JamfPolicyUploader.toolTip = "Upload a policy to Jamf"
+ JamfPolicyUploader.action = #selector(appDelegate().JamfPolicyUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfPolicyUploader)
+}
+
+func JamfPolicyUploader () {
+ output = """
+
+ Arguments
+
+ icon
+ %SELF_SERVICE_ICON%
+ policy_name
+ %POLICY_NAME%
+ policy_template
+ %POLICY_TEMPLATE%
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfPolicyUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfScriptUploader () {
+let JamfScriptUploader = NSButton(frame: NSRect(x: 17, y: 93, width: 191, height: 17))
+ JamfScriptUploader.title = "JamfScriptUploader"
+ JamfScriptUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfScriptUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfScriptUploader.isBordered = true
+ JamfScriptUploader.font = .boldSystemFont(ofSize: 11)
+ JamfScriptUploader.toolTip = "Upload a script to Jamf"
+ JamfScriptUploader.action = #selector(appDelegate().JamfScriptUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfScriptUploader)
+}
+
+func JamfScriptUploader () {
+ output = """
+
+ Arguments
+
+ script_path
+ /pat/to/script.sh
+ script_category
+ %SCRIPT_CATEGORY%
+ script_priority
+ After
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfScriptUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfSoftwareRestrictionUploader () {
+let JamfSoftwareRestrictionUploader = NSButton(frame: NSRect(x: 17, y: 72, width: 191, height: 17))
+ JamfSoftwareRestrictionUploader.title = "JamfSoftwareRestrictionUploader"
+ JamfSoftwareRestrictionUploader.bezelStyle = NSButton.BezelStyle.inline
+ JamfSoftwareRestrictionUploader.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfSoftwareRestrictionUploader.isBordered = true
+ JamfSoftwareRestrictionUploader.font = .boldSystemFont(ofSize: 11)
+ JamfSoftwareRestrictionUploader.toolTip = "Upload a software restriction to Jamf"
+ JamfSoftwareRestrictionUploader.action = #selector(appDelegate().JamfSoftwareRestrictionUploaderAction)
+appDelegate().processorsView3rdParty.addSubview(JamfSoftwareRestrictionUploader)
+}
+
+func JamfSoftwareRestrictionUploader () {
+ output = """
+
+ Arguments
+
+ restriction_name
+ Name of Restriction
+ restriction_template
+ /path/to/template.xml
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfSoftwareRestrictionUploader
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfUploaderSlacker () {
+let JamfUploaderSlacker = NSButton(frame: NSRect(x: 17, y: 51, width: 191, height: 17))
+ JamfUploaderSlacker.title = "JamfUploaderSlacker"
+ JamfUploaderSlacker.bezelStyle = NSButton.BezelStyle.inline
+ JamfUploaderSlacker.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfUploaderSlacker.isBordered = true
+ JamfUploaderSlacker.font = .boldSystemFont(ofSize: 11)
+ JamfUploaderSlacker.toolTip = "Postprocessor for AutoPkg that will send details about a recipe run to a Slack webhook"
+ JamfUploaderSlacker.action = #selector(appDelegate().JamfUploaderSlackerAction)
+appDelegate().processorsView3rdParty.addSubview(JamfUploaderSlacker)
+}
+
+func JamfUploaderSlacker () {
+ output = """
+
+ Arguments
+
+ NAME
+ Name of the application
+ slack_webhook_url
+ https://slack.webhook.url
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfUploaderSlacker
+
+"""
+ writeOutput ()
+}
+
+func createButtonJamfUploaderTeamsNotifier () {
+let JamfUploaderTeamsNotifier = NSButton(frame: NSRect(x: 17, y: 30, width: 191, height: 17))
+ JamfUploaderTeamsNotifier.title = "JamfUploaderTeamsNotifier"
+ JamfUploaderTeamsNotifier.bezelStyle = NSButton.BezelStyle.inline
+ JamfUploaderTeamsNotifier.setButtonType(NSButton.ButtonType.momentaryPushIn)
+ JamfUploaderTeamsNotifier.isBordered = true
+ JamfUploaderTeamsNotifier.font = .boldSystemFont(ofSize: 11)
+ JamfUploaderTeamsNotifier.toolTip = "Postprocessor for AutoPkg that will send details about a recipe run to a Microsoft Teams webhook"
+ JamfUploaderTeamsNotifier.action = #selector(appDelegate().JamfUploaderTeamsNotifierAction)
+appDelegate().processorsView3rdParty.addSubview(JamfUploaderTeamsNotifier)
+}
+
+func JamfUploaderTeamsNotifier () {
+ output = """
+
+ Arguments
+
+ NAME
+ Name of the application
+ teams_webhook_url
+ https://teams.webhook.url
+
+ Processor
+ com.github.grahampugh.jamf-upload.processors/JamfUploaderTeamsNotifier
+
+"""
+ writeOutput ()
+}
diff --git a/RecipeBuilder/CheckAndVerify.swift b/RecipeBuilder/CheckAndVerify.swift
new file mode 100644
index 0000000..db017e6
--- /dev/null
+++ b/RecipeBuilder/CheckAndVerify.swift
@@ -0,0 +1,379 @@
+//
+// CheckAndVerify.swift
+// RecipeBuilder
+//
+// Created by Mikael Löfgren on 2022-03-06.
+// Copyright © 2022 Mikael Löfgren. All rights reserved.
+//
+
+import Foundation
+import Cocoa
+
+// Inspired by: https://github.com/homebysix/pre-commit-macadmin/blob/main/pre_commit_hooks/check_autopkg_recipes.py
+
+func returnProcessVersion (processName: String) -> String {
+ var returnVersion = ""
+
+ struct ProcessVersions {
+ var name: String
+ var version: String
+}
+
+var processandversions: [ProcessVersions]
+processandversions = [
+ProcessVersions(name:"AppDmgVersioner", version:"0"), // no version needed?
+ProcessVersions(name:"AppPkgCreator", version:"1.0"),
+ProcessVersions(name:"CodeSignatureVerifier", version:"0.3.1"),
+ProcessVersions(name:"Copier", version:"0"), // no version needed?
+ProcessVersions(name:"CURLTextSearcher", version:"0.5.1"),
+ProcessVersions(name:"DeprecationWarning", version:"1.1"),
+ProcessVersions(name:"DmgCreator", version:"0"), // no version needed?
+ProcessVersions(name:"EndOfCheckPhase", version:"0.1.0"),
+ProcessVersions(name:"FileCreator", version:"0"), // no version needed?
+ProcessVersions(name:"FileFinder", version:"0.2.3"),
+ProcessVersions(name:"FileMover", version:"0.2.9"),
+ProcessVersions(name:"FlatPkgPacker", version:"0.2.4"),
+ProcessVersions(name:"FlatPkgUnpacker", version:"0.1.0"),
+ProcessVersions(name:"GitHubReleasesInfoProvider", version:"0.5.0"),
+ProcessVersions(name:"Installer", version:"0.4.0"),
+ProcessVersions(name:"InstallFromDMG", version:"0.4.0"),
+ProcessVersions(name:"MunkiCatalogBuilder", version:"0.1.0"),
+ProcessVersions(name:"MunkiImporter", version:"0.1.0"),
+ProcessVersions(name:"MunkiInfoCreator", version:"0"), // no version needed?
+ProcessVersions(name:"MunkiInstallsItemsCreator", version:"0.1.0"),
+ProcessVersions(name:"MunkiPkginfoMerger", version:"0.1.0"),
+ProcessVersions(name:"MunkiSetDefaultCatalog", version:"0.4.2"),
+ProcessVersions(name:"PackageRequired", version:"0.5.1"),
+ProcessVersions(name:"PathDeleter", version:"0.1.0"),
+ProcessVersions(name:"PkgCopier", version:"0.1.0"),
+ProcessVersions(name:"PkgCreator", version:"0"),// no version needed?
+ProcessVersions(name:"PkgExtractor", version:"0.1.0"),
+ProcessVersions(name:"PkgInfoCreator", version:"0"),// no version needed?
+ProcessVersions(name:"PkgPayloadUnpacker", version:"0.1.0"),
+ProcessVersions(name:"PkgRootCreator", version:"0"),// no version needed?
+ProcessVersions(name:"PlistEditor", version:"0.1.0"),
+ProcessVersions(name:"PlistReader", version:"0.2.5"),
+ProcessVersions(name:"SparkleUpdateInfoProvider", version:"0.1.0"),
+ProcessVersions(name:"StopProcessingIf", version:"0.1.0"),
+ProcessVersions(name:"Symlinker", version:"0.1.0"),
+ProcessVersions(name:"Unarchiver", version:"0.1.0"),
+ProcessVersions(name:"URLDownloader", version:"0"), // no version needed?
+ProcessVersions(name:"URLTextSearcher", version:"0.2.9"),
+ProcessVersions(name:"Versioner", version:"0.1.0")
+]
+
+ let nameArray = processandversions.filter{$0.name.hasPrefix("\(processName)")}.map{$0.version}
+
+ if !nameArray.isEmpty {
+ returnVersion = nameArray[0]
+ }
+ return returnVersion
+}
+
+// Not in use
+//struct InputValues:Codable {
+//var Name:String
+//private enum CodingKeys : String, CodingKey {
+// case Name = "NAME"
+//}
+//}
+
+struct ProcessValues:Codable {
+ var Processor:String
+ private enum CodingKeys : String, CodingKey {
+ case Processor
+ }
+}
+
+struct RecipePlistConfig:Codable {
+var Description: String?
+var Identifier: String
+var MinimumVersion: String?
+var ParentRecipe: String?
+//var Input: InputValues?
+var Process: [ProcessValues]?
+
+private enum CodingKeys : String, CodingKey {
+ case Description = "Description"
+ case Identifier = "Identifier"
+ case MinimumVersion = "MinimumVersion"
+ case ParentRecipe = "ParentRecipe"
+ //case Input = "Input"
+ case Process
+}
+}
+
+
+struct Recipe {
+ let identifier: String
+ let path: String
+}
+
+var recipesArraySet: [Recipe] = []
+var recipesArray: [String] = []
+var checkResults = ""
+
+func checkDuplicates(array: [String]) -> String {
+ var encountered = Set()
+ var duplicate = Set()
+ var result = ""
+
+ for value in array {
+ if encountered.contains(value) {
+ // Add duplicate to the set
+ duplicate.insert(value)
+ }
+ else {
+ // Add value to the set
+ encountered.insert(value)
+ }
+ }
+
+ for all in duplicate {
+ result += "\n⚠️ Duplicated identifier\nIdentifier: \(all)\n"
+ for recipePath in recipesArraySet {
+ if recipePath.identifier == all {
+ // Append the filepath to results
+ result += "File: \(recipePath.path)\n"
+ }
+ }
+ }
+ return result
+}
+
+
+
+func startCheckAndVerify () {
+
+ var defaultPath = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/").path
+
+ if !FileManager.default.fileExists(atPath: defaultPath) { defaultPath = FileManager.default.homeDirectoryForCurrentUser.path }
+
+ let dialog = NSOpenPanel();
+ dialog.message = "Choose a folder to verify .recipes files from"
+ dialog.directoryURL = NSURL.fileURL(withPath: defaultPath, isDirectory: true)
+ dialog.showsResizeIndicator = true;
+ dialog.showsHiddenFiles = true;
+ dialog.canCreateDirectories = false;
+ dialog.canChooseDirectories = true;
+ dialog.canChooseFiles = false;
+ dialog.allowsMultipleSelection = false;
+
+
+
+
+ if (dialog.runModal() == NSApplication.ModalResponse.OK) {
+ let result = dialog.url
+
+ if (result != nil) {
+ defaultPath = result!.path
+ }
+ } else {
+ // User clicked on "Cancel"
+ appDelegate().fileOptions.selectItem(at: 0)
+ appDelegate().spinner.isHidden=true
+ return
+ }
+
+ let recipeRepoDir = defaultPath
+ if !FileManager.default.fileExists(atPath: recipeRepoDir) {
+ print("Path doesnt exist at: \(recipeRepoDir)")
+ appDelegate().fileOptions.selectItem(at: 0)
+ appDelegate().spinner.isHidden=true
+ return }
+
+
+ let enumerator = FileManager.default.enumerator(atPath: recipeRepoDir)
+ let filePaths = enumerator?.allObjects as! [String]
+ var recipeFilePaths = filePaths.filter{$0.hasSuffix(".recipe")}
+ var recipeYamlFilePaths = filePaths.filter{$0.hasSuffix(".recipe.yaml")}
+ let totalRecipes = recipeFilePaths.count + recipeYamlFilePaths.count
+
+ if recipeFilePaths.isEmpty {
+ appDelegate().fileOptions.selectItem(at: 0)
+ appDelegate().spinner.isHidden=true
+ return
+ }
+
+ let startText = "Start checking \(totalRecipes) recipes files..."
+ appDelegate().spinner.isHidden=false
+ appDelegate().spinner.startAnimation(appDelegate)
+ appDelegate().logWindow.orderFront(Any?.self)
+ highlightr!.theme.codeFont = NSFont(name: "Menlo", size: 12)
+ let highlightedCode = highlightr!.highlight(startText, as: "bash")!
+ appDelegate().logTextView.string = ""
+ appDelegate().logTextView.textStorage?.insert(NSAttributedString(attributedString: highlightedCode), at: 0)
+
+ DispatchQueue.global(qos: .userInteractive).async {
+
+
+ for recipes in recipeFilePaths {
+ let path = "\(recipeRepoDir)/\(recipes)"
+
+ func parseRecipe() -> RecipePlistConfig {
+ let url = URL(fileURLWithPath: path)
+ guard let data = try? Data(contentsOf: url),
+ let preferences = try? PropertyListDecoder().decode(RecipePlistConfig.self, from: data)
+ else {
+ // If problem parsing file set Identifier to Empty
+ return RecipePlistConfig(Identifier: "Empty")
+ }
+
+ return preferences
+ }
+ var minimumVersion = "MISSING"
+ if parseRecipe().MinimumVersion != nil {
+ // Value from plist
+ minimumVersion = parseRecipe().MinimumVersion!
+ }
+
+ func checkProcessors () {
+ var processArray: [String] = []
+ if parseRecipe().Process != nil {
+ for all in parseRecipe().Process! {
+
+ // Value of process minimum (minimum version of autopkg required to run this recipe)
+ // and value from plist should be higher or equal
+ let processVersion = returnProcessVersion(processName: all.Processor)
+
+ // if the vaules are Ascending 1..2..3 or same then ok
+ let versionCheck = processVersion.compare(minimumVersion, options: .numeric)
+ let ascending = versionCheck == ComparisonResult.orderedAscending
+ let orderedSame = versionCheck == ComparisonResult.orderedSame
+ //var descending = versionCheck == ComparisonResult.orderedDescending
+
+ if ascending == false && orderedSame == false {
+ checkResults += "\n⚠️ Processor: \(all.Processor) needs MinimumVersion: \(processVersion), now version: \(minimumVersion) is set in:\nFile: \(path)\n"
+
+// print(all.Processor)
+// print("Processor version:\(processVersion)")
+// print("Plist version:\(minimumVersion)")
+ }
+
+ // Check deprecated processors
+ if all.Processor == "CURLDownloader" {
+ checkResults += "\n⚠️ Processor: \(all.Processor) is deprecated\nFile: \(path)\n"
+ }
+ if all.Processor == "BrewCaskInfoProvider" {
+ checkResults += "\n⚠️ Processor: \(all.Processor) is deprecated\nFile: \(path)\n"
+ }
+ // Warn if any superclass processors
+ if all.Processor == "URLGetter" {
+ checkResults += "\n⚠️ Processor: \(all.Processor) is a superclass processor\nFile: \(path)\n"
+ }
+ processArray.append(all.Processor)
+ }
+ }
+
+
+ // Check EndofCheckPhase is after URLDownloader using Array with Index
+ let urlDownloader = processArray.firstIndex(where: {$0 == "URLDownloader"})
+ let endOfCheckPhase = processArray.firstIndex(where: {$0 == "EndOfCheckPhase"})
+ if urlDownloader != nil && endOfCheckPhase != nil {
+ // Convert to Int
+ let urlDownloaderInt = Int(urlDownloader!)
+ let endOfCheckPhaseInt = Int(endOfCheckPhase!)
+
+ if urlDownloaderInt > endOfCheckPhaseInt {
+ checkResults += "\n⚠️ Processor: URLDownloader should be used before Processor: EndOfCheckPhase\nFile: \(path)\n"
+ }
+
+ if urlDownloaderInt + 1 < endOfCheckPhaseInt {
+ checkResults += "\n⚠️ Processor: EndOfCheckPhase is recommended to be directly after Processor: URLDownloader\nFile: \(path)\n"
+ }
+
+ } else {
+ if urlDownloader != nil && endOfCheckPhase == nil {
+ checkResults += "\n⚠️ Processor: URLDownloader exist but missing Processor: EndOfCheckPhase\nFile: \(path)\n"
+ }
+
+ }
+ }
+
+ checkProcessors ()
+
+ if parseRecipe().Identifier != "Empty" {
+ // Add Identifier to Array so we can check for duplicates
+ recipesArraySet.append(Recipe(identifier: parseRecipe().Identifier, path: path))
+
+ if parseRecipe().ParentRecipe != nil {
+ // If ParentRecipe is the same as Identifier then show warning
+ if parseRecipe().ParentRecipe == parseRecipe().Identifier {
+ checkResults += "\n🛑 ParentRecipe is the same as Identifier\nFile: \(path)\n"
+ }
+ }
+ } else {
+ // We get this error: Failed to set posix_spawn_file_actions for fd -1 at index 0 with errno 9
+ // if we process to many files like ~3000 with a shell command
+ let plutil = shell("/usr/bin/plutil \"\(path)\"").replacingOccurrences(of: ":", with: "\nError:", options: [.regularExpression, .caseInsensitive])
+ checkResults += "\n🛑 Error reading file\nFile: \(plutil)\n"
+ }
+ }
+
+if !recipeYamlFilePaths.isEmpty {
+ for yamlRecipes in recipeYamlFilePaths {
+ let path = "\(recipeRepoDir)/\(yamlRecipes)"
+ var yamlID = ""
+ if freopen(path, "r", stdin) == nil {
+ perror(path)
+ }
+ while let line = readLine() {
+ if line.contains("Identifier:") {
+ yamlID = line.replacingOccurrences(of: "Identifier: ", with: "", options: [.regularExpression, .caseInsensitive])
+ recipesArraySet.append(Recipe(identifier: yamlID, path: path))
+ }
+
+ if line.contains("ParentRecipe:") {
+ let yamlParentRecipe = line.replacingOccurrences(of: "ParentRecipe: ", with: "", options: [.regularExpression, .caseInsensitive])
+
+ if yamlParentRecipe == yamlID {
+ checkResults += "\n🛑 ParentRecipe is the same as Identifier\nFile: \(path)\n"
+ }
+ }
+
+ if line.contains("MinimumVersion:") {
+ var yamlMinimumVersion: String
+ yamlMinimumVersion = line.replacingOccurrences(of: "MinimumVersion: ", with: "", options: [.regularExpression, .caseInsensitive])
+ yamlMinimumVersion = yamlMinimumVersion.replacingOccurrences(of: "\"", with: "", options: [.regularExpression, .caseInsensitive])
+ yamlMinimumVersion = yamlMinimumVersion.replacingOccurrences(of: "'", with: "", options: [.regularExpression, .caseInsensitive])
+ let yamlMinimumVersionDouble = Double(yamlMinimumVersion) ?? 0
+
+ if yamlMinimumVersionDouble < 2.3 {
+ checkResults += "\n⚠️ MinimumVersion is lower then 2.3\nFile: \(path)\n"
+ }
+ }
+ }
+ }
+ }
+
+ DispatchQueue.main.async {
+ // Back on the main thread
+ recipesArray = recipesArraySet.map({ $0.identifier })
+
+ checkResults += checkDuplicates(array: recipesArray)
+
+ if checkResults.isEmpty {
+ checkResults += ("✅ No problems found\n")
+ }
+
+ checkResults += """
+--------------------------------------------
+Done checking \(totalRecipes) recipes files\n
+"""
+ appDelegate().logWindow.orderFront(Any?.self)
+ highlightr!.theme.codeFont = NSFont(name: "Menlo", size: 12)
+ let highlightedCode = highlightr!.highlight(checkResults, as: "bash")!
+ appDelegate().logTextView.string = ""
+ appDelegate().logTextView.textStorage?.insert(NSAttributedString(attributedString: highlightedCode), at: 0)
+ appDelegate().fileOptions.selectItem(at: 0)
+ appDelegate().spinner.isHidden=true
+ // Reset all values
+ recipeFilePaths.removeAll()
+ recipeYamlFilePaths.removeAll()
+ recipesArray.removeAll()
+ recipesArraySet.removeAll()
+ checkResults = ""
+
+}
+ }
+}
diff --git a/RecipeBuilder/Functions.swift b/RecipeBuilder/Functions.swift
index 6f12966..72f7b7b 100644
--- a/RecipeBuilder/Functions.swift
+++ b/RecipeBuilder/Functions.swift
@@ -20,6 +20,7 @@ var name = String ()
var identififerTextField = String ()
var format = ""
var recipeFileName = ""
+var tmpRecipeFile = ""
let recipeBuilderFolder = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/").path
var recipeBuilderOutputFolderCreate = ""
var downloadPath = ""
@@ -117,14 +118,37 @@ func writeOutput () {
func writePopOvertext (processor: String, extraHelpText: String) {
- var processorInfo = shell("/usr/local/bin/autopkg processor-info \(processor)")
- processorInfo = processorInfo+"\nExtra Note:\n\(extraHelpText)"
+ var processorInfo = ""
+ if !processor.isEmpty {
+ processorInfo = shell("/usr/local/bin/autopkg processor-info \(processor)")
+ processorInfo = processorInfo+"\nExtra Note:\n\(extraHelpText)"
+ } else {
+ processorInfo = extraHelpText
+ }
+
+ let attributedText = [ NSAttributedString.Key.font: NSFont(name: "Menlo", size: 10.0)! ]
+ let processorInfoAttributed = NSAttributedString(string: processorInfo, attributes: attributedText)
+ appDelegate().helpPopoverText.string = ""
+ appDelegate().helpPopoverText.textStorage?.insert(NSAttributedString(attributedString: processorInfoAttributed), at: 0)
+}
+
+func writePopOvertextJamfUploader (processor: String, extraHelpText: String) {
+ var processorInfo = ""
+ if !processor.isEmpty {
+ processorInfo = shell("/usr/local/bin/autopkg processor-info -r com.github.grahampugh.jamf-upload.processors \(processor)")
+ processorInfo = processorInfo+"\nExtra Note:\n\(extraHelpText)"
+ } else {
+ processorInfo = extraHelpText
+ }
+
let attributedText = [ NSAttributedString.Key.font: NSFont(name: "Menlo", size: 10.0)! ]
let processorInfoAttributed = NSAttributedString(string: processorInfo, attributes: attributedText)
appDelegate().helpPopoverText.string = ""
appDelegate().helpPopoverText.textStorage?.insert(NSAttributedString(attributedString: processorInfoAttributed), at: 0)
}
+
+
func writeOutputUserButtons () {
insertionPointIndex = (appDelegate().outputTextField.selectedRanges.first?.rangeValue.location)!
//let xmlFormatOutput = prettyFormat(xmlString: output)
@@ -203,6 +227,9 @@ Add Identifier key and string to the document for example:
case let identifierFormat where identifierFormat.contains(".install."):
formatTitle = "install"
format = ".install."
+ case let identifierFormat where identifierFormat.contains(".jamf."):
+ formatTitle = "jamf"
+ format = ".jamf."
case let identifierFormat where identifierFormat.contains(".jss."):
formatTitle = "jss"
format = ".jss."
@@ -430,6 +457,8 @@ func createNewDocument () {
description = "Downloads the latest version of \(name) and creates a package"
case "install":
description = "Installs the latest version of \(name)"
+ case "jamf":
+ description = "Downloads the latest version of \(name) and then uploads to Jamf"
case "jss":
description = "Downloads the latest version of \(name) and then uploads to the JSS"
case "lanrev":
@@ -471,6 +500,53 @@ output = """
"""
+
+let munkiOutput = """
+
+
+
+
+ Description
+ \(description)
+ Identifier
+ \(identifierManually)
+ Input
+
+ NAME
+ \(name)
+ MUNKI_REPO_SUBDIR
+ apps/%NAME%
+ pkginfo
+
+ catalogs
+
+ testing
+
+ description
+ INSERT_DESCRIPTION_HERE
+ category
+ INSERT_CATEGORY_HERE
+ developer
+ INSERT_DEVELOPER_HERE
+ display_name
+ INSERT_DISPLAY_NAME_HERE
+ name
+ %NAME%
+ unattended_install
+
+
+
+ MinimumVersion
+ 0.5.0
+ ParentRecipe
+ INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE
+ Process
+
+
+
+
+
+"""
let downloadOutput = """
@@ -497,6 +573,65 @@ let downloadOutput = """
"""
+ let jamfOutput = """
+
+
+
+
+ Description
+ \(description)
+ Identifier
+ \(identifierManually)
+ Input
+
+ CATEGORY
+ Applications
+ GROUP_NAME
+ %NAME%-update-smart
+ GROUP_TEMPLATE
+ SmartGroupTemplate.xml
+ NAME
+ \(name)
+ PATCH_SOFTWARETITLE
+ Name of the patch softwaretitle (e.g. 'Mozilla Firefox') used in Jamf
+ PATCH_NAME
+ Name of the patch policy (e.g. 'Mozilla Firefox - 93.02.10')
+ PATCH_TEMPLATE
+ PatchTemplate-selfservice.xml
+ PATCH_ICON_POLICY_NAME
+ Name of an already existing (!) policy (not a patch policy)
+ POLICY_CATEGORY
+ Testing
+ POLICY_NAME
+ Install Latest %NAME%
+ POLICY_TEMPLATE
+ PolicyTemplate.xml
+ SELF_SERVICE_DESCRIPTION
+ Install Latest %NAME%
+ SELF_SERVICE_DISPLAY_NAME
+ Install Latest %NAME%
+ SELF_SERVICE_ICON
+ \(name).png
+ TESTING_GROUP_NAME
+ Testing
+ UPDATE_PREDICATE
+ pkg_uploaded == False
+ SLACK_WEBHOOK_URL
+ https://url.to.slack.com
+ TEAMS_WEBHOOK_URL
+ https://url.to.teams.com
+
+ MinimumVersion
+ 2.3
+ ParentRecipe
+ INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE_OR_REMOVE
+ Process
+
+
+
+
+
+ """
let jssOutput = """
@@ -591,13 +726,53 @@ let jssOutput = """
range = (xmlFormatOutput as NSString).range(of: "")
attributedReplaceText = NSAttributedString(string: "", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+ } else if descriptionFormat == "jamf" {
+ output = jamfOutput
+ outputNewDocument ()
+ var range = (xmlFormatOutput as NSString).range(of: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE_OR_REMOVE")
+ var attributedReplaceText = NSAttributedString(string: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE_OR_REMOVE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+
+ range = (xmlFormatOutput as NSString).range(of: "")
+ attributedReplaceText = NSAttributedString(string: "", attributes: yellowBackgroundAttributes)
+
appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
} else if descriptionFormat == "jss" {
- output = jssOutput
+ output = jssOutput
+ outputNewDocument ()
+ let range = (xmlFormatOutput as NSString).range(of: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE")
+ let attributedReplaceText = NSAttributedString(string: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ } else if descriptionFormat == "munki" {
+ output = munkiOutput
outputNewDocument ()
- let range = (xmlFormatOutput as NSString).range(of: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE")
- let attributedReplaceText = NSAttributedString(string: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE", attributes: yellowBackgroundAttributes)
+ var range = (xmlFormatOutput as NSString).range(of: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE")
+ var attributedReplaceText = NSAttributedString(string: "INSERT_YOUR_PARENT_RECIPE_IDENTIFIER_HERE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ range = (xmlFormatOutput as NSString).range(of: "INSERT_DESCRIPTION_HERE")
+ attributedReplaceText = NSAttributedString(string: "INSERT_DESCRIPTION_HERE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ range = (xmlFormatOutput as NSString).range(of: "INSERT_CATEGORY_HERE")
+ attributedReplaceText = NSAttributedString(string: "INSERT_CATEGORY_HERE", attributes: yellowBackgroundAttributes)
appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ range = (xmlFormatOutput as NSString).range(of: "INSERT_DEVELOPER_HERE")
+ attributedReplaceText = NSAttributedString(string: "INSERT_DEVELOPER_HERE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ range = (xmlFormatOutput as NSString).range(of: "INSERT_DISPLAY_NAME_HERE")
+ attributedReplaceText = NSAttributedString(string: "INSERT_DISPLAY_NAME_HERE", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
+ range = (xmlFormatOutput as NSString).range(of: "")
+ attributedReplaceText = NSAttributedString(string: "", attributes: yellowBackgroundAttributes)
+ appDelegate().outputTextField.textStorage?.replaceCharacters(in: range, with: attributedReplaceText)
+
} else {
outputNewDocument ()
let range = (xmlFormatOutput as NSString).range(of: "")
@@ -618,7 +793,7 @@ func finaliseDocument () {
if identifierMismatch == true {return}
if recipeFileName == "" { return }
createRecipeBuilderFolders(createFolder: "tmp")
- let tmpRecipeFile = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/tmp/\(recipeFileName)").path
+ tmpRecipeFile = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/tmp/\(recipeFileName)").path
let documentDirURL = URL(fileURLWithPath: tmpRecipeFile)
// Save data to file
let fileURL = documentDirURL
@@ -686,8 +861,9 @@ func autoPkgRunner () {
getIdentifier ()
if recipeFileName == "" { return }
appDelegate().logWindow.orderFront(Any?.self)
- createRecipeBuilderFolders(createFolder: "tmp")
- let tmpRecipeFile = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/tmp/\(recipeFileName)").path
+ createRecipeBuilderFolders(createFolder: "")
+ let randomNumber = Int.random(in: 0 ..< 999)
+ tmpRecipeFile = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/\(recipeFileName).temp_\(randomNumber)").path
let documentDirURL = URL(fileURLWithPath: tmpRecipeFile)
// Save data to file
let fileURL = documentDirURL
@@ -753,6 +929,7 @@ func toggleExternalEditor () {
appDelegate().bbedit.state = .off
appDelegate().sublimeText.state = .off
appDelegate().textMate.state = .off
+ appDelegate().visualStudioCode.state = .off
}
if appDelegate().selectedExternalEditor == "BBEdit" {
@@ -760,6 +937,7 @@ func toggleExternalEditor () {
appDelegate().bbedit.state = .on
appDelegate().sublimeText.state = .off
appDelegate().textMate.state = .off
+ appDelegate().visualStudioCode.state = .off
}
if appDelegate().selectedExternalEditor == "Sublime Text" {
@@ -767,6 +945,7 @@ func toggleExternalEditor () {
appDelegate().bbedit.state = .off
appDelegate().sublimeText.state = .on
appDelegate().textMate.state = .off
+ appDelegate().visualStudioCode.state = .off
}
if appDelegate().selectedExternalEditor == "TextMate" {
@@ -774,6 +953,15 @@ func toggleExternalEditor () {
appDelegate().bbedit.state = .off
appDelegate().sublimeText.state = .off
appDelegate().textMate.state = .on
+ appDelegate().visualStudioCode.state = .off
+ }
+
+ if appDelegate().selectedExternalEditor == "Visual Studio Code" {
+ appDelegate().atom.state = .off
+ appDelegate().bbedit.state = .off
+ appDelegate().sublimeText.state = .off
+ appDelegate().textMate.state = .off
+ appDelegate().visualStudioCode.state = .on
}
}
@@ -943,7 +1131,7 @@ func shell(_ command: String) -> String {
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
-
+
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
@@ -1023,10 +1211,15 @@ try FileManager.default.createDirectory(atPath: recipeBuilderOutputFolderCreate,
func deleteTmpFolder () {
let tmpRecipeFolder = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/AutoPkg/RecipeBuilder Output/tmp/").path
- // If tempfolder exist
- if FileManager.default.fileExists(atPath: tmpRecipeFolder) {
- // Delete tempfolder
- try? FileManager.default.removeItem(atPath: tmpRecipeFolder)
- }
+ // If tempfolder exist
+ if FileManager.default.fileExists(atPath: tmpRecipeFolder) {
+ // Delete tempfolder
+ try? FileManager.default.removeItem(atPath: tmpRecipeFolder)
+ }
+ // If tempfile exist
+ if FileManager.default.fileExists(atPath: tmpRecipeFile) {
+ // Delete tempfile
+ try? FileManager.default.removeItem(atPath: tmpRecipeFile)
+ }
}
diff --git a/RecipeBuilder/Info.plist b/RecipeBuilder/Info.plist
index acc8d94..6bae38d 100644
--- a/RecipeBuilder/Info.plist
+++ b/RecipeBuilder/Info.plist
@@ -34,7 +34,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.03
+ $(MARKETING_VERSION)
CFBundleVersion
1
LSApplicationCategoryType
diff --git a/RecipeBuilder/JamfUploaderHelpTexts.swift b/RecipeBuilder/JamfUploaderHelpTexts.swift
new file mode 100644
index 0000000..2e5e8fb
--- /dev/null
+++ b/RecipeBuilder/JamfUploaderHelpTexts.swift
@@ -0,0 +1,26 @@
+//
+// JamfUploaderHelpTexts.swift
+// RecipeBuilder
+//
+// Created by Mikael Löfgren on 2022-03-04.
+// Copyright © 2022 Mikael Löfgren. All rights reserved.
+//
+
+import Foundation
+
+var JamfCategoryUploaderHelp=""
+var JamfComputerGroupUploaderHelp=""
+var JamfComputerProfileUploaderHelp=""
+var JamfDockItemUploaderHelp=""
+var JamfExtensionAttributeUploaderHelp=""
+var JamfMacAppUploaderHelp=""
+var JamfPackageUploaderHelp=""
+var JamfPatchUploaderHelp=""
+var JamfPolicyDeleterHelp=""
+var JamfPolicyLogFlusherHelp=""
+var JamfPolicyUploaderHelp=""
+var JamfScriptUploaderHelp=""
+var JamfSoftwareRestrictionUploaderHelp=""
+var JamfUploaderSlackerHelp=""
+var JamfUploaderTeamsNotifierHelp=""
+
diff --git a/RecipeBuilder/UserButtons.swift b/RecipeBuilder/UserButtons.swift
index 67ef186..95553f2 100644
--- a/RecipeBuilder/UserButtons.swift
+++ b/RecipeBuilder/UserButtons.swift
@@ -61,7 +61,7 @@ var output10 = ""
var help10 = ""
func createButton1 (title: String) {
-let button1 = NSButton(frame: NSRect(x: 17, y: 255, width: 195, height: 17))
+let button1 = NSButton(frame: NSRect(x: 17, y: 258, width: 191, height: 17))
button1.title = title
button1.bezelStyle = NSButton.BezelStyle.inline
button1.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -72,7 +72,7 @@ appDelegate().buttonView.addSubview(button1)
}
func createButton2 (title: String) {
-let button2 = NSButton(frame: NSRect(x: 17, y: 234, width: 195, height: 17))
+let button2 = NSButton(frame: NSRect(x: 17, y: 237, width: 191, height: 17))
button2.title = title
button2.bezelStyle = NSButton.BezelStyle.inline
button2.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -83,7 +83,7 @@ appDelegate().buttonView.addSubview(button2)
}
func createButton3 (title: String) {
-let button3 = NSButton(frame: NSRect(x: 17, y: 213, width: 195, height: 17))
+let button3 = NSButton(frame: NSRect(x: 17, y: 216, width: 191, height: 17))
button3.title = title
button3.bezelStyle = NSButton.BezelStyle.inline
button3.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -94,7 +94,7 @@ appDelegate().buttonView.addSubview(button3)
}
func createButton4 (title: String) {
-let button4 = NSButton(frame: NSRect(x: 17, y: 192, width: 195, height: 17))
+let button4 = NSButton(frame: NSRect(x: 17, y: 195, width: 191, height: 17))
button4.title = title
button4.bezelStyle = NSButton.BezelStyle.inline
button4.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -105,7 +105,7 @@ appDelegate().buttonView.addSubview(button4)
}
func createButton5 (title: String) {
-let button5 = NSButton(frame: NSRect(x: 17, y: 171, width: 195, height: 17))
+let button5 = NSButton(frame: NSRect(x: 17, y: 174, width: 191, height: 17))
button5.title = title
button5.bezelStyle = NSButton.BezelStyle.inline
button5.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -116,7 +116,7 @@ appDelegate().buttonView.addSubview(button5)
}
func createButton6 (title: String) {
-let button6 = NSButton(frame: NSRect(x: 17, y: 150, width: 195, height: 17))
+let button6 = NSButton(frame: NSRect(x: 17, y: 153, width: 191, height: 17))
button6.title = title
button6.bezelStyle = NSButton.BezelStyle.inline
button6.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -127,7 +127,7 @@ appDelegate().buttonView.addSubview(button6)
}
func createButton7 (title: String) {
-let button7 = NSButton(frame: NSRect(x: 17, y: 129, width: 195, height: 17))
+let button7 = NSButton(frame: NSRect(x: 17, y: 132, width: 191, height: 17))
button7.title = title
button7.bezelStyle = NSButton.BezelStyle.inline
button7.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -138,7 +138,7 @@ button7.action = #selector(appDelegate().buttonAction7)
}
func createButton8 (title: String) {
-let button8 = NSButton(frame: NSRect(x: 17, y: 108, width: 195, height: 17))
+let button8 = NSButton(frame: NSRect(x: 17, y: 111, width: 191, height: 17))
button8.title = title
button8.bezelStyle = NSButton.BezelStyle.inline
button8.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -149,7 +149,7 @@ appDelegate().buttonView.addSubview(button8)
}
func createButton9 (title: String) {
-let button9 = NSButton(frame: NSRect(x: 17, y: 87, width: 195, height: 17))
+let button9 = NSButton(frame: NSRect(x: 17, y: 90, width: 191, height: 17))
button9.title = title
button9.bezelStyle = NSButton.BezelStyle.inline
button9.setButtonType(NSButton.ButtonType.momentaryPushIn)
@@ -160,7 +160,7 @@ appDelegate().buttonView.addSubview(button9)
}
func createButton10 (title: String) {
-let button10 = NSButton(frame: NSRect(x: 17, y: 66, width: 195, height: 17))
+let button10 = NSButton(frame: NSRect(x: 17, y: 69, width: 191, height: 17))
button10.title = title
button10.bezelStyle = NSButton.BezelStyle.inline
button10.setButtonType(NSButton.ButtonType.momentaryPushIn)