├── .github ├── FUNDING.yml └── workflows │ └── ci-mac.yaml ├── .gitignore ├── .gitmodules ├── Assets ├── Icon.psd ├── menu.png └── window.png ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── ccache.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── ccache.xcscheme └── ccache ├── Classes ├── AboutWindowController.swift ├── AppInstaller.h ├── AppInstaller.m ├── ApplicationDelegate.swift ├── CCache.swift ├── MainViewController.swift ├── NSApplication+LaunchServices.h ├── NSApplication+LaunchServices.m ├── NSView+ccache.swift ├── StatisticItem.swift └── ccache-Bridging-Header.h ├── Info.plist ├── Interface ├── Base.lproj │ ├── MainMenu.xib │ ├── ccache.AboutWindowController.xib │ └── ccache.MainViewController.xib └── Images │ ├── StatusIconTemplate.pdf │ └── ccache.icns └── ccache.entitlements /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: macmade 2 | -------------------------------------------------------------------------------- /.github/workflows/ci-mac.yaml: -------------------------------------------------------------------------------- 1 | name: ci-mac 2 | on: [push] 3 | jobs: 4 | ci: 5 | runs-on: macos-latest 6 | strategy: 7 | matrix: 8 | run-config: 9 | - { scheme: 'ccache', configuration: 'Debug', project: 'ccache.xcodeproj', build: 1, analyze: 1, test: 0, info: 1, destination: 'platform=macOS' } 10 | - { scheme: 'ccache', configuration: 'Release', project: 'ccache.xcodeproj', build: 1, analyze: 1, test: 0, info: 1, destination: 'platform=macOS' } 11 | steps: 12 | 13 | - uses: actions/checkout@v1 14 | with: 15 | submodules: 'recursive' 16 | 17 | - uses: macmade/action-xcodebuild@v1.0.0 18 | 19 | - uses: macmade/action-slack@v1.0.0 20 | if: ${{ always() }} 21 | env: 22 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} 23 | with: 24 | channel: '#ci' 25 | status: ${{ job.status }} 26 | title: ${{ matrix.run-config[ 'scheme' ] }} - ${{ matrix.run-config[ 'configuration' ] }} 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac Finder 2 | .DS_Store 3 | .Trashes 4 | Icon? 5 | 6 | # Thumbnails 7 | ._* 8 | 9 | # Files that might appear on external disk 10 | .Spotlight-V100 11 | .Trashes 12 | 13 | # Xcode 14 | *.pbxuser 15 | *.mode1v3 16 | *.mode2v3 17 | *.perspectivev3 18 | *.xccheckout 19 | *.profraw 20 | !default.pbxuser 21 | !default.mode1v3 22 | !default.mode2v3 23 | !default.perspectivev3 24 | xcuserdata 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Submodules/GitHubUpdates"] 2 | path = Submodules/GitHubUpdates 3 | url = https://github.com/macmade/GitHubUpdates.git 4 | [submodule "Submodules/xcconfig"] 5 | path = Submodules/xcconfig 6 | url = https://github.com/macmade/xcconfig.git 7 | -------------------------------------------------------------------------------- /Assets/Icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macmade/ccache-gui/485ad2e7724649cd11bbdb3c349396f743a6fb8e/Assets/Icon.psd -------------------------------------------------------------------------------- /Assets/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macmade/ccache-gui/485ad2e7724649cd11bbdb3c349396f743a6fb8e/Assets/menu.png -------------------------------------------------------------------------------- /Assets/window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macmade/ccache-gui/485ad2e7724649cd11bbdb3c349396f743a6fb8e/Assets/window.png -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | xs-labs.com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Jean-David Gadina - www.xs-labs.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ccache-gui 2 | ========== 3 | 4 | [![Build Status](https://img.shields.io/github/actions/workflow/status/macmade/ccache-gui/ci-mac.yaml?label=macOS&logo=apple)](https://github.com/macmade/ccache-gui/actions/workflows/ci-mac.yaml) 5 | [![Issues](http://img.shields.io/github/issues/macmade/ccache-gui.svg?logo=github)](https://github.com/macmade/ccache-gui/issues) 6 | ![Status](https://img.shields.io/badge/status-active-brightgreen.svg?logo=git) 7 | ![License](https://img.shields.io/badge/license-mit-brightgreen.svg?logo=open-source-initiative) 8 | [![Contact](https://img.shields.io/badge/follow-@macmade-blue.svg?logo=twitter&style=social)](https://twitter.com/macmade) 9 | [![Sponsor](https://img.shields.io/badge/sponsor-macmade-pink.svg?logo=github-sponsors&style=social)](https://github.com/sponsors/macmade) 10 | 11 | ### About 12 | 13 | GUI helper application for the **[ccache](https://ccache.samba.org)** tool. 14 | 15 | **ccache** can be installed on macOS with **[Homebrew](https://brew.sh)**: 16 | 17 | brew install ccache 18 | 19 | The application run by default in the menu bar, but the window can be detached for convenience. 20 | 21 | ![Menu Item](Assets/menu.png "Menu Item") 22 | ![Detachable Window](Assets/window.png "Detachable Window") 23 | 24 | License 25 | ------- 26 | 27 | Project is released under the terms of the MIT License. 28 | 29 | Repository Infos 30 | ---------------- 31 | 32 | Owner: Jean-David Gadina - XS-Labs 33 | Web: www.xs-labs.com 34 | Blog: www.noxeos.com 35 | Twitter: @macmade 36 | GitHub: github.com/macmade 37 | LinkedIn: ch.linkedin.com/in/macmade/ 38 | StackOverflow: stackoverflow.com/users/182676/macmade 39 | -------------------------------------------------------------------------------- /ccache.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 050B84FA1EB9C90C0090EA12 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 050B84F81EB9C90C0090EA12 /* MainMenu.xib */; }; 11 | 050B85121EB9CEAD0090EA12 /* StatusIconTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 050B85111EB9CEAD0090EA12 /* StatusIconTemplate.pdf */; }; 12 | 052F5F4F1EF6EC2B0036F37E /* StatisticItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052F5F4E1EF6EC2B0036F37E /* StatisticItem.swift */; }; 13 | 052F5F7D1EF6F5240036F37E /* NSView+ccache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052F5F7C1EF6F5240036F37E /* NSView+ccache.swift */; }; 14 | 052F5F7F1EF6FA0E0036F37E /* CCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 052F5F7E1EF6FA0E0036F37E /* CCache.swift */; }; 15 | 053E7BE71EF6DE83004A24C3 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 053E7BE61EF6DE83004A24C3 /* AboutWindowController.swift */; }; 16 | 0555EBBB1EF3EE410016167F /* GitHubUpdates.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0555EBB61EF3EE340016167F /* GitHubUpdates.framework */; }; 17 | 0555EBBC1EF3EE4E0016167F /* GitHubUpdates.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0555EBB61EF3EE340016167F /* GitHubUpdates.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 05765A9F1EBA83C500D2DDDE /* ccache.MainViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05765A9D1EBA83C500D2DDDE /* ccache.MainViewController.xib */; }; 19 | 05765AB81EBB261D00D2DDDE /* ccache.AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 05765AB61EBB261D00D2DDDE /* ccache.AboutWindowController.xib */; }; 20 | 05765B101EBB99D300D2DDDE /* ccache.icns in Resources */ = {isa = PBXBuildFile; fileRef = 05765B0F1EBB99D300D2DDDE /* ccache.icns */; }; 21 | 059B3B6A1ECE28FF00D5013A /* AppInstaller.m in Sources */ = {isa = PBXBuildFile; fileRef = 059B3B691ECE28FF00D5013A /* AppInstaller.m */; }; 22 | 059B3B7E1ECE2CC500D5013A /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 059B3B7D1ECE2CC500D5013A /* Security.framework */; }; 23 | 05A364F01EC23007003A93EF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A364EF1EC23007003A93EF /* Cocoa.framework */; }; 24 | 05B9275A1EF84866004B9D71 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B927591EF84865004B9D71 /* ApplicationDelegate.swift */; }; 25 | 05B9277B1EF85CFC004B9D71 /* NSApplication+LaunchServices.m in Sources */ = {isa = PBXBuildFile; fileRef = 05765B8F1EBBBE5E00D2DDDE /* NSApplication+LaunchServices.m */; }; 26 | 05D7822A1EF70D000076B14D /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05D782291EF70D000076B14D /* MainViewController.swift */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 0555EBB51EF3EE340016167F /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */; 33 | proxyType = 2; 34 | remoteGlobalIDString = 05F82B251EF32EA700EC8A93; 35 | remoteInfo = GitHubUpdates; 36 | }; 37 | 0555EBB71EF3EE340016167F /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */; 40 | proxyType = 2; 41 | remoteGlobalIDString = 0555EBA01EF3DDA10016167F; 42 | remoteInfo = Relauncher; 43 | }; 44 | 0555EBB91EF3EE3D0016167F /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */; 47 | proxyType = 1; 48 | remoteGlobalIDString = 05F82B241EF32EA700EC8A93; 49 | remoteInfo = GitHubUpdates; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXCopyFilesBuildPhase section */ 54 | 05765B311EBBA6DF00D2DDDE /* CopyFiles */ = { 55 | isa = PBXCopyFilesBuildPhase; 56 | buildActionMask = 2147483647; 57 | dstPath = ""; 58 | dstSubfolderSpec = 10; 59 | files = ( 60 | 0555EBBC1EF3EE4E0016167F /* GitHubUpdates.framework in CopyFiles */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXCopyFilesBuildPhase section */ 65 | 66 | /* Begin PBXFileReference section */ 67 | 050B84C91EB93FF90090EA12 /* ccache.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ccache.app; sourceTree = BUILT_PRODUCTS_DIR; }; 68 | 050B84DA1EB93FF90090EA12 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 050B84F91EB9C90C0090EA12 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 70 | 050B85111EB9CEAD0090EA12 /* StatusIconTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = StatusIconTemplate.pdf; sourceTree = ""; }; 71 | 052F5F4E1EF6EC2B0036F37E /* StatisticItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatisticItem.swift; sourceTree = ""; }; 72 | 052F5F7C1EF6F5240036F37E /* NSView+ccache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+ccache.swift"; sourceTree = ""; }; 73 | 052F5F7E1EF6FA0E0036F37E /* CCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCache.swift; sourceTree = ""; }; 74 | 053E7BE51EF6DE83004A24C3 /* ccache-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ccache-Bridging-Header.h"; sourceTree = ""; }; 75 | 053E7BE61EF6DE83004A24C3 /* AboutWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = ""; }; 76 | 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GitHubUpdates.xcodeproj; path = Submodules/GitHubUpdates/GitHubUpdates.xcodeproj; sourceTree = ""; }; 77 | 05765A9E1EBA83C500D2DDDE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ccache.MainViewController.xib; sourceTree = ""; }; 78 | 05765AB71EBB261D00D2DDDE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ccache.AboutWindowController.xib; sourceTree = ""; }; 79 | 05765B0F1EBB99D300D2DDDE /* ccache.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = ccache.icns; sourceTree = ""; }; 80 | 05765B8E1EBBBE5E00D2DDDE /* NSApplication+LaunchServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSApplication+LaunchServices.h"; sourceTree = ""; }; 81 | 05765B8F1EBBBE5E00D2DDDE /* NSApplication+LaunchServices.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplication+LaunchServices.m"; sourceTree = ""; }; 82 | 0599CFDB21419474009930E6 /* ccache.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ccache.entitlements; sourceTree = ""; }; 83 | 059B3B681ECE28FF00D5013A /* AppInstaller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppInstaller.h; sourceTree = ""; }; 84 | 059B3B691ECE28FF00D5013A /* AppInstaller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppInstaller.m; sourceTree = ""; }; 85 | 059B3B7D1ECE2CC500D5013A /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 86 | 05A364EF1EC23007003A93EF /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 87 | 05A364F31EC23072003A93EF /* ccache-config.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "ccache-config.sh"; sourceTree = ""; }; 88 | 05A364F41EC23072003A93EF /* ccache.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = ccache.sh; sourceTree = ""; }; 89 | 05B927591EF84865004B9D71 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = ""; }; 90 | 05C83D9B2141797C00A9ED6D /* Release - ccache.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Release - ccache.xcconfig"; sourceTree = ""; }; 91 | 05C83D9C2141797C00A9ED6D /* Common.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Common.xcconfig; sourceTree = ""; }; 92 | 05C83D9D2141797C00A9ED6D /* Debug - ccache.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Debug - ccache.xcconfig"; sourceTree = ""; }; 93 | 05C83D9E2141797C00A9ED6D /* Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 94 | 05C83D9F2141797C00A9ED6D /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 95 | 05C83DA02141797C00A9ED6D /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 96 | 05C83DA22141797C00A9ED6D /* Signing.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Signing.xcconfig; sourceTree = ""; }; 97 | 05C83DA32141797C00A9ED6D /* Architectures.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Architectures.xcconfig; sourceTree = ""; }; 98 | 05C83DA52141797C00A9ED6D /* Issues.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Issues.xcconfig; sourceTree = ""; }; 99 | 05C83DA72141797C00A9ED6D /* Apple-APIs.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apple-APIs.xcconfig"; sourceTree = ""; }; 100 | 05C83DA82141797C00A9ED6D /* Generic-Issues.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Generic-Issues.xcconfig"; sourceTree = ""; }; 101 | 05C83DA92141797C00A9ED6D /* Security.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Security.xcconfig; sourceTree = ""; }; 102 | 05C83DAA2141797C00A9ED6D /* Objective-C.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Objective-C.xcconfig"; sourceTree = ""; }; 103 | 05C83DAB2141797C00A9ED6D /* Analysis-Policy.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Analysis-Policy.xcconfig"; sourceTree = ""; }; 104 | 05C83DAC2141797C00A9ED6D /* Deployment.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Deployment.xcconfig; sourceTree = ""; }; 105 | 05C83DAD2141797C00A9ED6D /* Build-Options.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Build-Options.xcconfig"; sourceTree = ""; }; 106 | 05C83DAE2141797C00A9ED6D /* Swift-Compiler.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Swift-Compiler.xcconfig"; sourceTree = ""; }; 107 | 05C83DAF2141797C00A9ED6D /* Static-Analyzer.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Static-Analyzer.xcconfig"; sourceTree = ""; }; 108 | 05C83DB12141797C00A9ED6D /* Warnings-Policies.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Warnings-Policies.xcconfig"; sourceTree = ""; }; 109 | 05C83DB22141797C00A9ED6D /* Code-Generation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Code-Generation.xcconfig"; sourceTree = ""; }; 110 | 05C83DB32141797C00A9ED6D /* Language.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Language.xcconfig; sourceTree = ""; }; 111 | 05C83DB42141797C00A9ED6D /* General.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; 112 | 05C83DB52141797C00A9ED6D /* Search-Paths.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Search-Paths.xcconfig"; sourceTree = ""; }; 113 | 05C83DB62141797C00A9ED6D /* Apple-LLVM.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Apple-LLVM.xcconfig"; sourceTree = ""; }; 114 | 05C83DB92141797C00A9ED6D /* Modules.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Modules.xcconfig; sourceTree = ""; }; 115 | 05C83DBA2141797C00A9ED6D /* Objective-C.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Objective-C.xcconfig"; sourceTree = ""; }; 116 | 05C83DBB2141797C00A9ED6D /* C++.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "C++.xcconfig"; sourceTree = ""; }; 117 | 05C83DBC2141797C00A9ED6D /* Code-Generation.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Code-Generation.xcconfig"; sourceTree = ""; }; 118 | 05C83DBD2141797C00A9ED6D /* Address-Sanitizer.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Address-Sanitizer.xcconfig"; sourceTree = ""; }; 119 | 05C83DBE2141797C00A9ED6D /* Language.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Language.xcconfig; sourceTree = ""; }; 120 | 05C83DBF2141797C00A9ED6D /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 121 | 05C83DC02141797C00A9ED6D /* Undefined-Behavior-Sanitizer.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Undefined-Behavior-Sanitizer.xcconfig"; sourceTree = ""; }; 122 | 05C83DC12141797C00A9ED6D /* Warning-Policies.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Warning-Policies.xcconfig"; sourceTree = ""; }; 123 | 05C83DC32141797C00A9ED6D /* Objective-C-ARC.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Objective-C-ARC.xcconfig"; sourceTree = ""; }; 124 | 05C83DC42141797C00A9ED6D /* Objective-C.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Objective-C.xcconfig"; sourceTree = ""; }; 125 | 05C83DC52141797C00A9ED6D /* C++.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "C++.xcconfig"; sourceTree = ""; }; 126 | 05C83DC62141797C00A9ED6D /* All-Languages.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "All-Languages.xcconfig"; sourceTree = ""; }; 127 | 05C83DC72141797C00A9ED6D /* Preprocessing.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Preprocessing.xcconfig; sourceTree = ""; }; 128 | 05C83DC82141797C00A9ED6D /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; 129 | 05C83DCA2141797C00A9ED6D /* ccache-config.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "ccache-config.sh"; sourceTree = ""; }; 130 | 05C83DCB2141797C00A9ED6D /* ccache.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ccache.sh; sourceTree = ""; }; 131 | 05D782291EF70D000076B14D /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 132 | /* End PBXFileReference section */ 133 | 134 | /* Begin PBXFrameworksBuildPhase section */ 135 | 050B84C61EB93FF90090EA12 /* Frameworks */ = { 136 | isa = PBXFrameworksBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 0555EBBB1EF3EE410016167F /* GitHubUpdates.framework in Frameworks */, 140 | 059B3B7E1ECE2CC500D5013A /* Security.framework in Frameworks */, 141 | 05A364F01EC23007003A93EF /* Cocoa.framework in Frameworks */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXFrameworksBuildPhase section */ 146 | 147 | /* Begin PBXGroup section */ 148 | 050B84C01EB93FF90090EA12 = { 149 | isa = PBXGroup; 150 | children = ( 151 | 05C83D9A2141797C00A9ED6D /* xcconfig */, 152 | 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */, 153 | 050B84CB1EB93FF90090EA12 /* ccache */, 154 | 05A364EE1EC23007003A93EF /* Frameworks */, 155 | 050B84CA1EB93FF90090EA12 /* Products */, 156 | 05A364F11EC23072003A93EF /* Scripts */, 157 | ); 158 | sourceTree = ""; 159 | }; 160 | 050B84CA1EB93FF90090EA12 /* Products */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 050B84C91EB93FF90090EA12 /* ccache.app */, 164 | ); 165 | name = Products; 166 | sourceTree = ""; 167 | }; 168 | 050B84CB1EB93FF90090EA12 /* ccache */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 050B84E11EB9C8120090EA12 /* Classes */, 172 | 050B84E01EB9C8070090EA12 /* Interface */, 173 | 050B84CF1EB93FF90090EA12 /* Supporting Files */, 174 | ); 175 | path = ccache; 176 | sourceTree = ""; 177 | }; 178 | 050B84CF1EB93FF90090EA12 /* Supporting Files */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 0599CFDB21419474009930E6 /* ccache.entitlements */, 182 | 050B84DA1EB93FF90090EA12 /* Info.plist */, 183 | ); 184 | name = "Supporting Files"; 185 | sourceTree = ""; 186 | }; 187 | 050B84E01EB9C8070090EA12 /* Interface */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 05765AB61EBB261D00D2DDDE /* ccache.AboutWindowController.xib */, 191 | 050B84FB1EB9CCD60090EA12 /* Images */, 192 | 050B84F81EB9C90C0090EA12 /* MainMenu.xib */, 193 | 05765A9D1EBA83C500D2DDDE /* ccache.MainViewController.xib */, 194 | ); 195 | path = Interface; 196 | sourceTree = ""; 197 | }; 198 | 050B84E11EB9C8120090EA12 /* Classes */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 053E7BE61EF6DE83004A24C3 /* AboutWindowController.swift */, 202 | 059B3B681ECE28FF00D5013A /* AppInstaller.h */, 203 | 059B3B691ECE28FF00D5013A /* AppInstaller.m */, 204 | 05B927591EF84865004B9D71 /* ApplicationDelegate.swift */, 205 | 052F5F7E1EF6FA0E0036F37E /* CCache.swift */, 206 | 05D782291EF70D000076B14D /* MainViewController.swift */, 207 | 05765B8E1EBBBE5E00D2DDDE /* NSApplication+LaunchServices.h */, 208 | 05765B8F1EBBBE5E00D2DDDE /* NSApplication+LaunchServices.m */, 209 | 052F5F7C1EF6F5240036F37E /* NSView+ccache.swift */, 210 | 052F5F4E1EF6EC2B0036F37E /* StatisticItem.swift */, 211 | 053E7BE51EF6DE83004A24C3 /* ccache-Bridging-Header.h */, 212 | ); 213 | path = Classes; 214 | sourceTree = ""; 215 | }; 216 | 050B84FB1EB9CCD60090EA12 /* Images */ = { 217 | isa = PBXGroup; 218 | children = ( 219 | 05765B0F1EBB99D300D2DDDE /* ccache.icns */, 220 | 050B85111EB9CEAD0090EA12 /* StatusIconTemplate.pdf */, 221 | ); 222 | path = Images; 223 | sourceTree = ""; 224 | }; 225 | 0555EBB11EF3EE340016167F /* Products */ = { 226 | isa = PBXGroup; 227 | children = ( 228 | 0555EBB61EF3EE340016167F /* GitHubUpdates.framework */, 229 | 0555EBB81EF3EE340016167F /* Relauncher */, 230 | ); 231 | name = Products; 232 | sourceTree = ""; 233 | }; 234 | 05A364EE1EC23007003A93EF /* Frameworks */ = { 235 | isa = PBXGroup; 236 | children = ( 237 | 059B3B7D1ECE2CC500D5013A /* Security.framework */, 238 | 05A364EF1EC23007003A93EF /* Cocoa.framework */, 239 | ); 240 | name = Frameworks; 241 | sourceTree = ""; 242 | }; 243 | 05A364F11EC23072003A93EF /* Scripts */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 05A364F31EC23072003A93EF /* ccache-config.sh */, 247 | 05A364F41EC23072003A93EF /* ccache.sh */, 248 | ); 249 | path = Scripts; 250 | sourceTree = ""; 251 | }; 252 | 05C83D9A2141797C00A9ED6D /* xcconfig */ = { 253 | isa = PBXGroup; 254 | children = ( 255 | 05C83D9B2141797C00A9ED6D /* Release - ccache.xcconfig */, 256 | 05C83D9C2141797C00A9ED6D /* Common.xcconfig */, 257 | 05C83D9D2141797C00A9ED6D /* Debug - ccache.xcconfig */, 258 | 05C83D9E2141797C00A9ED6D /* Debug.xcconfig */, 259 | 05C83D9F2141797C00A9ED6D /* Release.xcconfig */, 260 | 05C83DA02141797C00A9ED6D /* README.md */, 261 | 05C83DA12141797C00A9ED6D /* Common */, 262 | 05C83DC82141797C00A9ED6D /* .gitignore */, 263 | 05C83DC92141797C00A9ED6D /* Scripts */, 264 | ); 265 | name = xcconfig; 266 | path = Submodules/xcconfig; 267 | sourceTree = ""; 268 | }; 269 | 05C83DA12141797C00A9ED6D /* Common */ = { 270 | isa = PBXGroup; 271 | children = ( 272 | 05C83DA22141797C00A9ED6D /* Signing.xcconfig */, 273 | 05C83DA32141797C00A9ED6D /* Architectures.xcconfig */, 274 | 05C83DA42141797C00A9ED6D /* Static-Analyzer */, 275 | 05C83DAC2141797C00A9ED6D /* Deployment.xcconfig */, 276 | 05C83DAD2141797C00A9ED6D /* Build-Options.xcconfig */, 277 | 05C83DAE2141797C00A9ED6D /* Swift-Compiler.xcconfig */, 278 | 05C83DAF2141797C00A9ED6D /* Static-Analyzer.xcconfig */, 279 | 05C83DB02141797C00A9ED6D /* Swift-Compiler */, 280 | 05C83DB52141797C00A9ED6D /* Search-Paths.xcconfig */, 281 | 05C83DB62141797C00A9ED6D /* Apple-LLVM.xcconfig */, 282 | 05C83DB72141797C00A9ED6D /* Apple-LLVM */, 283 | ); 284 | path = Common; 285 | sourceTree = ""; 286 | }; 287 | 05C83DA42141797C00A9ED6D /* Static-Analyzer */ = { 288 | isa = PBXGroup; 289 | children = ( 290 | 05C83DA52141797C00A9ED6D /* Issues.xcconfig */, 291 | 05C83DA62141797C00A9ED6D /* Issues */, 292 | ); 293 | path = "Static-Analyzer"; 294 | sourceTree = ""; 295 | }; 296 | 05C83DA62141797C00A9ED6D /* Issues */ = { 297 | isa = PBXGroup; 298 | children = ( 299 | 05C83DA72141797C00A9ED6D /* Apple-APIs.xcconfig */, 300 | 05C83DA82141797C00A9ED6D /* Generic-Issues.xcconfig */, 301 | 05C83DA92141797C00A9ED6D /* Security.xcconfig */, 302 | 05C83DAA2141797C00A9ED6D /* Objective-C.xcconfig */, 303 | 05C83DAB2141797C00A9ED6D /* Analysis-Policy.xcconfig */, 304 | ); 305 | path = Issues; 306 | sourceTree = ""; 307 | }; 308 | 05C83DB02141797C00A9ED6D /* Swift-Compiler */ = { 309 | isa = PBXGroup; 310 | children = ( 311 | 05C83DB12141797C00A9ED6D /* Warnings-Policies.xcconfig */, 312 | 05C83DB22141797C00A9ED6D /* Code-Generation.xcconfig */, 313 | 05C83DB32141797C00A9ED6D /* Language.xcconfig */, 314 | 05C83DB42141797C00A9ED6D /* General.xcconfig */, 315 | ); 316 | path = "Swift-Compiler"; 317 | sourceTree = ""; 318 | }; 319 | 05C83DB72141797C00A9ED6D /* Apple-LLVM */ = { 320 | isa = PBXGroup; 321 | children = ( 322 | 05C83DB82141797C00A9ED6D /* Language */, 323 | 05C83DBC2141797C00A9ED6D /* Code-Generation.xcconfig */, 324 | 05C83DBD2141797C00A9ED6D /* Address-Sanitizer.xcconfig */, 325 | 05C83DBE2141797C00A9ED6D /* Language.xcconfig */, 326 | 05C83DBF2141797C00A9ED6D /* Warnings.xcconfig */, 327 | 05C83DC02141797C00A9ED6D /* Undefined-Behavior-Sanitizer.xcconfig */, 328 | 05C83DC12141797C00A9ED6D /* Warning-Policies.xcconfig */, 329 | 05C83DC22141797C00A9ED6D /* Warnings */, 330 | 05C83DC72141797C00A9ED6D /* Preprocessing.xcconfig */, 331 | ); 332 | path = "Apple-LLVM"; 333 | sourceTree = ""; 334 | }; 335 | 05C83DB82141797C00A9ED6D /* Language */ = { 336 | isa = PBXGroup; 337 | children = ( 338 | 05C83DB92141797C00A9ED6D /* Modules.xcconfig */, 339 | 05C83DBA2141797C00A9ED6D /* Objective-C.xcconfig */, 340 | 05C83DBB2141797C00A9ED6D /* C++.xcconfig */, 341 | ); 342 | path = Language; 343 | sourceTree = ""; 344 | }; 345 | 05C83DC22141797C00A9ED6D /* Warnings */ = { 346 | isa = PBXGroup; 347 | children = ( 348 | 05C83DC32141797C00A9ED6D /* Objective-C-ARC.xcconfig */, 349 | 05C83DC42141797C00A9ED6D /* Objective-C.xcconfig */, 350 | 05C83DC52141797C00A9ED6D /* C++.xcconfig */, 351 | 05C83DC62141797C00A9ED6D /* All-Languages.xcconfig */, 352 | ); 353 | path = Warnings; 354 | sourceTree = ""; 355 | }; 356 | 05C83DC92141797C00A9ED6D /* Scripts */ = { 357 | isa = PBXGroup; 358 | children = ( 359 | 05C83DCA2141797C00A9ED6D /* ccache-config.sh */, 360 | 05C83DCB2141797C00A9ED6D /* ccache.sh */, 361 | ); 362 | path = Scripts; 363 | sourceTree = ""; 364 | }; 365 | /* End PBXGroup section */ 366 | 367 | /* Begin PBXNativeTarget section */ 368 | 050B84C81EB93FF90090EA12 /* ccache */ = { 369 | isa = PBXNativeTarget; 370 | buildConfigurationList = 050B84DD1EB93FF90090EA12 /* Build configuration list for PBXNativeTarget "ccache" */; 371 | buildPhases = ( 372 | 050B84C51EB93FF90090EA12 /* Sources */, 373 | 050B84C61EB93FF90090EA12 /* Frameworks */, 374 | 0555EBBE1EF3F0440016167F /* ShellScript */, 375 | 050B84C71EB93FF90090EA12 /* Resources */, 376 | 05765B311EBBA6DF00D2DDDE /* CopyFiles */, 377 | ); 378 | buildRules = ( 379 | ); 380 | dependencies = ( 381 | 0555EBBA1EF3EE3D0016167F /* PBXTargetDependency */, 382 | ); 383 | name = ccache; 384 | productName = ccache; 385 | productReference = 050B84C91EB93FF90090EA12 /* ccache.app */; 386 | productType = "com.apple.product-type.application"; 387 | }; 388 | /* End PBXNativeTarget section */ 389 | 390 | /* Begin PBXProject section */ 391 | 050B84C11EB93FF90090EA12 /* Project object */ = { 392 | isa = PBXProject; 393 | attributes = { 394 | LastUpgradeCheck = 1220; 395 | ORGANIZATIONNAME = "XS-Labs"; 396 | TargetAttributes = { 397 | 050B84C81EB93FF90090EA12 = { 398 | CreatedOnToolsVersion = 8.3.1; 399 | DevelopmentTeam = 326Y53CJMD; 400 | LastSwiftMigration = 0900; 401 | ProvisioningStyle = Automatic; 402 | SystemCapabilities = { 403 | com.apple.HardenedRuntime = { 404 | enabled = 1; 405 | }; 406 | }; 407 | }; 408 | }; 409 | }; 410 | buildConfigurationList = 050B84C41EB93FF90090EA12 /* Build configuration list for PBXProject "ccache" */; 411 | compatibilityVersion = "Xcode 3.2"; 412 | developmentRegion = en; 413 | hasScannedForEncodings = 0; 414 | knownRegions = ( 415 | en, 416 | Base, 417 | ); 418 | mainGroup = 050B84C01EB93FF90090EA12; 419 | productRefGroup = 050B84CA1EB93FF90090EA12 /* Products */; 420 | projectDirPath = ""; 421 | projectReferences = ( 422 | { 423 | ProductGroup = 0555EBB11EF3EE340016167F /* Products */; 424 | ProjectRef = 0555EBB01EF3EE340016167F /* GitHubUpdates.xcodeproj */; 425 | }, 426 | ); 427 | projectRoot = ""; 428 | targets = ( 429 | 050B84C81EB93FF90090EA12 /* ccache */, 430 | ); 431 | }; 432 | /* End PBXProject section */ 433 | 434 | /* Begin PBXReferenceProxy section */ 435 | 0555EBB61EF3EE340016167F /* GitHubUpdates.framework */ = { 436 | isa = PBXReferenceProxy; 437 | fileType = wrapper.framework; 438 | path = GitHubUpdates.framework; 439 | remoteRef = 0555EBB51EF3EE340016167F /* PBXContainerItemProxy */; 440 | sourceTree = BUILT_PRODUCTS_DIR; 441 | }; 442 | 0555EBB81EF3EE340016167F /* Relauncher */ = { 443 | isa = PBXReferenceProxy; 444 | fileType = "compiled.mach-o.executable"; 445 | path = Relauncher; 446 | remoteRef = 0555EBB71EF3EE340016167F /* PBXContainerItemProxy */; 447 | sourceTree = BUILT_PRODUCTS_DIR; 448 | }; 449 | /* End PBXReferenceProxy section */ 450 | 451 | /* Begin PBXResourcesBuildPhase section */ 452 | 050B84C71EB93FF90090EA12 /* Resources */ = { 453 | isa = PBXResourcesBuildPhase; 454 | buildActionMask = 2147483647; 455 | files = ( 456 | 050B85121EB9CEAD0090EA12 /* StatusIconTemplate.pdf in Resources */, 457 | 05765AB81EBB261D00D2DDDE /* ccache.AboutWindowController.xib in Resources */, 458 | 05765B101EBB99D300D2DDDE /* ccache.icns in Resources */, 459 | 05765A9F1EBA83C500D2DDDE /* ccache.MainViewController.xib in Resources */, 460 | 050B84FA1EB9C90C0090EA12 /* MainMenu.xib in Resources */, 461 | ); 462 | runOnlyForDeploymentPostprocessing = 0; 463 | }; 464 | /* End PBXResourcesBuildPhase section */ 465 | 466 | /* Begin PBXShellScriptBuildPhase section */ 467 | 0555EBBE1EF3F0440016167F /* ShellScript */ = { 468 | isa = PBXShellScriptBuildPhase; 469 | buildActionMask = 2147483647; 470 | files = ( 471 | ); 472 | inputPaths = ( 473 | ); 474 | outputPaths = ( 475 | ); 476 | runOnlyForDeploymentPostprocessing = 0; 477 | shellPath = /bin/sh; 478 | shellScript = "#!/bin/bash\nif [ \"${CONFIGURATION}\" = \"Release\" ]; then\n plist=\"ccache/Info.plist\"\n rev=$(git rev-list `git branch | grep -e \"^*\" | cut -d' ' -f 2` | wc -l)\n /usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $rev\" \"$plist\"\nfi"; 479 | }; 480 | /* End PBXShellScriptBuildPhase section */ 481 | 482 | /* Begin PBXSourcesBuildPhase section */ 483 | 050B84C51EB93FF90090EA12 /* Sources */ = { 484 | isa = PBXSourcesBuildPhase; 485 | buildActionMask = 2147483647; 486 | files = ( 487 | 05B9277B1EF85CFC004B9D71 /* NSApplication+LaunchServices.m in Sources */, 488 | 053E7BE71EF6DE83004A24C3 /* AboutWindowController.swift in Sources */, 489 | 052F5F4F1EF6EC2B0036F37E /* StatisticItem.swift in Sources */, 490 | 059B3B6A1ECE28FF00D5013A /* AppInstaller.m in Sources */, 491 | 052F5F7F1EF6FA0E0036F37E /* CCache.swift in Sources */, 492 | 05B9275A1EF84866004B9D71 /* ApplicationDelegate.swift in Sources */, 493 | 052F5F7D1EF6F5240036F37E /* NSView+ccache.swift in Sources */, 494 | 05D7822A1EF70D000076B14D /* MainViewController.swift in Sources */, 495 | ); 496 | runOnlyForDeploymentPostprocessing = 0; 497 | }; 498 | /* End PBXSourcesBuildPhase section */ 499 | 500 | /* Begin PBXTargetDependency section */ 501 | 0555EBBA1EF3EE3D0016167F /* PBXTargetDependency */ = { 502 | isa = PBXTargetDependency; 503 | name = GitHubUpdates; 504 | targetProxy = 0555EBB91EF3EE3D0016167F /* PBXContainerItemProxy */; 505 | }; 506 | /* End PBXTargetDependency section */ 507 | 508 | /* Begin PBXVariantGroup section */ 509 | 050B84F81EB9C90C0090EA12 /* MainMenu.xib */ = { 510 | isa = PBXVariantGroup; 511 | children = ( 512 | 050B84F91EB9C90C0090EA12 /* Base */, 513 | ); 514 | name = MainMenu.xib; 515 | sourceTree = ""; 516 | }; 517 | 05765A9D1EBA83C500D2DDDE /* ccache.MainViewController.xib */ = { 518 | isa = PBXVariantGroup; 519 | children = ( 520 | 05765A9E1EBA83C500D2DDDE /* Base */, 521 | ); 522 | name = ccache.MainViewController.xib; 523 | sourceTree = ""; 524 | }; 525 | 05765AB61EBB261D00D2DDDE /* ccache.AboutWindowController.xib */ = { 526 | isa = PBXVariantGroup; 527 | children = ( 528 | 05765AB71EBB261D00D2DDDE /* Base */, 529 | ); 530 | name = ccache.AboutWindowController.xib; 531 | sourceTree = ""; 532 | }; 533 | /* End PBXVariantGroup section */ 534 | 535 | /* Begin XCBuildConfiguration section */ 536 | 050B84DB1EB93FF90090EA12 /* Debug */ = { 537 | isa = XCBuildConfiguration; 538 | baseConfigurationReference = 05C83D9E2141797C00A9ED6D /* Debug.xcconfig */; 539 | buildSettings = { 540 | MACOSX_DEPLOYMENT_TARGET = 10.12; 541 | }; 542 | name = Debug; 543 | }; 544 | 050B84DC1EB93FF90090EA12 /* Release */ = { 545 | isa = XCBuildConfiguration; 546 | baseConfigurationReference = 05C83D9F2141797C00A9ED6D /* Release.xcconfig */; 547 | buildSettings = { 548 | MACOSX_DEPLOYMENT_TARGET = 10.12; 549 | }; 550 | name = Release; 551 | }; 552 | 050B84DE1EB93FF90090EA12 /* Debug */ = { 553 | isa = XCBuildConfiguration; 554 | buildSettings = { 555 | CLANG_ENABLE_MODULES = YES; 556 | INFOPLIST_FILE = ccache/Info.plist; 557 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 558 | PRODUCT_BUNDLE_IDENTIFIER = "com.xs-labs.ccache"; 559 | PRODUCT_NAME = "$(TARGET_NAME)"; 560 | SWIFT_OBJC_BRIDGING_HEADER = "ccache/Classes/ccache-Bridging-Header.h"; 561 | }; 562 | name = Debug; 563 | }; 564 | 050B84DF1EB93FF90090EA12 /* Release */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | CLANG_ENABLE_MODULES = YES; 568 | INFOPLIST_FILE = ccache/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 570 | PRODUCT_BUNDLE_IDENTIFIER = "com.xs-labs.ccache"; 571 | PRODUCT_NAME = "$(TARGET_NAME)"; 572 | SWIFT_OBJC_BRIDGING_HEADER = "ccache/Classes/ccache-Bridging-Header.h"; 573 | }; 574 | name = Release; 575 | }; 576 | /* End XCBuildConfiguration section */ 577 | 578 | /* Begin XCConfigurationList section */ 579 | 050B84C41EB93FF90090EA12 /* Build configuration list for PBXProject "ccache" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 050B84DB1EB93FF90090EA12 /* Debug */, 583 | 050B84DC1EB93FF90090EA12 /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | defaultConfigurationName = Release; 587 | }; 588 | 050B84DD1EB93FF90090EA12 /* Build configuration list for PBXNativeTarget "ccache" */ = { 589 | isa = XCConfigurationList; 590 | buildConfigurations = ( 591 | 050B84DE1EB93FF90090EA12 /* Debug */, 592 | 050B84DF1EB93FF90090EA12 /* Release */, 593 | ); 594 | defaultConfigurationIsVisible = 0; 595 | defaultConfigurationName = Release; 596 | }; 597 | /* End XCConfigurationList section */ 598 | }; 599 | rootObject = 050B84C11EB93FF90090EA12 /* Project object */; 600 | } 601 | -------------------------------------------------------------------------------- /ccache.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ccache.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ccache.xcodeproj/xcshareddata/xcschemes/ccache.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 58 | 60 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ccache/Classes/AboutWindowController.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Cocoa 26 | 27 | public class AboutWindowController: NSWindowController 28 | { 29 | @objc private dynamic var name: String? 30 | @objc private dynamic var version: String? 31 | @objc private dynamic var copyright: String? 32 | 33 | public override var windowNibName: NSNib.Name? 34 | { 35 | NSNib.Name( NSStringFromClass( type( of: self ) ) ) 36 | } 37 | 38 | override public func windowDidLoad() 39 | { 40 | super.windowDidLoad() 41 | 42 | let version = Bundle.main.object( forInfoDictionaryKey: "CFBundleShortVersionString" ) as? String ?? "0.0.0" 43 | 44 | if let build = Bundle.main.object( forInfoDictionaryKey: "CFBundleVersion" ) as? String 45 | { 46 | self.version = "\(version) (\(build))" 47 | } 48 | else 49 | { 50 | self.version = version 51 | } 52 | 53 | self.name = Bundle.main.object( forInfoDictionaryKey: "CFBundleName" ) as? String 54 | self.copyright = Bundle.main.object( forInfoDictionaryKey: "NSHumanReadableCopyright" ) as? String 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ccache/Classes/AppInstaller.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www-xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | @import Cocoa; 26 | 27 | NS_ASSUME_NONNULL_BEGIN 28 | 29 | typedef NS_ENUM( NSInteger, AppInstallerStatus ) 30 | { 31 | AppInstallerStatusNoInstallNecessary = 0x00, 32 | AppInstallerStatusInstallSucessfull = 0x01, 33 | AppInstallerStatusInstallError = 0x02 34 | }; 35 | 36 | @interface AppInstaller: NSObject 37 | 38 | + ( AppInstallerStatus )installIfNecessary; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /ccache/Classes/AppInstaller.m: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www-xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | #import "AppInstaller.h" 26 | 27 | static NSString * const AlertSuppressKey = @"AppInstallerAlertSuppressKey"; 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface AppInstaller() 32 | 33 | + ( BOOL )isInApplicationsFolder; 34 | + ( BOOL )isInDMG; 35 | + ( BOOL )isWriteable; 36 | + ( nullable NSString * )installPath; 37 | + ( BOOL )moveToTrash: ( NSString * )path; 38 | + ( void )displayError; 39 | + ( NSString * )appName; 40 | 41 | @end 42 | 43 | NS_ASSUME_NONNULL_END 44 | 45 | @implementation AppInstaller 46 | 47 | + ( AppInstallerStatus )installIfNecessary 48 | { 49 | NSString * installDir; 50 | NSString * installPath; 51 | 52 | /* Don't show again */ 53 | if( [ [ NSUserDefaults standardUserDefaults ] boolForKey: AlertSuppressKey ] && [ AppInstaller isInDMG ] == NO ) 54 | { 55 | return AppInstallerStatusNoInstallNecessary; 56 | } 57 | 58 | /* Already installed */ 59 | if( [ AppInstaller isInApplicationsFolder ] ) 60 | { 61 | return AppInstallerStatusNoInstallNecessary; 62 | } 63 | 64 | /* Don't propose to move if we cannot remove the original app (if not in a DMG) */ 65 | if( [ AppInstaller isInDMG ] == NO && [ AppInstaller isWriteable ] == NO ) 66 | { 67 | return AppInstallerStatusNoInstallNecessary; 68 | } 69 | 70 | /* No valid install path */ 71 | if( ( installDir = [ AppInstaller installPath ] ) == nil ) 72 | { 73 | return AppInstallerStatusInstallError; 74 | } 75 | 76 | /* Final location */ 77 | installPath = [ installDir stringByAppendingPathComponent: [ [ [ NSBundle mainBundle ] bundlePath ] lastPathComponent ] ]; 78 | 79 | /* Existing app */ 80 | if( [ [ NSFileManager defaultManager ] fileExistsAtPath: installPath ] ) 81 | { 82 | { 83 | NSRunningApplication * app; 84 | 85 | for( app in [ [ NSWorkspace sharedWorkspace ] runningApplications ] ) 86 | { 87 | /* App is already running */ 88 | if( [ app.bundleURL.path isEqualToString: installPath ] ) 89 | { 90 | { 91 | NSAlert * alert; 92 | 93 | alert = [ NSAlert new ]; 94 | 95 | alert.messageText = [ NSString stringWithFormat: NSLocalizedString( @"%@ is already running", @"" ), [ AppInstaller appName ] ]; 96 | alert.informativeText = [ NSString stringWithFormat: NSLocalizedString( @"Another version of %@ is already running. In order to install this version, please quit the other one or restart your Mac and try again.", @"" ), [ AppInstaller appName ] ]; 97 | 98 | [ alert addButtonWithTitle: NSLocalizedString( @"OK", @"" ) ]; 99 | [ alert runModal ]; 100 | [ NSApp terminate: nil ]; 101 | } 102 | 103 | return AppInstallerStatusInstallError; 104 | } 105 | } 106 | } 107 | } 108 | 109 | { 110 | NSAlert * alert; 111 | 112 | if( [ NSApp isActive ] == NO ) 113 | { 114 | [ NSApp activateIgnoringOtherApps: YES ]; 115 | } 116 | 117 | alert = [ NSAlert new ]; 118 | alert.messageText = [ NSString stringWithFormat: NSLocalizedString( @"Install %@ in your \"Applications\" Folder?", @"" ), [ AppInstaller appName ] ]; 119 | alert.informativeText = [ NSString stringWithFormat: NSLocalizedString( @"%@ will now be installed in your \"Applications\" folder.", @"" ), [ AppInstaller appName ] ]; 120 | 121 | if( [ AppInstaller isInDMG ] == NO ) 122 | { 123 | alert.showsSuppressionButton = YES; 124 | } 125 | 126 | [ alert addButtonWithTitle: NSLocalizedString( @"Install", @"" ) ]; 127 | [ alert addButtonWithTitle: NSLocalizedString( @"Later", @"" ) ]; 128 | 129 | /* Don't move */ 130 | if( [ alert runModal ] != NSAlertFirstButtonReturn ) 131 | { 132 | if( [ AppInstaller isInDMG ] == NO ) 133 | { 134 | [ [ NSUserDefaults standardUserDefaults ] setBool: alert.suppressionButton.state == NSOnState forKey: AlertSuppressKey ]; 135 | [ [ NSUserDefaults standardUserDefaults ] synchronize ]; 136 | } 137 | 138 | return AppInstallerStatusInstallError; 139 | } 140 | } 141 | 142 | /* Do we need admin rights? */ 143 | if( [ [ NSFileManager defaultManager ] isWritableFileAtPath: installDir ] ) 144 | { 145 | /* Existing app */ 146 | if( [ [ NSFileManager defaultManager ] fileExistsAtPath: installPath ] ) 147 | { 148 | /* Trashes the existing app */ 149 | if( [ AppInstaller moveToTrash: installPath ] == NO ) 150 | { 151 | [ AppInstaller displayError ]; 152 | 153 | return AppInstallerStatusInstallError; 154 | } 155 | } 156 | 157 | /* Copies the new app */ 158 | if( [ [ NSFileManager defaultManager ] copyItemAtPath: [ [ NSBundle mainBundle ] bundlePath ] toPath: installPath error: NULL ] == NO ) 159 | { 160 | [ AppInstaller displayError ]; 161 | 162 | return AppInstallerStatusInstallError; 163 | } 164 | } 165 | else 166 | { 167 | if 168 | ( 169 | [ installPath hasSuffix: @".app" ] == NO 170 | || [ [ installPath stringByTrimmingCharactersInSet: [ NSCharacterSet whitespaceCharacterSet ] ] length ] == 0 171 | || [ [ installPath stringByTrimmingCharactersInSet: [ NSCharacterSet whitespaceCharacterSet ] ] length ] == 0 172 | ) 173 | { 174 | [ AppInstaller displayError ]; 175 | 176 | return AppInstallerStatusInstallError; 177 | } 178 | 179 | { 180 | OSStatus status; 181 | AuthorizationFlags flags; 182 | AuthorizationItem item; 183 | AuthorizationRights rights; 184 | AuthorizationRef authorizationRef; 185 | int pid; 186 | int exit; 187 | 188 | flags = kAuthorizationFlagDefaults; 189 | status = AuthorizationCreate 190 | ( 191 | NULL, 192 | kAuthorizationEmptyEnvironment, 193 | flags, 194 | &authorizationRef 195 | ); 196 | 197 | memset( &item, 0, sizeof( AuthorizationItem ) ); 198 | 199 | if( status != errAuthorizationSuccess ) 200 | { 201 | [ AppInstaller displayError ]; 202 | 203 | return AppInstallerStatusInstallError; 204 | } 205 | 206 | item.name = kAuthorizationRightExecute; 207 | rights.count = 1; 208 | rights.items = &item; 209 | 210 | flags = kAuthorizationFlagDefaults 211 | | kAuthorizationFlagInteractionAllowed 212 | | kAuthorizationFlagPreAuthorize 213 | | kAuthorizationFlagExtendRights; 214 | status = AuthorizationCopyRights 215 | ( 216 | authorizationRef, 217 | &rights, 218 | NULL, 219 | flags, 220 | NULL 221 | ); 222 | 223 | if( status != errAuthorizationSuccess ) 224 | { 225 | [ AppInstaller displayError ]; 226 | 227 | return AppInstallerStatusInstallError; 228 | } 229 | 230 | flags = kAuthorizationFlagDefaults; 231 | 232 | /* Existing app */ 233 | if( [ [ NSFileManager defaultManager ] fileExistsAtPath: installPath ] ) 234 | { 235 | { 236 | OSStatus err; 237 | char * args[ 3 ]; 238 | 239 | args[ 0 ] = "-rf"; 240 | args[ 1 ] = strdup( installPath.UTF8String ); 241 | args[ 2 ] = NULL; 242 | 243 | #pragma clang diagnostic push 244 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 245 | 246 | err = AuthorizationExecuteWithPrivileges 247 | ( 248 | authorizationRef, 249 | "/bin/rm", 250 | flags, 251 | args, 252 | NULL 253 | ); 254 | 255 | pid = wait( &exit ); 256 | 257 | if( pid == -1 || WIFEXITED( exit ) == 0 ) 258 | { 259 | free( args[ 1 ] ); 260 | 261 | [ AppInstaller displayError ]; 262 | 263 | return AppInstallerStatusInstallError; 264 | } 265 | 266 | free( args[ 1 ] ); 267 | 268 | #pragma clang diagnostic pop 269 | 270 | if( err != errAuthorizationSuccess ) 271 | { 272 | [ AppInstaller displayError ]; 273 | 274 | return AppInstallerStatusInstallError; 275 | } 276 | } 277 | } 278 | 279 | { 280 | OSStatus err; 281 | char * args[ 4 ]; 282 | 283 | args[ 0 ] = "-rf"; 284 | args[ 1 ] = strdup( [ [ NSBundle mainBundle ] bundlePath ].UTF8String ); 285 | args[ 2 ] = strdup( installPath.UTF8String ); 286 | args[ 3 ] = NULL; 287 | 288 | #pragma clang diagnostic push 289 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 290 | 291 | err = AuthorizationExecuteWithPrivileges 292 | ( 293 | authorizationRef, 294 | "/bin/cp", 295 | flags, 296 | args, 297 | NULL 298 | ); 299 | 300 | pid = wait( &exit ); 301 | 302 | if( pid == -1 || WIFEXITED( exit ) == 0 ) 303 | { 304 | free( args[ 1 ] ); 305 | free( args[ 2 ] ); 306 | 307 | [ AppInstaller displayError ]; 308 | 309 | return AppInstallerStatusInstallError; 310 | } 311 | 312 | free( args[ 1 ] ); 313 | free( args[ 2 ] ); 314 | 315 | #pragma clang diagnostic pop 316 | 317 | if( err != errAuthorizationSuccess ) 318 | { 319 | [ AppInstaller displayError ]; 320 | 321 | return AppInstallerStatusInstallError; 322 | } 323 | } 324 | } 325 | } 326 | 327 | if( [ AppInstaller isInDMG ] == NO ) 328 | { 329 | /* Moves the original app to the trash */ 330 | [ AppInstaller moveToTrash: [ [ NSBundle mainBundle ] bundlePath ] ]; 331 | } 332 | 333 | [ [ NSWorkspace sharedWorkspace ] openFile: installPath ]; 334 | [ NSApp terminate: nil ]; 335 | 336 | return AppInstallerStatusInstallSucessfull; 337 | } 338 | 339 | + ( BOOL )isInApplicationsFolder 340 | { 341 | NSArray * paths; 342 | NSString * path; 343 | 344 | paths = NSSearchPathForDirectoriesInDomains( NSApplicationDirectory, NSAllDomainsMask, YES ); 345 | 346 | /* All Applications directories */ 347 | for( path in paths ) 348 | { 349 | /* App is in an application directory */ 350 | if( [ [ [ NSBundle mainBundle ] bundlePath ] hasPrefix: path ] ) 351 | { 352 | return YES; 353 | } 354 | } 355 | 356 | return NO; 357 | } 358 | 359 | + ( BOOL )isInDMG 360 | { 361 | return [ [ [ NSBundle mainBundle ] bundlePath ] hasPrefix: @"/Volumes/ccache" ]; 362 | } 363 | 364 | + ( BOOL )isWriteable 365 | { 366 | return [ [ NSFileManager defaultManager ] isWritableFileAtPath: [ [ NSBundle mainBundle ] bundlePath ] ]; 367 | } 368 | 369 | + ( nullable NSString * )installPath 370 | { 371 | NSArray * paths; 372 | BOOL isDir; 373 | 374 | paths = NSSearchPathForDirectoriesInDomains( NSApplicationDirectory, NSLocalDomainMask, YES ); 375 | 376 | if( paths.count && [ [ NSFileManager defaultManager ] fileExistsAtPath: ( id )( paths.lastObject ) isDirectory: &isDir ] && isDir ) 377 | { 378 | return paths.lastObject; 379 | } 380 | 381 | return nil; 382 | } 383 | 384 | + ( BOOL )moveToTrash: ( NSString * )path 385 | { 386 | volatile __block BOOL result; 387 | volatile __block BOOL complete; 388 | 389 | result = NO; 390 | complete = NO; 391 | 392 | [ [ NSWorkspace sharedWorkspace ] recycleURLs: @[ [ NSURL fileURLWithPath: path ] ] 393 | completionHandler: ^( NSDictionary * _Nonnull newURLs, NSError * _Nullable error ) 394 | { 395 | ( void )newURLs; 396 | 397 | result = ( error == nil ); 398 | complete = YES; 399 | } 400 | ]; 401 | 402 | while( complete == NO ) 403 | { 404 | [ [ NSRunLoop mainRunLoop ] runUntilDate: [ NSDate dateWithTimeIntervalSinceNow: 0.1 ] ]; 405 | } 406 | 407 | return result; 408 | } 409 | 410 | + ( void )displayError 411 | { 412 | NSAlert * alert; 413 | 414 | alert = [ NSAlert new ]; 415 | alert.messageText = NSLocalizedString( @"Could not move to \"Applications\" Folder", @"" ); 416 | alert.informativeText = [ NSString stringWithFormat: NSLocalizedString( @"If another version of %@ is installed on your computer, please delete it from your \"Applications\" folder and try again.", @"" ), [ AppInstaller appName ] ]; 417 | 418 | [ alert addButtonWithTitle: NSLocalizedString( @"OK", @"" ) ]; 419 | [ alert runModal ]; 420 | } 421 | 422 | + ( NSString * )appName 423 | { 424 | NSString * name = [ [ NSBundle mainBundle ] objectForInfoDictionaryKey: @"CFBundleName" ]; 425 | 426 | if( name != nil ) 427 | { 428 | return name; 429 | } 430 | 431 | return @"ccache"; 432 | } 433 | 434 | @end 435 | -------------------------------------------------------------------------------- /ccache/Classes/ApplicationDelegate.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Foundation 26 | 27 | @NSApplicationMain class ApplicationDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate, NSWindowDelegate 28 | { 29 | @objc private dynamic var statusItem: NSStatusItem? 30 | @objc private dynamic var aboutWindowController: AboutWindowController? 31 | @objc private dynamic var mainViewController: MainViewController? 32 | @objc private dynamic var popover: NSPopover? 33 | @objc private dynamic var popoverTranscientEvent: Any? 34 | @objc private dynamic var popoverIsOpen: Bool = false 35 | @objc private dynamic var didFinishLaunching: Bool = false 36 | 37 | @objc public dynamic var startAtLogin: Bool = false 38 | { 39 | didSet 40 | { 41 | if self.startAtLogin 42 | { 43 | NSApp.enableLoginItem() 44 | } 45 | else 46 | { 47 | NSApp.disableLoginItem() 48 | } 49 | } 50 | } 51 | 52 | @objc private dynamic var popoverWindow: NSWindow? 53 | { 54 | didSet 55 | { 56 | if let window = self.popoverWindow 57 | { 58 | self.popoverWindowVisibilityObserver = window.observe( \.isVisible ) 59 | { 60 | [ weak self ] _, _ in guard let self = self else { return } 61 | 62 | if window.contentView !== self.mainViewController?.view 63 | { 64 | self.popoverWindow?.contentView = self.popover?.contentViewController?.view 65 | self.popover = nil 66 | self.popoverIsOpen = false 67 | } 68 | } 69 | } 70 | else 71 | { 72 | self.popoverWindowVisibilityObserver = nil 73 | } 74 | } 75 | } 76 | 77 | private var popoverWindowVisibilityObserver: NSKeyValueObservation? 78 | 79 | @IBAction public func showAboutWindow( _ sender: Any? ) 80 | { 81 | if self.aboutWindowController == nil 82 | { 83 | self.aboutWindowController = AboutWindowController() 84 | 85 | self.aboutWindowController?.window?.layoutIfNeeded() 86 | } 87 | 88 | if self.aboutWindowController?.window?.isVisible == false 89 | { 90 | self.aboutWindowController?.window?.center() 91 | } 92 | 93 | self.closePopover( sender ) 94 | self.aboutWindowController?.window?.makeKeyAndOrderFront( sender ) 95 | } 96 | 97 | @IBAction public func openPopover( _ sender: Any? ) 98 | { 99 | if self.popoverWindow != nil && self.popoverWindow?.contentView !== self.mainViewController?.view 100 | { 101 | self.popoverWindow = nil 102 | } 103 | 104 | if let popoverWindow = self.popoverWindow 105 | { 106 | NSApp.activate( ignoringOtherApps: true ) 107 | popoverWindow.makeKeyAndOrderFront( sender ) 108 | } 109 | else if let popover = self.popover, popover.isShown 110 | { 111 | self.togglePopover( sender ) 112 | } 113 | } 114 | 115 | @IBAction public func closePopover( _ sender: Any? ) 116 | { 117 | if let popover = self.popover, popover.isShown 118 | { 119 | popover.close() 120 | } 121 | } 122 | 123 | @IBAction private func togglePopover( _ sender: Any? ) 124 | { 125 | let view = self.statusItem?.button 126 | 127 | if self.popoverWindow != nil && self.popoverWindow?.contentView !== self.mainViewController?.view 128 | { 129 | self.popoverWindow = nil 130 | } 131 | 132 | if let popoverWindow = self.popoverWindow 133 | { 134 | NSApp.activate( ignoringOtherApps: true ) 135 | popoverWindow.makeKeyAndOrderFront( sender ) 136 | } 137 | else if let popover = self.popover, popover.isShown 138 | { 139 | popover.close() 140 | } 141 | else if view != nil 142 | { 143 | if self.popover == nil 144 | { 145 | self.popover = NSPopover() 146 | self.popover?.behavior = .applicationDefined 147 | self.popover?.contentViewController = self.mainViewController 148 | self.popover?.delegate = self 149 | } 150 | 151 | if self.statusItem != nil 152 | { 153 | self.popover?.show( relativeTo: self.statusItem!.button!.frame, of: view!, preferredEdge: .minY ) 154 | } 155 | } 156 | } 157 | 158 | // MARK: NSApplicationDelegate 159 | 160 | func applicationDidFinishLaunching( _ notification: Notification ) 161 | { 162 | AppInstaller.installIfNecessary() 163 | 164 | self.startAtLogin = NSApp.isLoginItemEnabled() 165 | self.statusItem = NSStatusBar.system.statusItem( withLength: NSStatusItem.squareLength ) 166 | self.statusItem?.image = NSImage( named: NSImage.Name( "StatusIconTemplate" ) ) 167 | self.statusItem?.target = self 168 | self.statusItem?.action = #selector( togglePopover ) 169 | self.mainViewController = MainViewController() 170 | self.didFinishLaunching = true; 171 | } 172 | 173 | func applicationWillTerminate( _ notification: Notification ) 174 | { 175 | if self.didFinishLaunching 176 | { 177 | NotificationCenter.default.removeObserver( self ) 178 | } 179 | } 180 | 181 | // MARK: NSWindowDelegate 182 | 183 | func windowWillClose( _ notification: Notification ) 184 | { 185 | if let window = self.popoverWindow, notification.object as AnyObject === window 186 | { 187 | window.delegate = nil 188 | self.popoverWindow = nil 189 | } 190 | } 191 | 192 | // MARK: NSPopoverDelegate 193 | 194 | func popoverShouldDetach( _ popover: NSPopover ) -> Bool 195 | { 196 | true 197 | } 198 | 199 | func detachableWindow( for popover: NSPopover ) -> NSWindow? 200 | { 201 | if popover.contentViewController == nil 202 | { 203 | return nil 204 | } 205 | 206 | if self.popoverWindow != nil 207 | { 208 | return self.popoverWindow 209 | } 210 | 211 | let mask: NSWindow.StyleMask = [ .titled, .closable, .miniaturizable, .fullSizeContentView ] 212 | let window = NSWindow( contentRect: popover.contentViewController!.view.bounds, styleMask: mask, backing: .buffered, defer: false ) 213 | 214 | window.delegate = self 215 | window.isReleasedWhenClosed = false 216 | window.titlebarAppearsTransparent = true 217 | window.titleVisibility = .hidden 218 | window.title = Bundle.main.object( forInfoDictionaryKey: "CFBundleName" ) as? String ?? "" 219 | 220 | NotificationCenter.default.removeObserver( self, name: NSPopover.willShowNotification, object: self.popover ) 221 | NotificationCenter.default.removeObserver( self, name: NSPopover.willCloseNotification, object: self.popover ) 222 | 223 | self.popoverWindow = window 224 | 225 | return window 226 | } 227 | 228 | func popoverWillShow( _ notification: Notification ) 229 | { 230 | self.popoverTranscientEvent = NSEvent.addGlobalMonitorForEvents( matching: .leftMouseUp ) 231 | { 232 | _ in self.popover?.close() 233 | } 234 | } 235 | 236 | func popoverDidShow( _ notification: Notification ) 237 | { 238 | self.popoverIsOpen = true 239 | } 240 | 241 | func popoverDidClose( _ notification: Notification ) 242 | { 243 | if self.popoverTranscientEvent != nil 244 | { 245 | NSEvent.removeMonitor( self.popoverTranscientEvent! ) 246 | } 247 | 248 | self.popoverIsOpen = false 249 | self.popover = nil 250 | self.popoverTranscientEvent = nil 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /ccache/Classes/CCache.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Foundation 26 | 27 | class CCache: NSObject 28 | { 29 | @objc public dynamic private( set ) var installed: Bool = false 30 | @objc public dynamic private( set ) var path: String? 31 | 32 | static public let sharedInstance = CCache() 33 | 34 | private override init() 35 | { 36 | super.init() 37 | 38 | guard let shell = ProcessInfo.processInfo.environment[ "SHELL" ] as String?, shell.count > 0 else 39 | { 40 | return 41 | } 42 | 43 | let pipe = Pipe() 44 | let task = Process() 45 | task.launchPath = shell 46 | task.arguments = [ "-l", "-c", "which ccache" ] 47 | task.standardOutput = pipe; 48 | 49 | task.launch() 50 | task.waitUntilExit() 51 | 52 | if task.terminationStatus == EXIT_SUCCESS 53 | { 54 | let data = pipe.fileHandleForReading.readDataToEndOfFile() 55 | let output = String( data: data, encoding: String.Encoding.utf8 )?.trimmingCharacters( in: CharacterSet.whitespacesAndNewlines ) 56 | 57 | if let output = output, output.isEmpty == false && FileManager.default.fileExists( atPath: output ) 58 | { 59 | self.path = output 60 | self.installed = true 61 | } 62 | } 63 | 64 | if self.installed == false 65 | { 66 | if FileManager.default.fileExists( atPath: "/opt/local/bin/ccache" ) 67 | { 68 | self.path = "/opt/local/bin/ccache" 69 | self.installed = true 70 | } 71 | else if FileManager.default.fileExists( atPath: "/opt/homebrew/bin/ccache" ) 72 | { 73 | self.path = "/opt/homebrew/bin/ccache" 74 | self.installed = true 75 | } 76 | } 77 | } 78 | 79 | private func execute( arguments: [ String ], completion: @escaping ( ( status: Int32, output: FileHandle?, error: FileHandle? ) ) -> Void ) 80 | { 81 | if self.installed == false 82 | { 83 | completion( ( EXIT_FAILURE, nil, nil ) ) 84 | 85 | return 86 | } 87 | 88 | DispatchQueue.global( qos: .userInitiated ).async 89 | { 90 | let task = Process() 91 | let p1 = Pipe() 92 | let p2 = Pipe() 93 | 94 | task.launchPath = self.path 95 | task.arguments = arguments 96 | task.standardOutput = p1 97 | task.standardError = p2 98 | 99 | task.launch() 100 | task.waitUntilExit() 101 | 102 | DispatchQueue.main.async 103 | { 104 | completion( ( task.terminationStatus, p1.fileHandleForReading, p2.fileHandleForReading ) ) 105 | } 106 | } 107 | } 108 | 109 | public func cleanup( completion: ( ( Bool ) -> Void )? ) 110 | { 111 | self.execute( arguments: [ "-c" ] ) 112 | { 113 | completion?( $0.status == 0 ) 114 | } 115 | } 116 | 117 | public func clear( completion: ( ( Bool ) -> Void )? ) 118 | { 119 | self.execute( arguments: [ "-C" ] ) 120 | { 121 | completion?( $0.status == 0 ) 122 | } 123 | } 124 | 125 | public func clearStatistics( completion: ( ( Bool ) -> Void )? ) 126 | { 127 | self.execute( arguments: [ "-z" ] ) 128 | { 129 | completion?( $0.status == 0 ) 130 | } 131 | } 132 | 133 | public func getStatistics( completion: ( ( Bool, String ) -> Void )? ) 134 | { 135 | self.execute( arguments: [ "-s" ] ) 136 | { 137 | if $0.status == 0 138 | { 139 | let str = String( data: $0.output?.readDataToEndOfFile() ?? Data(), encoding: String.Encoding.utf8 ) 140 | 141 | completion?( true, str ?? "" ) 142 | } 143 | else 144 | { 145 | completion?( false, "" ) 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /ccache/Classes/MainViewController.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Cocoa 26 | import GitHubUpdates 27 | 28 | class MainViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource 29 | { 30 | @objc private dynamic var awake: Bool = false 31 | @objc private dynamic var installed: Bool = CCache.sharedInstance.installed 32 | @objc private dynamic var running: Bool = false 33 | @objc private dynamic var headerRowHeight: CGFloat = 25.0 34 | @objc private dynamic var rowHeight: CGFloat = 17.0 35 | @objc private dynamic var tableViewHeight: CGFloat = 0.0 36 | @objc private dynamic var statistics: [ StatisticItem ] = [] 37 | 38 | @objc private dynamic var timer: Timer? 39 | @objc private dynamic var updater: GitHubUpdater? 40 | 41 | @IBOutlet @objc private dynamic var statisticsController: NSArrayController? 42 | @IBOutlet @objc private dynamic var tableView: NSTableView? 43 | 44 | override func awakeFromNib() 45 | { 46 | if self.awake 47 | { 48 | return 49 | } 50 | 51 | self.awake = true 52 | self.updater = GitHubUpdater() 53 | self.updater?.user = "macmade" 54 | self.updater?.repository = "ccache-gui" 55 | self.tableViewHeight = self.tableView?.enclosingScrollView?.constantForAttribute( .height ) ?? 0.0 56 | 57 | self.updateStatistics() 58 | self.updater?.checkForUpdatesInBackground() 59 | 60 | Timer.scheduledTimer( withTimeInterval: 3600, repeats: true ) 61 | { 62 | _ in self.updater?.checkForUpdatesInBackground() 63 | } 64 | } 65 | 66 | override func viewDidAppear() 67 | { 68 | super.viewDidAppear() 69 | 70 | if self.timer == nil 71 | { 72 | self.timer = Timer.scheduledTimer( withTimeInterval: 1, repeats: true ) 73 | { 74 | _ in self.updateStatistics() 75 | } 76 | } 77 | } 78 | 79 | override func viewDidDisappear() 80 | { 81 | super.viewDidDisappear() 82 | 83 | self.timer?.invalidate() 84 | 85 | self.timer = nil 86 | } 87 | 88 | @IBAction private func showOptionsMenu( _ sender: Any? ) 89 | { 90 | if let button = sender as? NSButton 91 | { 92 | if button.menu == nil || NSApp.currentEvent == nil 93 | { 94 | return; 95 | } 96 | 97 | NSMenu.popUpContextMenu( button.menu!, with: NSApp.currentEvent!, for: button ) 98 | } 99 | } 100 | 101 | @IBAction private func cleanup( _ sender: Any? ) 102 | { 103 | self.running = true 104 | 105 | CCache.sharedInstance.cleanup() 106 | { 107 | _ in 108 | 109 | self.updateStatistics() 110 | 111 | self.running = false 112 | } 113 | } 114 | 115 | @IBAction private func clear( _ sender: Any? ) 116 | { 117 | self.running = true 118 | 119 | CCache.sharedInstance.clear() 120 | { 121 | _ in 122 | 123 | self.updateStatistics() 124 | 125 | self.running = false 126 | } 127 | } 128 | 129 | @IBAction private func resetStatistics( _ sender: Any? ) 130 | { 131 | self.running = true 132 | 133 | CCache.sharedInstance.clearStatistics() 134 | { 135 | _ in 136 | 137 | self.updateStatistics() 138 | 139 | self.running = false 140 | } 141 | } 142 | 143 | private func updateStatistics() 144 | { 145 | CCache.sharedInstance.getStatistics() 146 | { 147 | success, statistics in 148 | 149 | if success == false || statistics.count == 0 150 | { 151 | return 152 | } 153 | 154 | let lines = statistics.components( separatedBy: "\n" ).filter 155 | { 156 | $0.trimmingCharacters( in: .whitespaces ).isEmpty == false 157 | } 158 | 159 | let items: [ StatisticItem ] = lines.compactMap 160 | { 161 | if $0.contains( ":" ) == false 162 | { 163 | return nil 164 | } 165 | 166 | let parts = $0.components( separatedBy: ":" ) 167 | let label = parts.first ?? "" 168 | let text = parts.count == 1 ? "" : parts.last ?? "" 169 | let item = StatisticItem( label: label, text: text, tooltip: nil ) 170 | 171 | return item 172 | } 173 | 174 | if items.count > 0 && items != self.statistics 175 | { 176 | self.statisticsController?.remove( contentsOf: self.statistics ) 177 | self.statisticsController?.add( contentsOf: items ) 178 | self.statisticsController?.didChangeArrangementCriteria() 179 | } 180 | 181 | self.adjustTableViewHeight() 182 | } 183 | } 184 | 185 | @IBAction private func openManual( _ sender: Any? ) 186 | { 187 | if let url = URL( string : "https://ccache.samba.org/manual.html" ) 188 | { 189 | NSWorkspace.shared.open( url ) 190 | } 191 | } 192 | 193 | @IBAction private func install( _ sender: Any? ) 194 | { 195 | if let url = URL( string : "https://brew.sh" ) 196 | { 197 | NSWorkspace.shared.open( url ) 198 | } 199 | } 200 | 201 | @objc private dynamic var xcodeDerivedDataPath: String? 202 | { 203 | if let library = NSSearchPathForDirectoriesInDomains( .libraryDirectory, .userDomainMask, true ).first, FileManager.default.fileExists( atPath: library ) 204 | { 205 | var path: NSString = library as NSString 206 | 207 | path = path.appendingPathComponent( "Developer" ) as NSString 208 | path = path.appendingPathComponent( "Xcode" ) as NSString 209 | path = path.appendingPathComponent( "DerivedData" ) as NSString 210 | 211 | var isDir: ObjCBool = false 212 | 213 | if path.length != 0 && FileManager.default.fileExists( atPath: path as String, isDirectory: &isDir ) && isDir.boolValue 214 | { 215 | return path as String 216 | } 217 | } 218 | 219 | return nil 220 | } 221 | 222 | @objc private dynamic var xcodeDerivedDataURL: URL? 223 | { 224 | if let path = self.xcodeDerivedDataPath 225 | { 226 | return NSURL.fileURL( withPath: path ) 227 | } 228 | 229 | return nil 230 | } 231 | 232 | @IBAction private func clearXcodeDerivedData( _ sender: Any? ) 233 | { 234 | guard let path = self.xcodeDerivedDataPath else 235 | { 236 | self.alertForMissingXcodeDerivedDataDirectory() 237 | 238 | return 239 | } 240 | 241 | self.running = true 242 | 243 | DispatchQueue.global( qos: .userInitiated ).async 244 | { 245 | do 246 | { 247 | for sub in try FileManager.default.contentsOfDirectory( atPath: path ) 248 | { 249 | try FileManager.default.removeItem( atPath: ( path as NSString ).appendingPathComponent( sub ) ) 250 | } 251 | } 252 | catch let error as NSError 253 | { 254 | DispatchQueue.main.async 255 | { 256 | NSAlert( error: error ).runModal() 257 | } 258 | } 259 | 260 | DispatchQueue.main.async 261 | { 262 | self.running = false 263 | } 264 | } 265 | } 266 | 267 | @IBAction private func revealXcodeDerivedData( _ sender: Any? ) 268 | { 269 | guard let path = self.xcodeDerivedDataPath else 270 | { 271 | self.alertForMissingXcodeDerivedDataDirectory() 272 | 273 | return 274 | } 275 | 276 | ( NSApp.delegate as? ApplicationDelegate )?.closePopover( sender ) 277 | NSWorkspace.shared.selectFile( nil, inFileViewerRootedAtPath: path ) 278 | } 279 | 280 | @IBAction private func checkForUpdates( _ sender: Any? ) 281 | { 282 | ( NSApp.delegate as? ApplicationDelegate )?.closePopover( sender ) 283 | self.updater?.checkForUpdates( sender ) 284 | } 285 | 286 | private func alertForMissingXcodeDerivedDataDirectory() 287 | { 288 | let alert = NSAlert() 289 | alert.messageText = NSLocalizedString( "No Derived Data", comment: "" ) 290 | alert.informativeText = NSLocalizedString( "The Xcode Derived Data directory does not exist.", comment: "" ) 291 | 292 | alert.addButton( withTitle: NSLocalizedString( "OK", comment: "" ) ) 293 | ( NSApp.delegate as? ApplicationDelegate )?.closePopover( nil ) 294 | alert.runModal() 295 | } 296 | 297 | private func adjustTableViewHeight() 298 | { 299 | if self.installed && self.statistics.count != 0 300 | { 301 | guard let items = self.statisticsController?.arrangedObjects as? [ StatisticItem ] else 302 | { 303 | return 304 | } 305 | 306 | let headers = items.filter { $0.text.isEmpty } 307 | let stats = items.filter { $0.text.isEmpty == false } 308 | let height = CGFloat( headers.count ) * self.headerRowHeight + CGFloat( stats.count ) * self.rowHeight 309 | 310 | self.tableView?.enclosingScrollView?.setConstant( height, forAttribute: .height ) 311 | } 312 | else 313 | { 314 | self.tableView?.enclosingScrollView?.setConstant( self.tableViewHeight, forAttribute: .height ) 315 | } 316 | } 317 | 318 | // MARK: NSTableViewDelegate 319 | 320 | func tableView( _ tableView: NSTableView, heightOfRow row: Int ) -> CGFloat 321 | { 322 | guard let items = self.statisticsController?.arrangedObjects as? [ StatisticItem ] else 323 | { 324 | return self.rowHeight 325 | } 326 | 327 | if row >= items.count 328 | { 329 | return self.rowHeight 330 | } 331 | 332 | return items[ row ].text.isEmpty ? self.headerRowHeight : self.rowHeight 333 | } 334 | 335 | func tableView( _ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int ) -> NSView? 336 | { 337 | guard let items = self.statisticsController?.arrangedObjects as? [ StatisticItem ] else 338 | { 339 | return nil 340 | } 341 | 342 | if row >= items.count 343 | { 344 | return nil 345 | } 346 | 347 | if items[ row ].text.isEmpty 348 | { 349 | return tableView.makeView( withIdentifier: NSUserInterfaceItemIdentifier( "HeaderCell" ), owner: self ) 350 | } 351 | 352 | return tableView.makeView( withIdentifier: NSUserInterfaceItemIdentifier( "DataCell" ), owner: self ) 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /ccache/Classes/NSApplication+LaunchServices.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com / www.imazing.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | @import Cocoa; 26 | 27 | @interface NSApplication( LaunchServices ) 28 | 29 | + ( BOOL )isLoginItemEnabledForBundleURL: ( NSURL * )url; 30 | + ( void )setLoginItemEnabled: ( BOOL )enabled forBundleURL: ( NSURL * )url; 31 | + ( void )enableLoginItemForBundleURL: ( NSURL * )url; 32 | + ( void )disableLoginItemForBundleURL: ( NSURL * )url; 33 | 34 | - ( BOOL )isLoginItemEnabled; 35 | - ( void )setLoginItemEnabled: ( BOOL )enabled; 36 | - ( void )enableLoginItem; 37 | - ( void )disableLoginItem; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /ccache/Classes/NSApplication+LaunchServices.m: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com / www.imazing.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | #import "NSApplication+LaunchServices.h" 26 | 27 | /* 28 | * LaunchServices functions for managing login items are deprecated, 29 | * but there's actually no viable alternative. 30 | * SystemManagement functions are not viable, because they require a separate 31 | * helper tool (complete app bundle) to be running constantly, for the sole 32 | * purpose of launching the main application. 33 | * Also, using SystemManagement, there's no way for the user to control the 34 | * login item, as it does not appear in the System Preferences, meaning there's 35 | * no way to delete the login item without the original app... 36 | * Common Apple, I think you can do better... 37 | */ 38 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 39 | 40 | @implementation NSApplication( LaunchServices ) 41 | 42 | + ( BOOL )isLoginItemEnabledForBundleURL: ( NSURL * )url 43 | { 44 | BOOL found; 45 | UInt32 seedValue; 46 | CFURLRef path; 47 | LSSharedFileListRef loginItemsRef; 48 | CFArrayRef loginItems; 49 | id loginItem; 50 | LSSharedFileListItemRef loginItemRef; 51 | 52 | found = NO; 53 | seedValue = 0; 54 | path = NULL; 55 | loginItemsRef = LSSharedFileListCreate( NULL, kLSSharedFileListSessionLoginItems, NULL ); 56 | 57 | if( loginItemsRef == NULL ) 58 | { 59 | return NO; 60 | } 61 | 62 | loginItems = LSSharedFileListCopySnapshot( loginItemsRef, &seedValue ); 63 | 64 | for( loginItem in ( __bridge NSArray * )loginItems ) 65 | { 66 | loginItemRef = ( __bridge LSSharedFileListItemRef )loginItem; 67 | 68 | if( LSSharedFileListItemResolve( loginItemRef, 0, ( CFURLRef * )&path, NULL ) == noErr ) 69 | { 70 | { 71 | NSString * s; 72 | 73 | s = url.path; 74 | 75 | if( s == nil ) 76 | { 77 | continue; 78 | } 79 | 80 | if( [ ( ( __bridge NSURL * )path ).path hasPrefix: s ] ) 81 | { 82 | CFRelease( path ); 83 | 84 | found = YES; 85 | 86 | break; 87 | } 88 | 89 | if( path != NULL ) 90 | { 91 | CFRelease( path ); 92 | } 93 | } 94 | } 95 | } 96 | 97 | if( loginItems != NULL ) 98 | { 99 | CFRelease( loginItems ); 100 | } 101 | 102 | CFRelease( loginItemsRef ); 103 | 104 | return found; 105 | } 106 | 107 | + ( void )setLoginItemEnabled: ( BOOL )enabled forBundleURL: ( NSURL * )url 108 | { 109 | if( enabled ) 110 | { 111 | [ NSApplication enableLoginItemForBundleURL: url ]; 112 | } 113 | else 114 | { 115 | [ NSApplication disableLoginItemForBundleURL: url ]; 116 | } 117 | } 118 | 119 | + ( void )enableLoginItemForBundleURL: ( NSURL * )url 120 | { 121 | LSSharedFileListRef loginItemsRef; 122 | LSSharedFileListItemRef loginItemRef; 123 | 124 | loginItemsRef = LSSharedFileListCreate( NULL, kLSSharedFileListSessionLoginItems, NULL ); 125 | 126 | if( !loginItemsRef ) 127 | { 128 | return; 129 | } 130 | 131 | loginItemRef = LSSharedFileListInsertItemURL 132 | ( 133 | loginItemsRef, 134 | kLSSharedFileListItemLast, 135 | NULL, 136 | NULL, 137 | ( __bridge CFURLRef )url, 138 | NULL, 139 | NULL 140 | ); 141 | 142 | if( loginItemRef ) 143 | { 144 | CFRelease( loginItemRef ); 145 | } 146 | } 147 | 148 | + ( void )disableLoginItemForBundleURL: ( NSURL * )url 149 | { 150 | UInt32 seedValue; 151 | CFURLRef path; 152 | CFArrayRef loginItems; 153 | LSSharedFileListRef loginItemsRef; 154 | id loginItem; 155 | LSSharedFileListItemRef loginItemRef; 156 | 157 | path = NULL; 158 | seedValue = 0; 159 | loginItemsRef = LSSharedFileListCreate( NULL, kLSSharedFileListSessionLoginItems, NULL ); 160 | 161 | if( !loginItemsRef ) 162 | { 163 | return; 164 | } 165 | 166 | loginItems = LSSharedFileListCopySnapshot( loginItemsRef, &seedValue ); 167 | 168 | for( loginItem in ( __bridge NSArray * )loginItems ) 169 | { 170 | loginItemRef = ( __bridge LSSharedFileListItemRef )loginItem; 171 | 172 | if( LSSharedFileListItemResolve( loginItemRef, 0, ( CFURLRef * )&path, NULL ) == noErr ) 173 | { 174 | { 175 | NSString * s; 176 | 177 | s = url.path; 178 | 179 | if( s == nil ) 180 | { 181 | continue; 182 | } 183 | 184 | if( [ ( ( __bridge NSURL * )path ).path hasPrefix: s ] ) 185 | { 186 | CFRelease( path ); 187 | LSSharedFileListItemRemove( loginItemsRef, loginItemRef ); 188 | 189 | break; 190 | } 191 | 192 | if( path != NULL ) 193 | { 194 | CFRelease( path ); 195 | } 196 | } 197 | } 198 | } 199 | 200 | if( loginItems != NULL ) 201 | { 202 | CFRelease( loginItems ); 203 | } 204 | } 205 | 206 | - ( BOOL )isLoginItemEnabled 207 | { 208 | return [ NSApplication isLoginItemEnabledForBundleURL: [ NSURL fileURLWithPath: [ [ NSBundle mainBundle ] bundlePath ] ] ]; 209 | } 210 | 211 | - ( void )setLoginItemEnabled: ( BOOL )enabled 212 | { 213 | [ NSApplication setLoginItemEnabled: enabled forBundleURL: [ NSURL fileURLWithPath: [ [ NSBundle mainBundle ] bundlePath ] ] ]; 214 | } 215 | 216 | - ( void )enableLoginItem 217 | { 218 | [ NSApplication enableLoginItemForBundleURL: [ NSURL fileURLWithPath: [ [ NSBundle mainBundle ] bundlePath ] ] ]; 219 | } 220 | 221 | - ( void )disableLoginItem 222 | { 223 | [ NSApplication disableLoginItemForBundleURL: [ NSURL fileURLWithPath: [ [ NSBundle mainBundle ] bundlePath ] ] ]; 224 | } 225 | 226 | @end 227 | -------------------------------------------------------------------------------- /ccache/Classes/NSView+ccache.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Cocoa 26 | 27 | extension NSView 28 | { 29 | public func constraintForAttribute( _ attribute: NSLayoutConstraint.Attribute ) -> NSLayoutConstraint? 30 | { 31 | self.constraints.filter { $0.firstAttribute == attribute }.first 32 | } 33 | 34 | public func constantForAttribute( _ attribute: NSLayoutConstraint.Attribute ) -> CGFloat 35 | { 36 | self.constraintForAttribute( attribute )?.constant ?? 0.0 37 | } 38 | 39 | public func setConstant( _ constant: CGFloat, forAttribute: NSLayoutConstraint.Attribute ) 40 | { 41 | self.constraintForAttribute( forAttribute )?.constant = constant 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ccache/Classes/StatisticItem.swift: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www.xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | import Foundation 26 | 27 | class StatisticItem: NSObject 28 | { 29 | @objc public dynamic var label: String 30 | @objc public dynamic var text: String 31 | 32 | public init( label: String, text: String, tooltip: String? ) 33 | { 34 | self.label = label.trimmingCharacters( in: CharacterSet.whitespaces ).capitalized 35 | self.text = text.trimmingCharacters( in: CharacterSet.whitespaces ) 36 | } 37 | 38 | override func isEqual( _ object: Any? ) -> Bool 39 | { 40 | guard let other = object as? StatisticItem else 41 | { 42 | return false 43 | } 44 | 45 | return self == other 46 | } 47 | 48 | public override var description: String 49 | { 50 | "\( super.description ) \( self.label ): \( self.text )" 51 | } 52 | 53 | public static func ==( o1: StatisticItem, o2: StatisticItem ) -> Bool 54 | { 55 | if o1 === o2 56 | { 57 | return true 58 | } 59 | 60 | return o1.label == o2.label && o1.text == o2.text 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /ccache/Classes/ccache-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Jean-David Gadina - www-xs-labs.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | ******************************************************************************/ 24 | 25 | #import "AppInstaller.h" 26 | #import "NSApplication+LaunchServices.h" 27 | -------------------------------------------------------------------------------- /ccache/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | ccache 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 0.1.12 21 | CFBundleVersion 22 | 67 23 | LSApplicationCategoryType 24 | public.app-category.developer-tools 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | LSUIElement 28 | 29 | NSHumanReadableCopyright 30 | Copyright © 2017 XS-Labs / DigiDNA. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /ccache/Interface/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | Default 534 | 535 | 536 | 537 | 538 | 539 | 540 | Left to Right 541 | 542 | 543 | 544 | 545 | 546 | 547 | Right to Left 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | Default 559 | 560 | 561 | 562 | 563 | 564 | 565 | Left to Right 566 | 567 | 568 | 569 | 570 | 571 | 572 | Right to Left 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | -------------------------------------------------------------------------------- /ccache/Interface/Base.lproj/ccache.AboutWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /ccache/Interface/Base.lproj/ccache.MainViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | NSNegateBoolean 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 240 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | NSNegateBoolean 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | NSNegateBoolean 263 | 264 | 265 | 266 | 267 | 282 | 297 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | NSNegateBoolean 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | NSNegateBoolean 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | NSNegateBoolean 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | -------------------------------------------------------------------------------- /ccache/Interface/Images/StatusIconTemplate.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macmade/ccache-gui/485ad2e7724649cd11bbdb3c349396f743a6fb8e/ccache/Interface/Images/StatusIconTemplate.pdf -------------------------------------------------------------------------------- /ccache/Interface/Images/ccache.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/macmade/ccache-gui/485ad2e7724649cd11bbdb3c349396f743a6fb8e/ccache/Interface/Images/ccache.icns -------------------------------------------------------------------------------- /ccache/ccache.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------