mirror of
https://github.com/munki/munki.git
synced 2026-01-06 06:29:56 -06:00
Merge branch 'Munki7dev'
This commit is contained in:
@@ -422,10 +422,7 @@ struct ManagedSoftwareUpdate: AsyncParsableCommand {
|
||||
_ = forceInstallPackageCheck() // this might mark some more items as unattended
|
||||
// now install anything that can be done unattended
|
||||
munkiLog("Installing only items marked unattended because SuppressLoginwindowInstall is true.")
|
||||
_ = await doInstallTasks(
|
||||
doAppleUpdates: appleUpdateCount > 0,
|
||||
onlyUnattended: true
|
||||
)
|
||||
_ = await doInstallTasks(onlyUnattended: true)
|
||||
return
|
||||
}
|
||||
if getIdleSeconds() < 10 {
|
||||
|
||||
@@ -332,7 +332,7 @@ func doInstallTasks(doAppleUpdates: Bool = false, onlyUnattended: Bool = false)
|
||||
}
|
||||
|
||||
var munkiItemsRestartAction = PostAction.none
|
||||
var appleItemsRestartAction = PostAction.none
|
||||
//var appleItemsRestartAction = PostAction.none
|
||||
|
||||
if munkiUpdatesAvailable() > 0 {
|
||||
// install Munki updates
|
||||
@@ -341,7 +341,7 @@ func doInstallTasks(doAppleUpdates: Bool = false, onlyUnattended: Bool = false)
|
||||
if munkiUpdatesContainItemWithInstallerType("startosinstall") {
|
||||
Report.shared.save()
|
||||
// install macOS
|
||||
// TODO: implement this (install macOS via startOSInstall)
|
||||
// TODO: implement this (install macOS via startOSInstall) (will likely never implement)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,7 +353,8 @@ func doInstallTasks(doAppleUpdates: Bool = false, onlyUnattended: Bool = false)
|
||||
|
||||
Report.shared.save()
|
||||
|
||||
return max(appleItemsRestartAction, munkiItemsRestartAction)
|
||||
//return max(appleItemsRestartAction, munkiItemsRestartAction) // we no longer support installing Apple updates
|
||||
return munkiItemsRestartAction
|
||||
}
|
||||
|
||||
/// Handle the need for a forced logout. Start our logouthelper
|
||||
|
||||
@@ -790,27 +790,10 @@
|
||||
C0EEC9A62DA7335900F92942 /* clientcerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = clientcerts.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
C09616492DEA2C0900281B6B /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
tokenize.swift,
|
||||
);
|
||||
target = C07A6FB62C2B5ADE00090743 /* munkitester */;
|
||||
};
|
||||
C096164D2DEA2C0900281B6B /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
tokenize.swift,
|
||||
);
|
||||
target = C0684E5B2DC736EE0091E774 /* munkiCLItesting */;
|
||||
};
|
||||
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||
|
||||
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||
C00519A22D2A5B850060DDB6 /* authrestartd */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = authrestartd; sourceTree = "<group>"; };
|
||||
C0276DB22E8C070500D443C3 /* repocheck */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = repocheck; sourceTree = "<group>"; };
|
||||
C05DB2032DAC53150081FACD /* manifestutil */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (C09616492DEA2C0900281B6B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, C096164D2DEA2C0900281B6B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = manifestutil; sourceTree = "<group>"; };
|
||||
C05DB2032DAC53150081FACD /* manifestutil */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = manifestutil; sourceTree = "<group>"; };
|
||||
C0684DD22DBFDBD20091E774 /* precache_agent */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = precache_agent; sourceTree = "<group>"; };
|
||||
C0684E2E2DC040450091E774 /* installhelper */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = installhelper; sourceTree = "<group>"; };
|
||||
C0684E5D2DC736EE0091E774 /* munkiCLItesting */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = munkiCLItesting; sourceTree = "<group>"; };
|
||||
|
||||
43
code/cli/munki/munkiCLItesting/fileUtilsTests.swift
Normal file
43
code/cli/munki/munkiCLItesting/fileUtilsTests.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// fileUtilsTests.swift
|
||||
// munki
|
||||
//
|
||||
// Created by Greg Neagle on 10/22/25.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import Testing
|
||||
|
||||
struct fileUtilsTests {
|
||||
@Test func pathIsDirectoryTests() throws {
|
||||
// setup
|
||||
let testDirectoryPath = try #require(TempDir.shared.path, "Can't get temp directory path")
|
||||
try #require(
|
||||
FileManager.default.createFile(
|
||||
atPath: testDirectoryPath + "/test.txt", contents: nil, attributes: nil
|
||||
) != false,
|
||||
"Can't create test file"
|
||||
)
|
||||
try #require(
|
||||
try? FileManager.default.createSymbolicLink(
|
||||
atPath: testDirectoryPath + "/symlink",
|
||||
withDestinationPath: testDirectoryPath
|
||||
),
|
||||
"Can't create test symlink"
|
||||
)
|
||||
#expect(pathIsDirectory(testDirectoryPath))
|
||||
#expect(!pathIsDirectory(testDirectoryPath + "/test.txt"))
|
||||
#expect(!pathIsDirectory(testDirectoryPath + "/symlink"))
|
||||
#expect(pathIsDirectory(testDirectoryPath + "/symlink", followSymlinks: true))
|
||||
}
|
||||
}
|
||||
@@ -236,7 +236,10 @@ struct PackageInfoFileTests {
|
||||
let unwrappedPkginfoPath = try #require(
|
||||
pkginfoPath, "Failed to create temporary pkgInfo file"
|
||||
)
|
||||
let receipt = receiptFromPackageInfoFile(unwrappedPkginfoPath)
|
||||
let receipt = try #require(
|
||||
receiptFromPackageInfoFile(unwrappedPkginfoPath),
|
||||
"Could not get receipt from pkginfo"
|
||||
)
|
||||
#expect((receipt["packageid"] as? String ?? "") == "com.googlecode.munki.core")
|
||||
}
|
||||
|
||||
@@ -244,7 +247,10 @@ struct PackageInfoFileTests {
|
||||
let unwrappedPkginfoPath = try #require(
|
||||
pkginfoPath, "Failed to create temporary pkgInfo file"
|
||||
)
|
||||
let receipt = receiptFromPackageInfoFile(unwrappedPkginfoPath)
|
||||
let receipt = try #require(
|
||||
receiptFromPackageInfoFile(unwrappedPkginfoPath),
|
||||
"Could not get receipt from pkginfo"
|
||||
)
|
||||
#expect((receipt["version"] as? String ?? "") == "7.0.0.5096")
|
||||
}
|
||||
|
||||
@@ -252,7 +258,10 @@ struct PackageInfoFileTests {
|
||||
let unwrappedPkginfoPath = try #require(
|
||||
pkginfoPath, "Failed to create temporary pkgInfo file"
|
||||
)
|
||||
let receipt = receiptFromPackageInfoFile(unwrappedPkginfoPath)
|
||||
let receipt = try #require(
|
||||
receiptFromPackageInfoFile(unwrappedPkginfoPath),
|
||||
"Could not get receipt from pkginfo"
|
||||
)
|
||||
#expect((receipt["installed_size"] as? Int ?? 0) == 39393)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,26 +74,24 @@ func createInstallsItem(_ itempath: String) -> PlistDict {
|
||||
} else {
|
||||
info["type"] = "bundle"
|
||||
}
|
||||
if let plist = getBundleInfo(itempath) {
|
||||
for key in ["CFBundleName", "CFBundleIdentifier",
|
||||
"CFBundleShortVersionString", "CFBundleVersion"]
|
||||
{
|
||||
if let value = plist[key] as? String {
|
||||
info[key] = value
|
||||
}
|
||||
for key in ["CFBundleName", "CFBundleIdentifier",
|
||||
"CFBundleShortVersionString", "CFBundleVersion"]
|
||||
{
|
||||
if let value = plist[key] as? String {
|
||||
info[key] = value
|
||||
}
|
||||
if let minOSVers = plist["LSMinimumSystemVersion"] as? String {
|
||||
info["minosversion"] = minOSVers
|
||||
} else if let minOSVersByArch = plist["LSMinimumSystemVersionByArchitecture"] as? [String: String] {
|
||||
// get the highest/latest of all the minimum os versions
|
||||
let minOSVersions = minOSVersByArch.values
|
||||
let versions = minOSVersions.map { MunkiVersion($0) }
|
||||
if let maxVersion = versions.max() {
|
||||
info["minosversion"] = maxVersion.value
|
||||
}
|
||||
} else if let minSysVers = plist["SystemVersionCheck:MinimumSystemVersion"] as? String {
|
||||
info["minosversion"] = minSysVers
|
||||
}
|
||||
if let minOSVers = plist["LSMinimumSystemVersion"] as? String {
|
||||
info["minosversion"] = minOSVers
|
||||
} else if let minOSVersByArch = plist["LSMinimumSystemVersionByArchitecture"] as? [String: String] {
|
||||
// get the highest/latest of all the minimum os versions
|
||||
let minOSVersions = minOSVersByArch.values
|
||||
let versions = minOSVersions.map { MunkiVersion($0) }
|
||||
if let maxVersion = versions.max() {
|
||||
info["minosversion"] = maxVersion.value
|
||||
}
|
||||
} else if let minSysVers = plist["SystemVersionCheck:MinimumSystemVersion"] as? String {
|
||||
info["minosversion"] = minSysVers
|
||||
}
|
||||
} else if let plist = try? readPlist(fromFile: itempath) as? PlistDict {
|
||||
// we must be a plist
|
||||
@@ -115,6 +113,8 @@ func createInstallsItem(_ itempath: String) -> PlistDict {
|
||||
} else {
|
||||
info["version_comparison_key"] = "CFBundleShortVersionString"
|
||||
}
|
||||
} else if info["CFBundleVersion"] != nil {
|
||||
info["version_comparison_key"] = "CFBundleVersion"
|
||||
}
|
||||
|
||||
if !info.keys.contains("CFBundleShortVersionString"), !info.keys.contains("CFBundleVersion") {
|
||||
|
||||
@@ -168,7 +168,7 @@ class FileRepo: Repo {
|
||||
}
|
||||
}
|
||||
// does root dir exist now?
|
||||
if !pathIsDirectory(root) {
|
||||
if !pathIsDirectory(root, followSymlinks: true) {
|
||||
throw MunkiError("Repo path does not exist")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,21 +336,19 @@ func getHTTPfileIfChangedAtomically(
|
||||
resume: Bool = false,
|
||||
followRedirects: String = "none",
|
||||
) throws -> Bool {
|
||||
var eTag = ""
|
||||
var getOnlyIfNewer = false
|
||||
if pathExists(destinationPath) {
|
||||
getOnlyIfNewer = true
|
||||
// see if we have an etag attribute
|
||||
// see if we have a stored etag or last-modified header
|
||||
do {
|
||||
let data = try getXattr(named: GURL_XATTR, atPath: destinationPath)
|
||||
if let headers = try readPlist(fromData: data) as? [String: String] {
|
||||
eTag = headers["etag"] ?? ""
|
||||
// We can use onlyIfNewer if we have either etag or last-modified
|
||||
if headers["etag"] != nil || headers["last-modified"] != nil {
|
||||
getOnlyIfNewer = true
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// fall through
|
||||
}
|
||||
if eTag.isEmpty {
|
||||
getOnlyIfNewer = false
|
||||
// fall through - no cached headers
|
||||
}
|
||||
}
|
||||
var headers: [String: String]
|
||||
|
||||
@@ -39,7 +39,7 @@ func pathIsRegularFile(_ path: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/// Returns true if path is a symlink/
|
||||
/// Returns true if path is a symlink
|
||||
func pathIsSymlink(_ path: String) -> Bool {
|
||||
if let fileType = fileType(path) {
|
||||
return fileType == FileAttributeType.typeSymbolicLink.rawValue
|
||||
@@ -47,10 +47,17 @@ func pathIsSymlink(_ path: String) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
/// Returns true if path is a directory/
|
||||
func pathIsDirectory(_ path: String) -> Bool {
|
||||
/// Returns true if path is a directory; follows symlinks if followSymlinks=true
|
||||
func pathIsDirectory(_ path: String, followSymlinks: Bool = false) -> Bool {
|
||||
if let fileType = fileType(path) {
|
||||
return fileType == FileAttributeType.typeDirectory.rawValue
|
||||
if fileType == FileAttributeType.typeDirectory.rawValue {
|
||||
return true
|
||||
}
|
||||
if followSymlinks, fileType == FileAttributeType.typeSymbolicLink.rawValue {
|
||||
if let target = try? FileManager.default.destinationOfSymbolicLink(atPath: path) {
|
||||
return pathIsDirectory(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
/// one single place to define a version for CLI tools
|
||||
let CLI_TOOLS_VERSION = "7.0.1"
|
||||
let CLI_TOOLS_VERSION = "7.0.2"
|
||||
let BUILD = "<BUILD_GOES_HERE>"
|
||||
|
||||
/// Returns version of Munki tools
|
||||
|
||||
Reference in New Issue
Block a user