Merge remote-tracking branch 'origin/master' into meta-dev
# Conflicts: # .github/workflows/main.yml # ClashX.xcodeproj/project.pbxproj # ClashX/goClash/go.mod # ClashX/goClash/go.sum
This commit is contained in:
commit
fe814bf803
|
@ -22,6 +22,7 @@
|
||||||
01E33AB229B5BF4200FD1006 /* NSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */; };
|
01E33AB229B5BF4200FD1006 /* NSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */; };
|
||||||
01E33AB529B5C5E400FD1006 /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */; };
|
01E33AB529B5C5E400FD1006 /* menu_icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */; };
|
||||||
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA63125BBF03DC1A291D3351 /* libPods-ClashX Meta.a */; };
|
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AA63125BBF03DC1A291D3351 /* libPods-ClashX Meta.a */; };
|
||||||
|
4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4908087A29F8F3FF007A4944 /* libresolv.tbd */; };
|
||||||
4913C82321157D0200F6B87C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913C82221157D0200F6B87C /* Notification.swift */; };
|
4913C82321157D0200F6B87C /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913C82221157D0200F6B87C /* Notification.swift */; };
|
||||||
491E6203258A424D00313AEF /* CommonUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 491E61FD258A424500313AEF /* CommonUtils.m */; };
|
491E6203258A424D00313AEF /* CommonUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 491E61FD258A424500313AEF /* CommonUtils.m */; };
|
||||||
49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */; };
|
49228457270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49228456270AADE20027A4B6 /* RemoteConfigUpdateIntervalSettingView.swift */; };
|
||||||
|
@ -156,6 +157,7 @@
|
||||||
01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Extension.swift"; sourceTree = "<group>"; };
|
01E33AB129B5BF4200FD1006 /* NSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSColor+Extension.swift"; sourceTree = "<group>"; };
|
||||||
01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icon@2x.png"; sourceTree = "<group>"; };
|
01E33AB429B5C5E300FD1006 /* menu_icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu_icon@2x.png"; sourceTree = "<group>"; };
|
||||||
3F86DA2DA3CC14731BE1ABF7 /* Pods-ClashX Meta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClashX Meta.release.xcconfig"; path = "Pods/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta.release.xcconfig"; sourceTree = "<group>"; };
|
3F86DA2DA3CC14731BE1ABF7 /* Pods-ClashX Meta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ClashX Meta.release.xcconfig"; path = "Pods/Target Support Files/Pods-ClashX Meta/Pods-ClashX Meta.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
4908087A29F8F3FF007A4944 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
|
||||||
4913C82221157D0200F6B87C /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
4913C82221157D0200F6B87C /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||||
491E61FC258A424500313AEF /* CommonUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtils.h; sourceTree = "<group>"; };
|
491E61FC258A424500313AEF /* CommonUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonUtils.h; sourceTree = "<group>"; };
|
||||||
491E61FD258A424500313AEF /* CommonUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtils.m; sourceTree = "<group>"; };
|
491E61FD258A424500313AEF /* CommonUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommonUtils.m; sourceTree = "<group>"; };
|
||||||
|
@ -266,6 +268,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
4908087B29F8F405007A4944 /* libresolv.tbd in Frameworks */,
|
||||||
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */,
|
185CBAEDFE986E6E1B836359 /* libPods-ClashX Meta.a in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -544,6 +547,7 @@
|
||||||
CF1AC9FACC36FCE7663C5583 /* Frameworks */ = {
|
CF1AC9FACC36FCE7663C5583 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4908087A29F8F3FF007A4944 /* libresolv.tbd */,
|
||||||
AA63125BBF03DC1A291D3351 /* libPods-ClashX Meta.a */,
|
AA63125BBF03DC1A291D3351 /* libPods-ClashX Meta.a */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
|
|
|
@ -278,7 +278,6 @@ private enum DaemonInstallResult {
|
||||||
case kSMErrorToolNotValid: return "blessError: kSMErrorToolNotValid"
|
case kSMErrorToolNotValid: return "blessError: kSMErrorToolNotValid"
|
||||||
case kSMErrorJobNotFound: return "blessError: kSMErrorJobNotFound"
|
case kSMErrorJobNotFound: return "blessError: kSMErrorJobNotFound"
|
||||||
case kSMErrorServiceUnavailable: return "blessError: kSMErrorServiceUnavailable"
|
case kSMErrorServiceUnavailable: return "blessError: kSMErrorServiceUnavailable"
|
||||||
case kSMErrorJobNotFound: return "blessError: kSMErrorJobNotFound"
|
|
||||||
case kSMErrorJobMustBeEnabled: return "ClashX Helper is disabled by other process. Please run \"sudo launchctl enable system/\(PrivilegedHelperManager.machServiceName)\" in your terminal. The command has been copied to your pasteboard"
|
case kSMErrorJobMustBeEnabled: return "ClashX Helper is disabled by other process. Please run \"sudo launchctl enable system/\(PrivilegedHelperManager.machServiceName)\" in your terminal. The command has been copied to your pasteboard"
|
||||||
case kSMErrorInvalidPlist: return "blessError: kSMErrorInvalidPlist"
|
case kSMErrorInvalidPlist: return "blessError: kSMErrorInvalidPlist"
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -58,6 +58,8 @@ struct SwiftUIView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(alignment:.center) {
|
HStack(alignment:.center) {
|
||||||
Image(nsImage: $viewModel.image.wrappedValue).renderingMode(.template)
|
Image(nsImage: $viewModel.image.wrappedValue).renderingMode(.template)
|
||||||
|
.resizable().aspectRatio(contentMode: .fit).frame(width: 16,height: 16)
|
||||||
|
|
||||||
if $viewModel.showSpeed.wrappedValue {
|
if $viewModel.showSpeed.wrappedValue {
|
||||||
Spacer(minLength: 0)
|
Spacer(minLength: 0)
|
||||||
VStack(alignment: .trailing) {
|
VStack(alignment: .trailing) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#! /usr/bin/python
|
#! /usr/bin/python3
|
||||||
#
|
#
|
||||||
# File: SMJobBlessUtil.py
|
# File: SMJobBlessUtil.py
|
||||||
#
|
#
|
||||||
|
@ -57,6 +57,7 @@ import getopt
|
||||||
import subprocess
|
import subprocess
|
||||||
import plistlib
|
import plistlib
|
||||||
import operator
|
import operator
|
||||||
|
import platform
|
||||||
|
|
||||||
class UsageException (Exception):
|
class UsageException (Exception):
|
||||||
"""
|
"""
|
||||||
|
@ -93,7 +94,7 @@ def checkCodeSignature(programPath, programType):
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
subprocess.check_call(args, stderr=open("/dev/null"))
|
subprocess.check_call(args, stderr=open("/dev/null"))
|
||||||
except subprocess.CalledProcessError, e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise CheckException("%s code signature invalid" % programType, programPath)
|
raise CheckException("%s code signature invalid" % programType, programPath)
|
||||||
|
|
||||||
def readDesignatedRequirement(programPath, programType):
|
def readDesignatedRequirement(programPath, programType):
|
||||||
|
@ -107,8 +108,8 @@ def readDesignatedRequirement(programPath, programType):
|
||||||
programPath
|
programPath
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
req = subprocess.check_output(args, stderr=open("/dev/null"))
|
req = subprocess.check_output(args, stderr=open("/dev/null"), encoding="utf-8")
|
||||||
except subprocess.CalledProcessError, e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise CheckException("%s designated requirement unreadable" % programType, programPath)
|
raise CheckException("%s designated requirement unreadable" % programType, programPath)
|
||||||
|
|
||||||
reqLines = req.splitlines()
|
reqLines = req.splitlines()
|
||||||
|
@ -119,7 +120,8 @@ def readDesignatedRequirement(programPath, programType):
|
||||||
def readInfoPlistFromPath(infoPath):
|
def readInfoPlistFromPath(infoPath):
|
||||||
"""Reads an "Info.plist" file from the specified path."""
|
"""Reads an "Info.plist" file from the specified path."""
|
||||||
try:
|
try:
|
||||||
info = plistlib.readPlist(infoPath)
|
with open(infoPath, 'rb') as fp:
|
||||||
|
info = plistlib.load(fp)
|
||||||
except:
|
except:
|
||||||
raise CheckException("'Info.plist' not readable", infoPath)
|
raise CheckException("'Info.plist' not readable", infoPath)
|
||||||
if not isinstance(info, dict):
|
if not isinstance(info, dict):
|
||||||
|
@ -134,36 +136,55 @@ def readPlistFromToolSection(toolPath, segmentName, sectionName):
|
||||||
args = [
|
args = [
|
||||||
# "false",
|
# "false",
|
||||||
"otool",
|
"otool",
|
||||||
|
"-V",
|
||||||
|
"-arch",
|
||||||
|
platform.machine(),
|
||||||
"-s",
|
"-s",
|
||||||
segmentName,
|
segmentName,
|
||||||
sectionName,
|
sectionName,
|
||||||
toolPath
|
toolPath
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
plistDump = subprocess.check_output(args)
|
plistDump = subprocess.check_output(args, encoding="utf-8")
|
||||||
except subprocess.CalledProcessError, e:
|
except subprocess.CalledProcessError as e:
|
||||||
raise CheckException("tool %s / %s section unreadable" % (segmentName, sectionName), toolPath)
|
raise CheckException("tool %s / %s section unreadable" % (segmentName, sectionName), toolPath)
|
||||||
|
|
||||||
# Convert that hex dump to an property list.
|
# Convert that dump to an property list.
|
||||||
|
|
||||||
plistLines = plistDump.splitlines()
|
plistLines = plistDump.strip().splitlines(keepends=True)
|
||||||
if len(plistLines) < 3 or plistLines[1] != ("Contents of (%s,%s) section" % (segmentName, sectionName)):
|
|
||||||
|
if len(plistLines) < 3:
|
||||||
raise CheckException("tool %s / %s section dump malformed (1)" % (segmentName, sectionName), toolPath)
|
raise CheckException("tool %s / %s section dump malformed (1)" % (segmentName, sectionName), toolPath)
|
||||||
|
|
||||||
|
header = plistLines[1].strip()
|
||||||
|
|
||||||
|
if not header.endswith("(%s,%s) section" % (segmentName, sectionName)):
|
||||||
|
raise CheckException("tool %s / %s section dump malformed (2)" % (segmentName, sectionName), toolPath)
|
||||||
|
|
||||||
del plistLines[0:2]
|
del plistLines[0:2]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bytes = []
|
|
||||||
|
if header.startswith('Contents of'):
|
||||||
|
data = []
|
||||||
for line in plistLines:
|
for line in plistLines:
|
||||||
# line looks like this:
|
# line looks like this:
|
||||||
#
|
#
|
||||||
# '0000000100000b80\t3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 '
|
# '100000000 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 |<?xml version="1|'
|
||||||
columns = line.split("\t")
|
parts = line.split('|')
|
||||||
assert len(columns) == 2
|
assert len(parts) == 3
|
||||||
for hexStr in columns[1].split():
|
columns = parts[0].split()
|
||||||
bytes.append(int(hexStr, 16))
|
assert len(columns) >= 2
|
||||||
plist = plistlib.readPlistFromString(bytearray(bytes))
|
del columns[0]
|
||||||
|
for hexStr in columns:
|
||||||
|
data.append(int(hexStr, 16))
|
||||||
|
data = bytes(data)
|
||||||
|
else:
|
||||||
|
data = bytes("".join(plistLines), encoding="utf-8")
|
||||||
|
|
||||||
|
plist = plistlib.loads(data)
|
||||||
except:
|
except:
|
||||||
raise CheckException("tool %s / %s section dump malformed (2)" % (segmentName, sectionName), toolPath)
|
raise CheckException("tool %s / %s section dump malformed (3)" % (segmentName, sectionName), toolPath)
|
||||||
|
|
||||||
# Check the root of the property list.
|
# Check the root of the property list.
|
||||||
|
|
||||||
|
@ -220,7 +241,7 @@ def checkStep2(appPath, toolPathList):
|
||||||
|
|
||||||
infoPath = os.path.join(appPath, "Contents", "Info.plist")
|
infoPath = os.path.join(appPath, "Contents", "Info.plist")
|
||||||
info = readInfoPlistFromPath(infoPath)
|
info = readInfoPlistFromPath(infoPath)
|
||||||
if not info.has_key("SMPrivilegedExecutables"):
|
if "SMPrivilegedExecutables" not in info:
|
||||||
raise CheckException("'SMPrivilegedExecutables' not found", infoPath)
|
raise CheckException("'SMPrivilegedExecutables' not found", infoPath)
|
||||||
infoToolDict = info["SMPrivilegedExecutables"]
|
infoToolDict = info["SMPrivilegedExecutables"]
|
||||||
if not isinstance(infoToolDict, dict):
|
if not isinstance(infoToolDict, dict):
|
||||||
|
@ -260,13 +281,13 @@ def checkStep3(appPath, toolPathList):
|
||||||
for toolPath in toolPathList:
|
for toolPath in toolPathList:
|
||||||
info = readPlistFromToolSection(toolPath, "__TEXT", "__info_plist")
|
info = readPlistFromToolSection(toolPath, "__TEXT", "__info_plist")
|
||||||
|
|
||||||
if not info.has_key("CFBundleInfoDictionaryVersion") or info["CFBundleInfoDictionaryVersion"] != "6.0":
|
if "CFBundleInfoDictionaryVersion" not in info or info["CFBundleInfoDictionaryVersion"] != "6.0":
|
||||||
raise CheckException("'CFBundleInfoDictionaryVersion' in tool __TEXT / __info_plist section must be '6.0'", toolPath)
|
raise CheckException("'CFBundleInfoDictionaryVersion' in tool __TEXT / __info_plist section must be '6.0'", toolPath)
|
||||||
|
|
||||||
if not info.has_key("CFBundleIdentifier") or info["CFBundleIdentifier"] != os.path.basename(toolPath):
|
if "CFBundleIdentifier" not in info or info["CFBundleIdentifier"] != os.path.basename(toolPath):
|
||||||
raise CheckException("'CFBundleIdentifier' in tool __TEXT / __info_plist section must match tool name", toolPath)
|
raise CheckException("'CFBundleIdentifier' in tool __TEXT / __info_plist section must match tool name", toolPath)
|
||||||
|
|
||||||
if not info.has_key("SMAuthorizedClients"):
|
if "SMAuthorizedClients" not in info:
|
||||||
raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section not found", toolPath)
|
raise CheckException("'SMAuthorizedClients' in tool __TEXT / __info_plist section not found", toolPath)
|
||||||
infoClientList = info["SMAuthorizedClients"]
|
infoClientList = info["SMAuthorizedClients"]
|
||||||
if not isinstance(infoClientList, list):
|
if not isinstance(infoClientList, list):
|
||||||
|
@ -286,7 +307,7 @@ def checkStep4(appPath, toolPathList):
|
||||||
for toolPath in toolPathList:
|
for toolPath in toolPathList:
|
||||||
launchd = readPlistFromToolSection(toolPath, "__TEXT", "__launchd_plist")
|
launchd = readPlistFromToolSection(toolPath, "__TEXT", "__launchd_plist")
|
||||||
|
|
||||||
if not launchd.has_key("Label") or launchd["Label"] != os.path.basename(toolPath):
|
if "Label" not in launchd or launchd["Label"] != os.path.basename(toolPath):
|
||||||
raise CheckException("'Label' in tool __TEXT / __launchd_plist section must match tool name", toolPath)
|
raise CheckException("'Label' in tool __TEXT / __launchd_plist section must match tool name", toolPath)
|
||||||
|
|
||||||
# We don't need to check that the label matches the bundle identifier because
|
# We don't need to check that the label matches the bundle identifier because
|
||||||
|
@ -336,12 +357,8 @@ def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
|
||||||
raise CheckException("tool directory not found", toolDirPath)
|
raise CheckException("tool directory not found", toolDirPath)
|
||||||
|
|
||||||
toolNameToReqMap = {}
|
toolNameToReqMap = {}
|
||||||
print os.listdir(toolDirPath)
|
|
||||||
for toolName in os.listdir(toolDirPath):
|
for toolName in os.listdir(toolDirPath):
|
||||||
req = readDesignatedRequirement(os.path.join(toolDirPath, toolName), "tool")
|
req = readDesignatedRequirement(os.path.join(toolDirPath, toolName), "tool")
|
||||||
print '-----'
|
|
||||||
print toolName
|
|
||||||
print '-----'
|
|
||||||
toolNameToReqMap[toolName] = req
|
toolNameToReqMap[toolName] = req
|
||||||
|
|
||||||
if len(toolNameToReqMap) > len(toolInfoPlistPaths):
|
if len(toolNameToReqMap) > len(toolInfoPlistPaths):
|
||||||
|
@ -356,29 +373,30 @@ def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
|
||||||
for toolInfoPlistPath in toolInfoPlistPaths:
|
for toolInfoPlistPath in toolInfoPlistPaths:
|
||||||
toolInfo = readInfoPlistFromPath(toolInfoPlistPath)
|
toolInfo = readInfoPlistFromPath(toolInfoPlistPath)
|
||||||
toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] = toolInfo
|
toolInfoPlistPathToToolInfoMap[toolInfoPlistPath] = toolInfo
|
||||||
if not toolInfo.has_key("CFBundleIdentifier"):
|
if "CFBundleIdentifier" not in toolInfo:
|
||||||
raise CheckException("'CFBundleIdentifier' not found", toolInfoPlistPath)
|
raise CheckException("'CFBundleIdentifier' not found", toolInfoPlistPath)
|
||||||
bundleID = toolInfo["CFBundleIdentifier"]
|
bundleID = toolInfo["CFBundleIdentifier"]
|
||||||
if not isinstance(bundleID, basestring):
|
if not isinstance(bundleID, str):
|
||||||
raise CheckException("'CFBundleIdentifier' must be a string", toolInfoPlistPath)
|
raise CheckException("'CFBundleIdentifier' must be a string", toolInfoPlistPath)
|
||||||
appToolDict[bundleID] = toolNameToReqMap[bundleID]
|
appToolDict[bundleID] = toolNameToReqMap[bundleID]
|
||||||
|
|
||||||
# Set the SMPrivilegedExecutables value in the app "Info.plist".
|
# Set the SMPrivilegedExecutables value in the app "Info.plist".
|
||||||
|
|
||||||
appInfo = readInfoPlistFromPath(appInfoPlistPath)
|
appInfo = readInfoPlistFromPath(appInfoPlistPath)
|
||||||
needsUpdate = not appInfo.has_key("SMPrivilegedExecutables")
|
needsUpdate = "SMPrivilegedExecutables" not in appInfo
|
||||||
if not needsUpdate:
|
if not needsUpdate:
|
||||||
oldAppToolDict = appInfo["SMPrivilegedExecutables"]
|
oldAppToolDict = appInfo["SMPrivilegedExecutables"]
|
||||||
if not isinstance(oldAppToolDict, dict):
|
if not isinstance(oldAppToolDict, dict):
|
||||||
raise CheckException("'SMPrivilegedExecutables' must be a dictionary", appInfoPlistPath)
|
raise CheckException("'SMPrivilegedExecutables' must be a dictionary", appInfoPlistPath)
|
||||||
appToolDictSorted = sorted(appToolDict.iteritems(), key=operator.itemgetter(0))
|
appToolDictSorted = sorted(appToolDict.items(), key=operator.itemgetter(0))
|
||||||
oldAppToolDictSorted = sorted(oldAppToolDict.iteritems(), key=operator.itemgetter(0))
|
oldAppToolDictSorted = sorted(oldAppToolDict.items(), key=operator.itemgetter(0))
|
||||||
needsUpdate = (appToolDictSorted != oldAppToolDictSorted)
|
needsUpdate = (appToolDictSorted != oldAppToolDictSorted)
|
||||||
|
|
||||||
if needsUpdate:
|
if needsUpdate:
|
||||||
appInfo["SMPrivilegedExecutables"] = appToolDict
|
appInfo["SMPrivilegedExecutables"] = appToolDict
|
||||||
plistlib.writePlist(appInfo, appInfoPlistPath)
|
with open(appInfoPlistPath, 'wb') as fp:
|
||||||
print >> sys.stdout, "%s: updated" % appInfoPlistPath
|
plistlib.dump(appInfo, fp)
|
||||||
|
print ("%s: updated" % appInfoPlistPath, file = sys.stdout)
|
||||||
|
|
||||||
# Set the SMAuthorizedClients value in each tool's "Info.plist".
|
# Set the SMAuthorizedClients value in each tool's "Info.plist".
|
||||||
|
|
||||||
|
@ -386,7 +404,7 @@ def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
|
||||||
for toolInfoPlistPath in toolInfoPlistPaths:
|
for toolInfoPlistPath in toolInfoPlistPaths:
|
||||||
toolInfo = toolInfoPlistPathToToolInfoMap[toolInfoPlistPath]
|
toolInfo = toolInfoPlistPathToToolInfoMap[toolInfoPlistPath]
|
||||||
|
|
||||||
needsUpdate = not toolInfo.has_key("SMAuthorizedClients")
|
needsUpdate = "SMAuthorizedClients" not in toolInfo
|
||||||
if not needsUpdate:
|
if not needsUpdate:
|
||||||
oldToolAppList = toolInfo["SMAuthorizedClients"]
|
oldToolAppList = toolInfo["SMAuthorizedClients"]
|
||||||
if not isinstance(oldToolAppList, list):
|
if not isinstance(oldToolAppList, list):
|
||||||
|
@ -396,8 +414,9 @@ def setreq(appPath, appInfoPlistPath, toolInfoPlistPaths):
|
||||||
|
|
||||||
if needsUpdate:
|
if needsUpdate:
|
||||||
toolInfo["SMAuthorizedClients"] = toolAppListSorted
|
toolInfo["SMAuthorizedClients"] = toolAppListSorted
|
||||||
plistlib.writePlist(toolInfo, toolInfoPlistPath)
|
with open(toolInfoPlistPath, 'wb') as f:
|
||||||
print >> sys.stdout, "%s: updated" % toolInfoPlistPath
|
plistlib.dump(toolInfo, f)
|
||||||
|
print("%s: updated" % toolInfoPlistPath, file = sys.stdout)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
options, appArgs = getopt.getopt(sys.argv[1:], "d")
|
options, appArgs = getopt.getopt(sys.argv[1:], "d")
|
||||||
|
@ -426,16 +445,16 @@ def main():
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
main()
|
main()
|
||||||
except CheckException, e:
|
except CheckException as e:
|
||||||
if e.path is None:
|
if e.path is None:
|
||||||
print >> sys.stderr, "%s: %s" % (os.path.basename(sys.argv[0]), e.message)
|
print("%s: %s" % (os.path.basename(sys.argv[0]), e.message), file = sys.stderr)
|
||||||
else:
|
else:
|
||||||
path = e.path
|
path = e.path
|
||||||
if path.endswith("/"):
|
if path.endswith("/"):
|
||||||
path = path[:-1]
|
path = path[:-1]
|
||||||
print >> sys.stderr, "%s: %s" % (path, e.message)
|
print("%s: %s" % (path, e.message), file = sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except UsageException, e:
|
except UsageException as e:
|
||||||
print >> sys.stderr, "usage: %s check /path/to/app" % os.path.basename(sys.argv[0])
|
print("usage: %s check /path/to/app" % os.path.basename(sys.argv[0]), file = sys.stderr)
|
||||||
print >> sys.stderr, " %s setreq /path/to/app /path/to/app/Info.plist /path/to/tool/Info.plist..." % os.path.basename(sys.argv[0])
|
print(" %s setreq /path/to/app /path/to/app/Info.plist /path/to/tool/Info.plist..." % os.path.basename(sys.argv[0]), file = sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
Loading…
Reference in New Issue