├── .gitignore ├── README.md ├── CODE_OF_CONDUCT.md ├── Chef_Processors ├── ChefProcessors.recipe ├── ChefAttributeList.py ├── ChefAttributeHash.py ├── ChefArray.py ├── ChefLaunchd.py ├── ChefRemotePackage.py ├── ChefMacOSXUserDefaults.py └── ChefRemoteDirectory.py ├── Shared_Processors ├── SharedProcessors.recipe ├── FileAppender.py ├── PackageInfoVersioner.py ├── SHAChecksum.py ├── Rsync.py ├── InstallsArrayFineTuning.py ├── DirectoryList.py ├── SubDirectoryList.py └── README.md ├── .pre-commit-config.yaml ├── Duo ├── duo.download.recipe ├── duo.pkg.recipe ├── duo.extract.recipe ├── ConfigHeaderVersioner.py └── ConfigureMakeInstaller.py ├── Intellij ├── Intellij.download.recipe ├── Intellij.install.recipe ├── Intellij.munki.recipe └── IntellijURLProvider.py ├── BlueJeans ├── BlueJeans.download.recipe └── BlueJeans.munki.recipe ├── Mosh ├── mosh.download.recipe ├── mosh.munki.recipe └── MoshVersioner.py ├── DbVisualizer ├── DbVisualizer.download.recipe ├── DbVisualizer.dmg.recipe ├── DbVisualizer.pkg.recipe ├── DbVisualizer.install.recipe └── DbVisualizer.munki.recipe ├── Framer ├── Framer.download.recipe └── Framer.munki.recipe ├── android_sdk ├── android_sdk.minimal.pkg.recipe ├── android_sdk.minimal.download.recipe ├── android_sdk.minimal.munki.recipe ├── AndroidSDKVersioner.py ├── PropertiesWriter.py ├── AndroidXMLParser.py └── AndroidExtraXMLParser.py ├── android_ndk ├── android_ndk.download.recipe ├── android_ndk.dmg.recipe ├── AndroidNDKVersioner.py └── android_ndk.munki.recipe ├── Xcode ├── Xcode.extract.recipe ├── Xcode.download.recipe ├── XcodeVersionedName.munki.recipe ├── XcodeXIPUnpacker.py ├── XcodeBuildNumberEmitter.py ├── Xcode.munki.recipe ├── XcodeVersionEmitter.py ├── AppleDataGatherer.py ├── XcodeFileNamer.py └── XcodeVersioner.py ├── Acrolinx ├── Acrolinx.download.recipe ├── Acrolinx.munki.recipe └── AcrolinxURLProvider.py ├── VMwareFusionDeploy ├── VMwareFusionDeploy.pkg.recipe └── VMwareFusionDeploy.munki.recipe ├── AdoptOpenJDK ├── AdoptOpenJDK11.download.recipe ├── AdoptOpenJDK11.munki.recipe └── AdoptOpenJDKURLProvider.py ├── LobbyVideo ├── DateVersioner.py ├── lobbyvideo.dmg.recipe └── lobbyvideo.munki.recipe ├── SQLDeveloper ├── SQLDeveloper.dmg.recipe ├── SQLDeveloperVersioner.py └── SQLDeveloper.munki.recipe ├── munkitools ├── munkitools4.download.recipe ├── munkitools3.download.recipe ├── munkitools3.pkg.recipe └── munkitools4.pkg.recipe └── CONTRIBUTING.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Where did all the recipes go? 2 | 3 | This repo is being decommissioned. All modern recipes are migrated to [nmcspadden-recipes](https://github.com/autopkg/nmcspadden-recipes). 4 | 5 | Thank you for being a user of this repo. Thanks to all the contributors! -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Facebook has adopted a Code of Conduct that we expect project participants to adhere to. 4 | Please read the [full text](https://code.fb.com/codeofconduct/) 5 | so that you can understand what actions will and will not be tolerated. 6 | -------------------------------------------------------------------------------- /Chef_Processors/ChefProcessors.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Recipe stub for any Shared Processors in this directory. 9 | Identifier 10 | com.facebook.autopkg.shared.chef 11 | Input 12 | 13 | MinimumVersion 14 | 0.4.0 15 | Process 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Shared_Processors/SharedProcessors.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Recipe stub for any Shared Processors in this directory. 9 | 10 | Identifier 11 | com.facebook.autopkg.shared 12 | Input 13 | 14 | MinimumVersion 15 | 0.4.0 16 | Process 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/homebysix/pre-commit-macadmin 3 | rev: v1.4.0 4 | hooks: 5 | - id: check-autopkg-recipes 6 | args: ['--recipe-prefix=com.facebook.autopkg.'] 7 | - id: forbid-autopkg-overrides 8 | - id: forbid-autopkg-trust-info 9 | - id: check-plists 10 | - repo: https://github.com/pre-commit/pre-commit-hooks 11 | rev: v2.2.3 12 | hooks: 13 | - id: check-added-large-files 14 | args: [--maxkb=100] 15 | - id: check-ast 16 | - id: check-byte-order-marker 17 | - id: check-case-conflict 18 | - id: check-docstring-first 19 | - id: check-merge-conflict 20 | - id: end-of-file-fixer 21 | - id: fix-encoding-pragma 22 | - id: mixed-line-ending 23 | - id: trailing-whitespace 24 | args: [--markdown-linebreak-ext=md] 25 | -------------------------------------------------------------------------------- /Duo/duo.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest release of Duo. 9 | Identifier 10 | com.facebook.autopkg.download.duo 11 | Input 12 | 13 | NAME 14 | Duo 15 | 16 | MinimumVersion 17 | 0.2.0 18 | Process 19 | 20 | 21 | Processor 22 | DeprecationWarning 23 | Arguments 24 | 25 | warning_message 26 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Intellij/Intellij.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest Intellij disk image. 9 | Identifier 10 | com.facebook.autopkg.download.intellij 11 | Input 12 | 13 | NAME 14 | Intellij 15 | 16 | MinimumVersion 17 | 0.6.0 18 | Process 19 | 20 | 21 | Processor 22 | DeprecationWarning 23 | Arguments 24 | 25 | warning_message 26 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /BlueJeans/BlueJeans.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest release of BlueJeans. 9 | Identifier 10 | com.facebook.autopkg.download.bluejeans 11 | Input 12 | 13 | NAME 14 | BlueJeans 15 | 16 | MinimumVersion 17 | 0.2.0 18 | Process 19 | 20 | 21 | Processor 22 | DeprecationWarning 23 | Arguments 24 | 25 | warning_message 26 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Mosh/mosh.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest release of mosh. 9 | Identifier 10 | com.facebook.autopkg.download.mosh 11 | Input 12 | 13 | NAME 14 | Mosh 15 | PRERELEASES 16 | True 17 | 18 | MinimumVersion 19 | 0.5.0 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DbVisualizer/DbVisualizer.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the latest version of DbVisualizer. 9 | Identifier 10 | com.facebook.autopkg.download.dbvisualizer 11 | Input 12 | 13 | NAME 14 | DbVisualizer 15 | VERSION 16 | 11 17 | 18 | MinimumVersion 19 | 0.5.0 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Duo/duo.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Packages Duo. 9 | Identifier 10 | com.facebook.autopkg.pkg.duo 11 | Input 12 | 13 | NAME 14 | Duo 15 | PREFIX_PATH 16 | opt/duo 17 | 18 | MinimumVersion 19 | 0.2.0 20 | ParentRecipe 21 | com.facebook.autopkg.extract.duo 22 | Process 23 | 24 | 25 | Processor 26 | DeprecationWarning 27 | Arguments 28 | 29 | warning_message 30 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Framer/Framer.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest Framer zip file. 9 | Identifier 10 | com.facebook.autopkg.download.framer 11 | Input 12 | 13 | DOWNLOAD_URL 14 | https://dl.devmate.com/com.motif.framer/FramerStudio.zip 15 | NAME 16 | Framer 17 | 18 | MinimumVersion 19 | 0.2.0 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Duo/duo.extract.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Extracts Duo. 9 | Identifier 10 | com.facebook.autopkg.extract.duo 11 | Input 12 | 13 | NAME 14 | Duo 15 | PREFIX_PATH 16 | opt/duo 17 | 18 | MinimumVersion 19 | 0.2.0 20 | ParentRecipe 21 | com.facebook.autopkg.download.duo 22 | Process 23 | 24 | 25 | Processor 26 | DeprecationWarning 27 | Arguments 28 | 29 | warning_message 30 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Intellij/Intellij.install.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads Intellij Disk Image and then moves it to Applications 9 | Identifier 10 | com.facebook.autopkg.install.intellij 11 | Input 12 | 13 | RELEASE 14 | latest 15 | 16 | MinimumVersion 17 | 0.1.0 18 | ParentRecipe 19 | com.facebook.autopkg.download.intellij 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DbVisualizer/DbVisualizer.dmg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads and makes a DMG of the latest version of DbVisualizer. 9 | Identifier 10 | com.facebook.autopkg.dmg.dbvisualizer 11 | Input 12 | 13 | NAME 14 | DbVisualizer 15 | 16 | MinimumVersion 17 | 0.5.0 18 | ParentRecipe 19 | com.facebook.autopkg.download.dbvisualizer 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android_sdk/android_sdk.minimal.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a package containing the Android SDK. 9 | Identifier 10 | com.facebook.autopkg.pkg.android_sdk.minimal 11 | Input 12 | 13 | NAME 14 | android_sdk 15 | 16 | MinimumVersion 17 | 0.2.0 18 | ParentRecipe 19 | com.facebook.autopkg.download.android_sdk.minimal 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DbVisualizer/DbVisualizer.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the current release version of DbVisualizer and builds a package. 9 | Identifier 10 | com.facebook.autopkg.pkg.dbvisualizer 11 | Input 12 | 13 | NAME 14 | DbVisualizer 15 | 16 | MinimumVersion 17 | 0.2.0 18 | ParentRecipe 19 | com.facebook.autopkg.download.dbvisualizer 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android_sdk/android_sdk.minimal.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads a minimal set of the latest release of Android SDK. 9 | Identifier 10 | com.facebook.autopkg.download.android_sdk.minimal 11 | Input 12 | 13 | NAME 14 | android_sdk 15 | 16 | MinimumVersion 17 | 0.5.0 18 | Process 19 | 20 | 21 | Processor 22 | DeprecationWarning 23 | Arguments 24 | 25 | warning_message 26 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /DbVisualizer/DbVisualizer.install.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the current release version of DbVisualizer, builds an installer package and installs it. 9 | Identifier 10 | com.facebook.autopkg.install.dbvisualizer 11 | Input 12 | 13 | NAME 14 | DbVisualizer 15 | 16 | MinimumVersion 17 | 0.4.0 18 | ParentRecipe 19 | com.facebook.autopkg.pkg.dbvisualizer 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android_ndk/android_ndk.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads latest release of Android NDK. 9 | Identifier 10 | com.facebook.autopkg.download.android_ndk 11 | Input 12 | 13 | NAME 14 | android_ndk 15 | RELEASE 16 | r.* 17 | 18 | MinimumVersion 19 | 0.5.0 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /android_ndk/android_ndk.dmg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a disk image containing the Android NDK. 9 | Identifier 10 | com.facebook.autopkg.dmg.android_ndk 11 | Input 12 | 13 | NAME 14 | android_ndk 15 | 16 | MinimumVersion 17 | 0.2.0 18 | ParentRecipe 19 | com.facebook.autopkg.download.android_ndk 20 | Process 21 | 22 | 23 | Processor 24 | DeprecationWarning 25 | Arguments 26 | 27 | warning_message 28 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Xcode/Xcode.extract.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Description 7 | Extract Xcode from a XIP. Requires passing in a XIP containing Xcode. 8 | Identifier 9 | com.facebook.autopkg.xcode.extract 10 | Input 11 | 12 | NAME 13 | Xcode 14 | BUILD_NUMBER_EMIT_PATH 15 | %RECIPE_CACHE_DIR%/xcode_build_number 16 | 17 | MinimumVersion 18 | 1.0.4 19 | ParentRecipe 20 | com.facebook.autopkg.xcode.downloader 21 | Process 22 | 23 | 24 | Processor 25 | DeprecationWarning 26 | Arguments 27 | 28 | warning_message 29 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Acrolinx/Acrolinx.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the latest version of Acrolinx and imports it into Munki. 9 | Identifier 10 | com.facebook.autopkg.download.Acrolinx 11 | Input 12 | 13 | NAME 14 | Acrolinx 15 | AC_USERNAME 16 | username 17 | AC_PASSWORD 18 | password 19 | 20 | MinimumVersion 21 | 2.0 22 | Process 23 | 24 | 25 | Processor 26 | DeprecationWarning 27 | Arguments 28 | 29 | warning_message 30 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Shared_Processors/FileAppender.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """Processor that creates a file.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | from autopkglib import Processor, ProcessorError 13 | 14 | __all__ = ["FileAppender"] 15 | 16 | 17 | class FileAppender(Processor): 18 | """Append contents to the end of a file.""" 19 | 20 | description = __doc__ 21 | input_variables = { 22 | "file_path": {"required": True, "description": "Path to a file to append to."}, 23 | "file_content": {"required": True, "description": "Contents to add to a file."}, 24 | } 25 | output_variables = {} 26 | 27 | def main(self): 28 | try: 29 | with open(self.env["file_path"], "a") as fileref: 30 | fileref.write(self.env["file_content"]) 31 | self.output("Appened to file at %s" % self.env["file_path"]) 32 | except BaseException as err: 33 | raise ProcessorError( 34 | "Can't append to file at %s: %s" % (self.env["file_path"], err) 35 | ) 36 | # clean the variable up afterwards to not poison future runs 37 | self.env["file_content"] = "" 38 | self.env["file_path"] = "" 39 | 40 | 41 | if __name__ == "__main__": 42 | PROCESSOR = FileAppender() 43 | PROCESSOR.execute_shell() 44 | -------------------------------------------------------------------------------- /Xcode/Xcode.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Description 7 | Download Xcode from the Apple dev portal. You must override the APPLE_ID and PASSWORD_FILE. BETA must either be empty for stable releases or set to "Beta" in order to match Xcode betas. 8 | Identifier 9 | com.facebook.autopkg.xcode.downloader 10 | Input 11 | 12 | NAME 13 | Xcode 14 | APPLE_ID 15 | dev@domain.com 16 | PASSWORD_FILE 17 | secret.txt 18 | BETA 19 | 20 | PATTERN 21 | (.*\/Xcode_.*\/Xcode.*.xip) 22 | NOSKIP 23 | 24 | VERSION_EMIT_PATH 25 | %RECIPE_CACHE_DIR%/xcode_tag 26 | 27 | MinimumVersion 28 | 1.0.4 29 | Process 30 | 31 | 32 | Processor 33 | DeprecationWarning 34 | Arguments 35 | 36 | warning_message 37 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /VMwareFusionDeploy/VMwareFusionDeploy.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a VMwareFusion mass deployment package DMG. Requires justinrummel-recipes to download. You can substitute your own deploy.ini file in an override by placing the content in the DEPLOY_INI_FILE input variable. At a minimum, you'll need to put your license key in, or the postflight will fail. 9 | Identifier 10 | com.facebook.autopkg.pkg.deploy.VMwareFusion 11 | Input 12 | 13 | DEPLOY_INI_FILE 14 | [Volume License] 15 | key = XXXXX-XXXXX-XXXXX-XXXXX-XXXXX 16 | 17 | [UI Defaults] 18 | 19 | [Locations] 20 | 21 | [Applications] 22 | 23 | [Virtual Machines] 24 | 25 | NAME 26 | VMwareFusionDeploy 27 | 28 | MinimumVersion 29 | 0.2.5 30 | ParentRecipe 31 | com.justinrummel.download.VMwareFusion 32 | Process 33 | 34 | 35 | Processor 36 | DeprecationWarning 37 | Arguments 38 | 39 | warning_message 40 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /AdoptOpenJDK/AdoptOpenJDK11.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the current release version of AdoptOpenJDK 11. JVM defaults to "hotspot", or you can use "openj9". JDK_VERSION is which JDK OpenJDK version you wish to use, defaults to 11. 9 | Identifier 10 | com.facebook.autopkg.download.AdoptOpenJDK11 11 | Input 12 | 13 | NAME 14 | AdoptOpenJDK11 15 | JVM_TYPE 16 | hotspot 17 | JDK_TYPE 18 | jdk 19 | JDK_VERSION 20 | 11 21 | BINARY_TYPE 22 | pkg 23 | RELEASE 24 | latest 25 | 26 | MinimumVersion 27 | 1.4.1 28 | Process 29 | 30 | 31 | Processor 32 | DeprecationWarning 33 | Arguments 34 | 35 | warning_message 36 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Intellij/Intellij.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the latest Intellij disk image and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.intellij 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/Intellij 15 | NAME 16 | Intellij 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | description 24 | Lightweight IDE for Java SE, Groovy and Scala development. 25 | display_name 26 | Intellij Community Edition 27 | name 28 | %NAME% 29 | unattended_install 30 | 31 | 32 | 33 | MinimumVersion 34 | 0.2.0 35 | ParentRecipe 36 | com.facebook.autopkg.download.intellij 37 | Process 38 | 39 | 40 | Processor 41 | DeprecationWarning 42 | Arguments 43 | 44 | warning_message 45 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Mosh/mosh.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Imports latest release of mosh into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.mosh 11 | Input 12 | 13 | NAME 14 | Mosh 15 | PRERELEASES 16 | True 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | category 24 | Developer Tools 25 | developer 26 | MIT 27 | display_name 28 | Mosh 29 | minimum_os_version 30 | 10.6 31 | name 32 | %NAME% 33 | unattended_install 34 | 35 | 36 | 37 | MinimumVersion 38 | 0.5.0 39 | ParentRecipe 40 | com.facebook.autopkg.download.mosh 41 | Process 42 | 43 | 44 | Processor 45 | DeprecationWarning 46 | Arguments 47 | 48 | warning_message 49 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /android_sdk/android_sdk.minimal.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads a minimal set of Android SDK tools, creates a PKG out of it, and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.android_sdk.minimal 11 | Input 12 | 13 | DESTINATION_PATH 14 | /opt/android_sdk 15 | MUNKI_REPO_SUBDIR 16 | apps/%NAME% 17 | NAME 18 | android_sdk 19 | pkginfo 20 | 21 | catalogs 22 | 23 | testing 24 | 25 | category 26 | Developer Tools 27 | description 28 | Android SDK. 29 | developer 30 | Google 31 | display_name 32 | Android SDK 33 | unattended_install 34 | 35 | 36 | 37 | MinimumVersion 38 | 0.2.0 39 | ParentRecipe 40 | com.facebook.autopkg.pkg.android_sdk.minimal 41 | Process 42 | 43 | 44 | Processor 45 | DeprecationWarning 46 | Arguments 47 | 48 | warning_message 49 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /LobbyVideo/DateVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | from __future__ import absolute_import 19 | 20 | import datetime 21 | import time 22 | 23 | from autopkglib import Processor 24 | 25 | __all__ = ["DateVersioner"] 26 | 27 | 28 | class DateVersioner(Processor): 29 | description = "Places current date and time into %version%." 30 | input_variables = { 31 | "notime": { 32 | "required": False, 33 | "description": ( 34 | "True/false. If true, ", 35 | "only the current date is provided. Defaults to false.", 36 | ), 37 | } 38 | } 39 | output_variables = {"version": {"description": "Current date and time as version."}} 40 | 41 | __doc__ = description 42 | 43 | def main(self): 44 | try: 45 | notime = self.env["notime"] 46 | except KeyError: 47 | notime = False 48 | self.output("notime is %s" % notime) 49 | self.env["version"] = ( 50 | str(datetime.date.today()) + "_" + str(time.strftime("%H-%M-%S")) 51 | ) 52 | if notime: 53 | self.env["version"] = str(datetime.date.today()) 54 | self.output("Version is set to %s" % self.env["version"]) 55 | 56 | 57 | if __name__ == "__main__": 58 | processor = DateVersioner() 59 | processor.execute_shell() 60 | -------------------------------------------------------------------------------- /Shared_Processors/PackageInfoVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for PackageInfoVersioner class.""" 9 | 10 | # Disabling warnings for env members and imports that only affect recipe- 11 | # specific processors. 12 | # pylint: disable=e1101,f0401 13 | 14 | from __future__ import absolute_import 15 | 16 | from xml.dom import minidom 17 | 18 | from autopkglib import Processor, ProcessorError 19 | 20 | __all__ = ["PackageInfoVersioner"] 21 | 22 | 23 | class PackageInfoVersioner(Processor): 24 | """Get version from a PackageInfo file in a distribution/bundle package.""" 25 | 26 | description = __doc__ 27 | input_variables = { 28 | "package_info_path": { 29 | "required": True, 30 | "description": ( 31 | "Path to PackageInfo file inside a distribution", 32 | "/bundle package.", 33 | ), 34 | } 35 | } 36 | output_variables = { 37 | "pkg_id": { 38 | "description": "Package identifier returned from pkg-info field in PackageInfo." 39 | }, 40 | "version": { 41 | "description": "Version returned from pkg-info field in PackageInfo." 42 | } 43 | } 44 | 45 | __doc__ = description 46 | 47 | def main(self): 48 | try: 49 | dom = minidom.parse(self.env["package_info_path"]) 50 | except IOError as err: 51 | raise ProcessorError(err) 52 | pkgrefs = dom.getElementsByTagName("pkg-info") 53 | self.env["pkg_id"] = pkgrefs[0].attributes["identifier"].value 54 | self.output("Found pkg_id %s" % self.env["pkg_id"]) 55 | self.env["version"] = pkgrefs[0].attributes["version"].value 56 | self.output("Found version %s" % self.env["version"]) 57 | 58 | 59 | if __name__ == "__main__": 60 | PROCESSOR = PackageInfoVersioner() 61 | PROCESSOR.execute_shell() 62 | -------------------------------------------------------------------------------- /Framer/Framer.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the latest Framer zip file and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.framer 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/Framer 15 | NAME 16 | Framer 17 | pkginfo 18 | 19 | catalogs 20 | 21 | prod 22 | trusted_testers 23 | testing 24 | 25 | category 26 | Design 27 | description 28 | Framer is a design tool that uses code to make anything possible. Pioneer new patterns and groundbreaking designs. Find the best solution, not just the expected one. 29 | developer 30 | Motiv Tools, BV 31 | display_name 32 | Framer Studio 33 | name 34 | %NAME% 35 | unattended_install 36 | 37 | 38 | 39 | MinimumVersion 40 | 0.2.0 41 | ParentRecipe 42 | com.facebook.autopkg.download.framer 43 | Process 44 | 45 | 46 | Processor 47 | DeprecationWarning 48 | Arguments 49 | 50 | warning_message 51 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Shared_Processors/SHAChecksum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) 2015, Facebook, Inc. 4 | # All rights reserved. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree. An additional grant 8 | # of patent rights can be found in the PATENTS file in the same directory. 9 | """See docstring for SHAChecksum class""" 10 | 11 | # Disabling warnings for env members and imports that only affect recipe- 12 | # specific processors. 13 | # pylint: disable=e1101,f0401 14 | 15 | import subprocess 16 | 17 | from autopkglib import Processor, ProcessorError 18 | 19 | 20 | __all__ = ["SHAChecksum"] 21 | 22 | 23 | class SHAChecksum(Processor): 24 | """Calculate checksum for a file""" 25 | 26 | description = __doc__ 27 | input_variables = { 28 | "source_file": { 29 | "required": True, 30 | "description": ("Path to file to calculate checksum on."), 31 | }, 32 | "checksum_type": { 33 | "required": False, 34 | "description": ( 35 | "Checksum type, will be passed directly to ", 36 | "shasum -a. See manpage for available options. " 37 | "Defaults to SHA1.", 38 | ), 39 | }, 40 | } 41 | output_variables = { 42 | "checksum": { 43 | "description": "Version returned from pkg-info field in PackageInfo." 44 | } 45 | } 46 | 47 | __doc__ = description 48 | 49 | def main(self): 50 | sha_args = self.env.get("checksum_type", None) 51 | cmd = ["/usr/bin/shasum"] 52 | if sha_args: 53 | cmd.append("-a") 54 | cmd.append(sha_args) 55 | cmd.append(self.env["source_file"]) 56 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 57 | (shaout, shaerr) = proc.communicate() 58 | if shaerr: 59 | raise ProcessorError(shaerr) 60 | self.output(shaout) 61 | self.env["checksum"] = shaout.split()[0].decode("utf-8") 62 | 63 | 64 | if __name__ == "__main__": 65 | PROCESSOR = SHAChecksum() 66 | PROCESSOR.execute_shell() 67 | -------------------------------------------------------------------------------- /Shared_Processors/Rsync.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2015, Facebook, Inc. 5 | # All rights reserved. 6 | # 7 | # This source code is licensed under the BSD-style license found in the 8 | # LICENSE file in the root directory of this source tree. An additional grant 9 | # of patent rights can be found in the PATENTS file in the same directory. 10 | """See docstring for Rsync class.""" 11 | 12 | from __future__ import absolute_import 13 | 14 | import subprocess 15 | 16 | from autopkglib import Processor, ProcessorError 17 | 18 | __all__ = ["Rsync"] 19 | 20 | 21 | class Rsync(Processor): 22 | """Rsyncs a path to another path.""" 23 | 24 | description = __doc__ 25 | input_variables = { 26 | "source_path": { 27 | "required": True, 28 | "description": ("Path to file or directory to copy from."), 29 | }, 30 | "destination_path": { 31 | "required": True, 32 | "description": ("Path to file or directory to copy to."), 33 | }, 34 | "rsync_arguments": { 35 | "required": False, 36 | "description": ("List of arguments passed to rsync directly."), 37 | }, 38 | "rsync_path": { 39 | "required": False, 40 | "description": ("Custom path to rsync. Defaults to /usr/bin/rsync."), 41 | }, 42 | } 43 | output_variables = {} 44 | 45 | __doc__ = description 46 | 47 | def main(self): 48 | rsync_location = self.env.get("rsync_path", "/usr/bin/rsync") 49 | rsync_args = self.env.get("rsync_arguments", []) 50 | if isinstance(rsync_args, basestring): 51 | raise ProcessorError("rsync_args must be a list!") 52 | cmd = [rsync_location] 53 | if rsync_args: 54 | cmd.extend(rsync_args) 55 | cmd.extend([self.env["source_path"], self.env["destination_path"]]) 56 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 57 | (rout, rerr) = proc.communicate() 58 | if rerr: 59 | raise ProcessorError(rerr) 60 | self.output(rout) 61 | 62 | 63 | if __name__ == "__main__": 64 | PROCESSOR = Rsync() 65 | PROCESSOR.execute_shell() 66 | -------------------------------------------------------------------------------- /Xcode/XcodeVersionedName.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Download, extract, and import Xcode as a unique entry into Munki. You must override the APPLE_ID and PASSWORD. 9 | Identifier 10 | com.facebook.autopkg.xcode_versioned.munki 11 | Input 12 | 13 | APPLE_ID 14 | dev@domain.com 15 | DESTINATION_APP_NAME 16 | Xcode.app 17 | ICON_NAME 18 | Xcode.png 19 | MUNKI_REPO_SUBDIR 20 | apps/apple/xcode/ 21 | NAME 22 | Xcode 23 | PASSWORD_FILE 24 | secret.txt 25 | 26 | ARBITRARY_SUFFIX 27 | 28 | pkginfo 29 | 30 | catalogs 31 | 32 | testing 33 | 34 | description 35 | Xcode 36 | display_name 37 | %NAME% 38 | name 39 | %NAME% 40 | unattended_install 41 | 42 | 43 | 44 | MinimumVersion 45 | 1.0.4 46 | ParentRecipe 47 | com.facebook.autopkg.xcode.extract 48 | Process 49 | 50 | 51 | Processor 52 | DeprecationWarning 53 | Arguments 54 | 55 | warning_message 56 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /DbVisualizer/DbVisualizer.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads and makes a DMG of the latest version of DbVisualizer, and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.dbvisualizer 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/DbVis 15 | NAME 16 | DbVisualizer 17 | VERSION 18 | 11 19 | pkginfo 20 | 21 | catalogs 22 | 23 | testing 24 | 25 | category 26 | Database Tools 27 | description 28 | DbVisualizer is the universal database tool for developers, DBAs and analysts. It is the perfect solution since the same tool can be used on all major operating systems accessing a wide range of databases. 29 | developer 30 | DbVis Software 31 | display_name 32 | DbVisualizer 33 | requires 34 | 35 | OracleJava7 36 | 37 | unattended_install 38 | 39 | 40 | 41 | MinimumVersion 42 | 0.5.0 43 | ParentRecipe 44 | com.facebook.autopkg.dmg.dbvisualizer 45 | Process 46 | 47 | 48 | Processor 49 | DeprecationWarning 50 | Arguments 51 | 52 | warning_message 53 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Shared_Processors/InstallsArrayFineTuning.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for PackageInfoVersioner class.""" 9 | 10 | 11 | from __future__ import absolute_import 12 | 13 | from autopkglib import Processor, ProcessorError 14 | 15 | __all__ = ["InstallsArrayFineTuning"] 16 | 17 | 18 | class InstallsArrayFineTuning(Processor): 19 | """Change an installs array to allow fine-tuning of a type.""" 20 | 21 | description = __doc__ 22 | input_variables = { 23 | "additional_pkginfo": { 24 | "required": True, 25 | "description": ("Dictionary containing an installs array."), 26 | }, 27 | "changes": { 28 | "required": True, 29 | "description": ( 30 | "List of dictionaries containing replacement values " 31 | "for installs types. Each dictionary must contain a " 32 | "path and the new type." 33 | ), 34 | }, 35 | } 36 | 37 | output_variables = { 38 | "changed_pkginfo": {"description": "Fine tuned additional_pkginfo dictionary."} 39 | } 40 | 41 | __doc__ = description 42 | 43 | def main(self): 44 | """Magic.""" 45 | current = self.env["additional_pkginfo"]["installs"] 46 | changes = self.env["changes"] 47 | for change in changes: 48 | path = change.get("path", None) 49 | if not path: 50 | raise ProcessorError("No path found in change!") 51 | newtype = change.get("type", None) 52 | if not newtype: 53 | raise ProcessorError("No type found in change!") 54 | # Replace the installs 55 | for install in current: 56 | if install["path"] == path: 57 | install["type"] = newtype 58 | self.output("Replacing type for %s to %s" % (path, newtype)) 59 | self.env["changed_pkginfo"] = current 60 | 61 | 62 | if __name__ == "__main__": 63 | PROCESSOR = InstallsArrayFineTuning() 64 | PROCESSOR.execute_shell() 65 | -------------------------------------------------------------------------------- /android_ndk/AndroidNDKVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | """Return version for Android NDK.""" 4 | # 5 | # Copyright (c) Facebook, Inc. and its affiliates. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | 19 | from __future__ import absolute_import 20 | 21 | import os 22 | import shlex 23 | 24 | from autopkglib import Processor, ProcessorError 25 | 26 | __all__ = ["AndroidNDKVersioner"] 27 | 28 | 29 | class AndroidNDKVersioner(Processor): 30 | """Return version for Android NDK.""" 31 | 32 | description = ( 33 | "Detect version of downloaded Android NDK based on source.properties." 34 | ) 35 | input_variables = { 36 | "properties_path": { 37 | "required": True, 38 | "description": "File to parse for version info.", 39 | } 40 | } 41 | output_variables = { 42 | "release_num": {"description": "Release of download."}, 43 | "version": {"description": "Version of download."}, 44 | } 45 | 46 | def main(self): 47 | """Main.""" 48 | path = self.env.get("properties_path") 49 | if not os.path.isfile(path): 50 | raise ProcessorError("%s doesn't exist!" % path) 51 | with open(path, "rb") as f: 52 | data = f.read() 53 | split_data = shlex.split(data) 54 | # Version is defined in the files 55 | version = split_data[split_data.index("Pkg.Revision") + 2] 56 | self.env["version"] = version.split()[-1] 57 | # Release is just based on filename 58 | self.env["release_num"] = os.path.basename(os.path.dirname(path)).split("-")[-1] 59 | 60 | 61 | if __name__ == "__main__": 62 | PROCESSOR = AndroidNDKVersioner() 63 | PROCESSOR.execute_shell() 64 | -------------------------------------------------------------------------------- /BlueJeans/BlueJeans.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Imports the latest release of BlueJeans into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.bluejeans 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/%NAME% 15 | NAME 16 | BlueJeans 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | category 24 | Productivity 25 | description 26 | As an alternate to the browser plugin, Mac and Windows users can participate in live meetings using the Blue Jeans desktop app. This app will download automatically when you choose the Desktop App connection option to join a Blue Jeans meeting. 27 | 28 | With the Blue Jeans desktop app, you can: 29 | 30 | Host and join live meetings 31 | Start an instant meeting 32 | See and share video, audio, and content 33 | developer 34 | BlueJeans 35 | display_name 36 | Blue Jeans 37 | name 38 | %NAME% 39 | unattended_install 40 | 41 | 42 | 43 | MinimumVersion 44 | 0.2.0 45 | ParentRecipe 46 | com.facebook.autopkg.download.bluejeans 47 | Process 48 | 49 | 50 | Processor 51 | DeprecationWarning 52 | Arguments 53 | 54 | warning_message 55 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Acrolinx/Acrolinx.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the latest version of Acrolinx and imports it into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.Acrolinx 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/acrolinx 15 | NAME 16 | Acrolinx 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | category 24 | Productivity 25 | description 26 | Acrolinx helps you create more readable, findable, and engaging content. 27 | developer 28 | Acrolinx 29 | display_name 30 | Acrolinx 31 | name 32 | %NAME% 33 | unattended_install 34 | 35 | 36 | 37 | MinimumVersion 38 | 2.0 39 | ParentRecipe 40 | com.facebook.autopkg.download.Acrolinx 41 | Process 42 | 43 | 44 | Processor 45 | DeprecationWarning 46 | Arguments 47 | 48 | warning_message 49 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /AdoptOpenJDK/AdoptOpenJDK11.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Downloads the current release version of AdoptOpenJDK 11 and imports into Munki. 9 | Identifier 10 | com.github.facebook.munki.AdoptOpenJDK11 11 | Input 12 | 13 | NAME 14 | AdoptOpenJDK11 15 | MUNKI_REPO_SUBDIR 16 | apps/openjdk 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | category 24 | Developer Tools 25 | description 26 | Adopt Open JDK 11 27 | developer 28 | AdoptOpenJDK 29 | display_name 30 | Adopt OpenJDK 11 31 | name 32 | %NAME% 33 | unattended_install 34 | 35 | 36 | 37 | MinimumVersion 38 | 1.4.1 39 | ParentRecipe 40 | com.facebook.autopkg.download.AdoptOpenJDK11 41 | Process 42 | 43 | 44 | Processor 45 | DeprecationWarning 46 | Arguments 47 | 48 | warning_message 49 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /android_ndk/android_ndk.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Takes the EXTRACTED DMG and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.android_ndk 11 | Input 12 | 13 | DESTINATION_PATH 14 | /opt/android_ndk 15 | MUNKI_REPO_SUBDIR 16 | apps/%NAME% 17 | NAME 18 | android_ndk 19 | pkginfo 20 | 21 | catalogs 22 | 23 | testing 24 | 25 | category 26 | Developer Tools 27 | description 28 | Android NDK. Be sure to set your ENV variable for ANDROID_NDK_REPOSITORY to /opt/android_ndk/. 29 | developer 30 | Google 31 | display_name 32 | Android NDK 33 | unattended_install 34 | 35 | 36 | 37 | MinimumVersion 38 | 0.2.0 39 | ParentRecipe 40 | com.facebook.autopkg.dmg.android_ndk 41 | Process 42 | 43 | 44 | Processor 45 | DeprecationWarning 46 | Arguments 47 | 48 | warning_message 49 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /Xcode/XcodeXIPUnpacker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """Unpack an Xcode XIP.""" 18 | 19 | import os 20 | import subprocess 21 | 22 | from autopkglib import Processor, ProcessorError 23 | 24 | 25 | __all__ = ["XcodeXIPUnpacker"] 26 | 27 | 28 | class XcodeXIPUnpacker(Processor): 29 | """Unpack a XIP file from Apple.""" 30 | 31 | description = "Unpack an Apple XIP file." 32 | input_variables = { 33 | "PKG": {"required": True, "description": "Path to an Xcode .xip file."}, 34 | "output_path": { 35 | "required": False, 36 | "description": ( 37 | "Path to unpack the contents. Defaults to " 38 | "%RECIPE_CACHE_DIR%/%NAME%_unpack." 39 | ), 40 | }, 41 | } 42 | output_variables = {} 43 | 44 | __doc__ = description 45 | 46 | def main(self): 47 | """Main.""" 48 | xip_path = self.env["PKG"] 49 | if self.env.get("output_path"): 50 | output = self.env["output_path"] 51 | else: 52 | output = os.path.join( 53 | self.env["RECIPE_CACHE_DIR"], self.env["NAME"] + "_unpack" 54 | ) 55 | if not os.path.isdir(output): 56 | os.makedirs(output) 57 | 58 | self.output( 59 | "Extracting xip archive, please be patient, this could take a long time..." 60 | ) 61 | os.chdir(output) 62 | cmd = ["/usr/bin/xip", "--expand", xip_path] 63 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 64 | (out, err) = proc.communicate() 65 | if err: 66 | raise ProcessorError(err) 67 | self.output("Finished xip unpack.") 68 | 69 | 70 | if __name__ == "__main__": 71 | processor = XcodeXIPUnpacker() 72 | processor.execute_shell() 73 | -------------------------------------------------------------------------------- /Xcode/XcodeBuildNumberEmitter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """ Emit Xcode Build Number to disk """ 18 | 19 | import os.path 20 | 21 | from autopkglib import Processor 22 | 23 | 24 | __all__ = ["XcodeBuildNumberEmitter"] 25 | 26 | 27 | class XcodeBuildNumberEmitter(Processor): 28 | """Emit file containing Xcode Build Number""" 29 | 30 | description = __doc__ 31 | input_variables = { 32 | "dont_skip": { 33 | "required": False, 34 | "default": False, 35 | "description": ("If this evaluates as truthy, do not skip this step."), 36 | }, 37 | "build_version": { 38 | "required": True, 39 | "description": ("The build version number for this Xcode Release"), 40 | }, 41 | "output_filepath": { 42 | "required": True, 43 | "description": ("Path to which xcode build number is emitted."), 44 | }, 45 | } 46 | output_variables = { 47 | "derived_filename": {"description": "The derived filename to emit."} 48 | } 49 | 50 | __doc__ = description 51 | 52 | def main(self): 53 | """Main.""" 54 | if not self.env["dont_skip"]: 55 | self.output("dont_skip is false, so skipping this Processor.") 56 | return 57 | 58 | build_number = self.env["build_version"] 59 | 60 | destination = os.path.expandvars(self.env["output_filepath"]) 61 | with open(destination, "w") as f: 62 | f.write(build_number) 63 | self.output( 64 | "Xcode build number ({}) written to disk at {}".format( 65 | build_number, 66 | destination, 67 | ) 68 | ) 69 | 70 | 71 | if __name__ == "__main__": 72 | PROCESSOR = XcodeBuildNumberEmitter() 73 | PROCESSOR.execute_shell() 74 | -------------------------------------------------------------------------------- /Chef_Processors/ChefAttributeList.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for ChefAttributeList class.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | import os.path 13 | 14 | from autopkglib import Processor 15 | 16 | __all__ = ["ChefAttributeList"] 17 | 18 | 19 | class ChefAttributeList(Processor): 20 | """Class for Attribute List.""" 21 | 22 | description = ( 23 | "Produces a Chef attribute variable for a list of items. " 24 | "The attribute prefixes correspond to node settings - i.e. " 25 | "default[category][prefix][attribute]." 26 | ) 27 | input_variables = { 28 | "attribute_version": { 29 | "required": True, 30 | "description": "Version of Munki this applies to.", 31 | }, 32 | "attribute": {"required": True, "description": "Name of attribute."}, 33 | "value": { 34 | "required": True, 35 | "description": ( 36 | "Single string containing list of items, separated by commas." 37 | ), 38 | }, 39 | "path_prefix": { 40 | "required": False, 41 | "description": "Path to prepend to each found item.", 42 | "default": "", 43 | }, 44 | } 45 | output_variables = { 46 | "chef_block": {"description": "Chef attribute block."}, 47 | "attribute_variable": {"description": "Full name of variable."}, 48 | } 49 | 50 | __doc__ = description 51 | 52 | def main(self): 53 | """Main.""" 54 | att_prefix = "munki['%s']['%s']" % ( 55 | self.env["attribute_version"], 56 | self.env["attribute"], 57 | ) 58 | self.env["chef_block"] = att_prefix + " = [\n" 59 | for value in self.env["value"].split(","): 60 | # attribute = '%s = [\n' 61 | # print "Value: %s" % value 62 | self.env["chef_block"] += " '%s',\n" % str( 63 | os.path.join(self.env["path_prefix"], value) 64 | ) 65 | self.env["chef_block"] += "]\n" 66 | self.output("Chef block: %s" % self.env["chef_block"]) 67 | self.env["attribute_variable"] = att_prefix.replace("default", "node") 68 | 69 | 70 | if __name__ == "__main__": 71 | PROCESSOR = ChefAttributeList() 72 | PROCESSOR.execute_shell() 73 | -------------------------------------------------------------------------------- /Mosh/MoshVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | """See docstring for MoshVersioner class""" 18 | 19 | # The majority of this code is taken from MunkiCommon: 20 | # https://github.com/munki/munki/blob/master/code/client/munkilib/munkicommon.py 21 | 22 | import os 23 | import subprocess 24 | import tempfile 25 | from xml.dom import minidom 26 | 27 | from autopkglib import Processor, ProcessorError 28 | 29 | 30 | __all__ = ["MoshVersioner"] 31 | 32 | 33 | class MoshVersioner(Processor): 34 | description = "Get version from Mosh download." 35 | input_variables = { 36 | "pathname": {"required": True, "description": ("Path to downloaded package.")} 37 | } 38 | output_variables = { 39 | "version": { 40 | "description": ( 41 | "Version info parsed, naively derived from the " "package's name." 42 | ) 43 | } 44 | } 45 | 46 | __doc__ = description 47 | 48 | def main(self): 49 | filepath = self.env["pathname"] 50 | pkgtmp = tempfile.mkdtemp() 51 | os.chdir(pkgtmp) 52 | cmd_extract = ["/usr/bin/xar", "-xf", filepath, "Distribution"] 53 | result = subprocess.call(cmd_extract) 54 | if result == 0: 55 | dom = minidom.parse(os.path.join(pkgtmp, "Distribution")) 56 | pkgrefs = dom.getElementsByTagName("pkg-ref") 57 | unfixed = pkgrefs[1].attributes["version"].value.encode("UTF-8") 58 | # At this point, unfixed_version is typically "mosh-1.x.x" 59 | self.env["version"] = unfixed.lstrip(b"mosh-").decode() 60 | self.output("Found version: %s" % self.env["version"]) 61 | else: 62 | raise ProcessorError( 63 | "An error occurred while extracting Distribution file" 64 | ) 65 | 66 | 67 | if __name__ == "__main__": 68 | PROCESSOR = MoshVersioner() 69 | PROCESSOR.execute_shell() 70 | -------------------------------------------------------------------------------- /Xcode/Xcode.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Description 7 | Download, extract, and import Xcode into Munki. You must override the APPLE_ID and PASSWORD. 8 | Identifier 9 | com.facebook.autopkg.xcode.munki 10 | Input 11 | 12 | NAME 13 | Xcode 14 | USE_VERSIONED_FILENAME 15 | 16 | FILENAME_SUFFIX 17 | 18 | MUNKI_REPO_SUBDIR 19 | apps/apple/xcode/ 20 | ICON_NAME 21 | Xcode.png 22 | pkginfo 23 | 24 | catalogs 25 | 26 | testing 27 | 28 | description 29 | Xcode 30 | display_name 31 | %NAME% 32 | name 33 | %NAME% 34 | postinstall_script 35 | #!/bin/sh 36 | # Ensure everyone is a member of "developer" group 37 | /usr/sbin/dseditgroup -o edit -a everyone -t group _developer 38 | # Enable Developer Mode 39 | /usr/sbin/DevToolsSecurity -enable 40 | # Accept the license 41 | /Applications/%fixed_filename%/Contents/Developer/usr/bin/xcodebuild -license accept 42 | # Install embedded packages 43 | for PKG in `/bin/ls /Applications/%fixed_filename%/Contents/Resources/Packages/*.pkg` ; do 44 | /usr/sbin/installer -pkg "$PKG" -target / 45 | done 46 | 47 | unattended_install 48 | 49 | 50 | 51 | MinimumVersion 52 | 1.0.4 53 | ParentRecipe 54 | com.facebook.autopkg.xcode.extract 55 | Process 56 | 57 | 58 | Processor 59 | DeprecationWarning 60 | Arguments 61 | 62 | warning_message 63 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /LobbyVideo/lobbyvideo.dmg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Pacakges the lobbyvideo file 9 | Identifier 10 | com.facebook.autopkg.dmg.lobbyvideo 11 | Input 12 | 13 | DESTINATION_PATH 14 | /Users/Shared 15 | NAME 16 | lobbyvideo 17 | RULESET_NAME 18 | lobbyvideo.mp4 19 | SOURCE_DIR 20 | /Users/Shared/lobby_video 21 | 22 | MinimumVersion 23 | 0.2.0 24 | Process 25 | 26 | 27 | Processor 28 | DeprecationWarning 29 | Arguments 30 | 31 | warning_message 32 | This recipe will soon be removed. Please remove it from your list of recipes. 33 | 34 | 35 | 36 | Arguments 37 | 38 | pkgdirs 39 | 40 | dmg_root 41 | 0775 42 | 43 | pkgroot 44 | %RECIPE_CACHE_DIR%/ 45 | 46 | Processor 47 | PkgRootCreator 48 | 49 | 50 | Arguments 51 | 52 | destination_path 53 | %RECIPE_CACHE_DIR%/dmg_root/ 54 | source_path 55 | %SOURCE_DIR%/%RULESET_NAME% 56 | 57 | Processor 58 | Copier 59 | 60 | 61 | Arguments 62 | 63 | notime 64 | 65 | 66 | Processor 67 | DateVersioner 68 | 69 | 70 | Arguments 71 | 72 | dmg_path 73 | %RECIPE_CACHE_DIR%/%NAME%-%version%.dmg 74 | dmg_root 75 | %RECIPE_CACHE_DIR%/dmg_root/ 76 | 77 | Processor 78 | DmgCreator 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /VMwareFusionDeploy/VMwareFusionDeploy.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Imports the VMwareFusion mass deployment package into Munki. Requires justinrummel-recipes to download. You can substitute your own deploy.ini file in an override by placing the content in the DEPLOY_INI_FILE input variable. At a minimum, you'll need to put your license key in (replace the XXXXXs), or the postflight will fail. 9 | Identifier 10 | com.facebook.autopkg.munki.deploy.VMwareFusion 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/VMware 15 | NAME 16 | VMwareFusion 17 | pkginfo 18 | 19 | blocking_applications 20 | 21 | VMware Fusion.app 22 | 23 | catalogs 24 | 25 | testing 26 | 27 | category 28 | Productivity 29 | description 30 | 31 | developer 32 | VMware 33 | display_name 34 | VMWare Fusion Pro 35 | minimum_os_version 36 | 10.13 37 | name 38 | %NAME% 39 | uninstall_method 40 | uninstall_script 41 | uninstall_script 42 | #!/bin/sh 43 | /bin/rm -rf /Applications/VMware\ Fusion.app 44 | /bin/rm -f /Library/Preferences/VMware Fusion/config 45 | 46 | 47 | 48 | MinimumVersion 49 | 0.2.5 50 | ParentRecipe 51 | com.facebook.autopkg.pkg.deploy.VMwareFusion 52 | Process 53 | 54 | 55 | Processor 56 | DeprecationWarning 57 | Arguments 58 | 59 | warning_message 60 | These recipes have moved into nmcspadden-recipes, and the identifiers have changed. Please update your overrides! 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /LobbyVideo/lobbyvideo.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a dmg of the lobbyvideo and imports into Munki. 9 | Identifier 10 | com.facebook.autopkg.munki.lobbyvideo 11 | Input 12 | 13 | MUNKI_REPO_SUBDIR 14 | apps/lobby/ 15 | NAME 16 | lobbyvideo 17 | pkginfo 18 | 19 | catalogs 20 | 21 | testing 22 | 23 | description 24 | Lobby Video 25 | display_name 26 | %NAME% 27 | name 28 | %NAME% 29 | unattended_install 30 | 31 | 32 | 33 | MinimumVersion 34 | 0.2.0 35 | ParentRecipe 36 | com.facebook.autopkg.dmg.lobbyvideo 37 | Process 38 | 39 | 40 | Processor 41 | DeprecationWarning 42 | Arguments 43 | 44 | warning_message 45 | This recipe will soon be removed. Please remove it from your list of recipes. 46 | 47 | 48 | 49 | Arguments 50 | 51 | additional_pkginfo 52 | 53 | version 54 | %version% 55 | 56 | 57 | Processor 58 | MunkiPkginfoMerger 59 | 60 | 61 | Arguments 62 | 63 | additional_makepkginfo_options 64 | 65 | --itemname=%RULESET_NAME% 66 | --destinationpath=%DESTINATION_PATH% 67 | --owner=root 68 | --group=wheel 69 | --mode=u+rwx,go+rx 70 | 71 | pkg_path 72 | %dmg_path% 73 | repo_subdirectory 74 | %MUNKI_REPO_SUBDIR% 75 | 76 | Processor 77 | MunkiImporter 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /Acrolinx/AcrolinxURLProvider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | """See docstring for AcrolinxURLProvider class""" 17 | 18 | from __future__ import absolute_import, division, print_function, unicode_literals 19 | 20 | from autopkglib import ProcessorError 21 | from autopkglib.URLGetter import URLGetter 22 | 23 | 24 | __all__ = ["AcrolinxURLProvider"] 25 | 26 | URL = "https://{}:{}@download.acrolinx.com:1443/api/deliverablePackages/575b1d0d401ae30b00e90f40/download/latest?preserve_credentials=true&proxy=true" 27 | 28 | 29 | class AcrolinxURLProvider(URLGetter): 30 | """Provides a download URL for Acrolinx.""" 31 | 32 | description = __doc__ 33 | input_variables = { 34 | "username": {"required": True, "description": "Username for authentication."}, 35 | "password": {"required": True, "description": "Password for authentication"}, 36 | } 37 | output_variables = {"url": {"description": "Download URL for Acrolinx."}} 38 | 39 | def main(self): 40 | """Find the download URL""" 41 | username = self.env["username"] 42 | password = self.env["password"] 43 | url = URL.format(username, password) 44 | # Fetch the API data 45 | curl_cmd = self.prepare_curl_cmd() 46 | curl_cmd.extend(["--head", url]) 47 | raw_headers = self.download_with_curl(curl_cmd) 48 | header = self.parse_headers(raw_headers) 49 | # Use semantic versioning for the version string, although historically this 50 | # hasn't been anything particularly problematic 51 | acrolinx_url = header.get("http_redirected") 52 | if not acrolinx_url: 53 | self.output(f"Header: {header}") 54 | raise ProcessorError( 55 | "Header did not contain an 'http_redirected' " 56 | "value containing the expected Acrolinx URL. Check your " 57 | "username and password." 58 | ) 59 | self.output(f"Found URL: {acrolinx_url}") 60 | self.env["url"] = acrolinx_url 61 | 62 | 63 | if __name__ == "__main__": 64 | PROCESSOR = AcrolinxURLProvider() 65 | PROCESSOR.execute_shell() 66 | -------------------------------------------------------------------------------- /SQLDeveloper/SQLDeveloper.dmg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a DMG for SQLDeveloper. You must provide your own .zip download using the -p argument. 9 | Identifier 10 | com.facebook.autopkg.dmg.sqldeveloper 11 | Input 12 | 13 | NAME 14 | SQLDeveloper 15 | 16 | MinimumVersion 17 | 0.5.1 18 | Process 19 | 20 | 21 | Comment 22 | Requires manually providing SQLDeveloper .zip download. 23 | Processor 24 | PackageRequired 25 | 26 | 27 | Arguments 28 | 29 | pkgdirs 30 | 31 | pkgroot 32 | %RECIPE_CACHE_DIR%/%NAME% 33 | 34 | Processor 35 | PkgRootCreator 36 | 37 | 38 | Arguments 39 | 40 | archive_path 41 | %PKG% 42 | destination_path 43 | %pkgroot% 44 | purge_destination 45 | 46 | 47 | Processor 48 | Unarchiver 49 | 50 | 51 | Arguments 52 | 53 | input_path 54 | %pkgroot%/SQLDeveloper.app 55 | requirement 56 | identifier "com.oracle.SQLDeveloper" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VB5E2TV963 57 | 58 | Processor 59 | CodeSignatureVerifier 60 | 61 | 62 | Arguments 63 | 64 | app_path 65 | %pkgroot%/SQLDeveloper.app 66 | 67 | Processor 68 | SQLDeveloperVersioner 69 | 70 | 71 | Arguments 72 | 73 | dmg_path 74 | %RECIPE_CACHE_DIR%/%NAME%-%version%.dmg 75 | dmg_root 76 | %pkgroot% 77 | 78 | Processor 79 | DmgCreator 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /munkitools/munkitools4.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Note: munkitools does not include a code signature. If your 9 | organization requires code signature, it is recommend to internally sign 10 | the application. 11 | 12 | Downloads and imports version 4 of the Munki tools via 13 | the official releases listing on GitHub. You can set INCLUDE_PRERELEASES 14 | to any value to have this recipe pull prerelease versions. 15 | 16 | Note that Munki 4 includes two additional component pkgs, munkitools_python 17 | and munkitools_no_python. 18 | This recipe imports this to the Munki with the appropriate 'requires' key, 19 | however as it is considered an optional component, this recipe does not 20 | add it as an update_for any Munki component. Admins should add 21 | munkitools_app_usage to a manifest manually if its installation on clients 22 | is desired. 23 | 24 | This recipe cannot be overridden to pull a download from an 25 | alternate location such as munkibuilds.org - it will only download the 26 | official releases. For this, use the munkitools2-autobuild.munki 27 | recipe with a manually-provided DOWNLOAD_URL variable. 28 | 29 | The GitHubReleasesInfoProvider processor used by this recipe also 30 | respects an input variable: 'sort_by_highest_tag_names', which 31 | if set, will ignore the post dates of the releases and instead sort 32 | descending by tag names according to LooseVersion semantics. 33 | 34 | MUNKI_ICON should be overridden with your icon name. 35 | 36 | Identifier 37 | com.facebook.autopkg.download.munkitools4 38 | Input 39 | 40 | INCLUDE_PRERELEASES 41 | 42 | NAME 43 | munkitools4 44 | 45 | MinimumVersion 46 | 0.5.0 47 | Process 48 | 49 | 50 | Arguments 51 | 52 | asset_regex 53 | ^munkitools-4.*?pkg$ 54 | github_repo 55 | munki/munki 56 | include_prereleases 57 | %INCLUDE_PRERELEASES% 58 | 59 | Processor 60 | GitHubReleasesInfoProvider 61 | 62 | 63 | Processor 64 | URLDownloader 65 | 66 | 67 | Processor 68 | EndOfCheckPhase 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Duo/ConfigHeaderVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for ConfigHeaderVersioner class.""" 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | from __future__ import absolute_import, print_function 25 | 26 | from autopkglib import Processor, ProcessorError 27 | 28 | __all__ = ["ConfigHeaderVersioner"] 29 | 30 | 31 | class ConfigHeaderVersioner(Processor): 32 | # pylint: disable=missing-docstring 33 | description = "Looks for a version key in a config.h header file." 34 | input_variables = { 35 | "header_file": { 36 | "required": True, 37 | "description": "Path to the config.h file in a Makefile directory.", 38 | }, 39 | "version_key": { 40 | "required": False, 41 | "description": ( 42 | "Key to look for for versioning. Defaults to PACKAGE_VERSION." 43 | ), 44 | "default": "PACKAGE_VERSION", 45 | }, 46 | } 47 | output_variables = {"version": {"description": "Value of version key."}} 48 | 49 | __doc__ = description 50 | 51 | def main(self): 52 | print("Version key: %s" % self.env["version_key"]) 53 | try: 54 | with open(self.env["header_file"], "rb") as f: 55 | for line in f: 56 | if self.env["version_key"] in line: 57 | version_line = line 58 | break 59 | # If we get here, we didn't find the version key 60 | else: 61 | raise ProcessorError("Version key not found in file!") 62 | except IOError as err: 63 | raise ProcessorError(err) 64 | self.output("Version line found: %s" % version_line) 65 | # The line is typically: #define PACKAGE_VERSION 66 | self.env["version"] = version_line.split(" ")[2].rstrip().strip('"') 67 | self.output("Version found: %s" % self.env["version"]) 68 | 69 | 70 | if __name__ == "__main__": 71 | PROCESSOR = ConfigHeaderVersioner() 72 | PROCESSOR.execute_shell() 73 | -------------------------------------------------------------------------------- /Chef_Processors/ChefAttributeHash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree. 8 | # 9 | """See docstring for ChefAttributeHash class.""" 10 | 11 | from __future__ import absolute_import 12 | 13 | from autopkglib import Processor 14 | 15 | __all__ = ["ChefAttributeHash"] 16 | 17 | 18 | class ChefAttributeHash(Processor): 19 | description = ( 20 | "Produces a Chef attribute variable for a hash of items. " 21 | "The attribute prefixes correspond to node settings - i.e. " 22 | "default[category][prefix][attribute]." 23 | ) 24 | input_variables = { 25 | "attribute_category": { 26 | "required": True, 27 | "description": "Leading category for each attribute.", 28 | }, 29 | "attribute_prefix": { 30 | "required": True, 31 | "description": "Prefix to each attribute.", 32 | }, 33 | "attribute": {"required": True, "description": "Name of attribute."}, 34 | "value": {"required": True, "description": ("Dictionary of keys and values.")}, 35 | "in_array": { 36 | "required": False, 37 | "description": ( 38 | "Is this hash inside an array? If yes, a comma is added to the end" 39 | ), 40 | }, 41 | } 42 | output_variables = { 43 | "chef_block": {"description": "Chef attribute block."}, 44 | "attribute_variable": {"description": "Full name of variable."}, 45 | } 46 | 47 | __doc__ = description 48 | 49 | def main(self): 50 | att_prefix = "default['%s']['%s']['%s']" % ( 51 | self.env["attribute_category"], 52 | self.env["attribute_prefix"], 53 | self.env["attribute"], 54 | ) 55 | self.env["chef_block"] = att_prefix + " = {\n" 56 | for value in sorted(self.env["value"].keys()): 57 | self.env["chef_block"] += "\t%s => %s,\n" % ( 58 | value, 59 | self.env["value"][value], 60 | ) 61 | self.env["chef_block"] += "}" 62 | # Remove the trailing comma on the last item 63 | self.env["chef_block"] = self.env["chef_block"].replace(",\n}", "\n}") 64 | if self.env.get("in_array"): 65 | # if this hash is in a list of hashes, add a comma at the end 66 | self.env["chef_block"] += "," 67 | self.env["chef_block"] += "\n" 68 | self.output("Chef block: %s" % self.env["chef_block"]) 69 | self.env["attribute_variable"] = att_prefix.replace("default", "node") 70 | 71 | 72 | if __name__ == "__main__": 73 | PROCESSOR = ChefAttributeHash() 74 | PROCESSOR.execute_shell() 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Facebook's AutoPkg Recipes 2 | We want to make contributing to this project as easy and transparent as 3 | possible. 4 | 5 | ## Our Development Process 6 | Changes to AutoPkg recipes must be tested extensively and follow [AutoPkg recipe best practices](https://github.com/autopkg/autopkg/wiki/Recipe-Writing-Guidelines) as best as possible. 7 | 8 | These recipes are authored to support Facebook's needs first and foremost, and are then made available to the community in the hopes that others may benefit. 9 | 10 | Changes may occur in these recipes as Facebook encounters new solutions or revised methods for obtaining and installing the software. 11 | 12 | ## Pull Requests 13 | We actively welcome your pull requests. 14 | 15 | 1. Fork the repo and create your branch from `master`. 16 | 2. If you've added code that should be tested, please extensively test it and demonstrate with run logs that it works. 17 | 3. If any input or output variables change, please update the documentation. 18 | 4. Obviously, your recipe changes should work. 19 | 5. Make sure your code passes lint tests. 20 | 6. If you haven't already, complete the Contributor License Agreement ("CLA"). 21 | 22 | ## Contributor License Agreement ("CLA") 23 | In order to accept your pull request, we need you to submit a CLA. You only need 24 | to do this once to work on any of Facebook's open source projects. 25 | 26 | Complete your CLA here: 27 | 28 | ## Issues 29 | We use GitHub issues to track public bugs. Please ensure your description is 30 | clear and has sufficient instructions to be able to reproduce the issue. 31 | 32 | Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe 33 | disclosure of security bugs. In those cases, please go through the process 34 | outlined on that page and do not file a public issue. 35 | 36 | ## Coding Style 37 | * 4 spaces for indentation rather than tabs 38 | * 80 character line length 39 | * All custom processors (Python code) must pass flake8 and isort style linting. 40 | 41 | Sometimes custom processors are necessities to solve specific problems that can't be addressed by the built in provided processors. This repo contains several custom processors for that purpose. 42 | 43 | When possible, utilize existing built-in processors and shared processors. Custom Python processors should be purpose-built and limited in scope to the functionality necessary to solve the problem. 44 | 45 | ## License 46 | By contributing to Facebook's Recipes for AutoPkg, you agree that your contributions will be licensed 47 | under its BSD license. 48 | 49 | Please note that most of AutoPkg itself is licensed under the Apache license. For a good source on the differences between these licenses, please consult the free open book "[Understanding Open Source and Free Software Licensing](http://www.oreilly.com/openbook/osfreesoft/)" (O'Reilly, 2004). 50 | -------------------------------------------------------------------------------- /android_sdk/AndroidSDKVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for AndroidSDKVersioner class.""" 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | from __future__ import absolute_import 25 | 26 | import urllib2 27 | import xml.etree.cElementTree as ET 28 | 29 | from autopkglib import Processor, ProcessorError 30 | 31 | __all__ = ["AndroidSDKVersioner"] 32 | 33 | 34 | class AndroidSDKVersioner(Processor): 35 | # pylint: disable=missing-docstring 36 | description = "Parse the XML file for the latest version of the SDK tools." 37 | input_variables = { 38 | "xml_file": {"required": True, "description": "Path or URL to XML file."} 39 | } 40 | output_variables = { 41 | "version": {"description": "Combined version of the SDK tools."} 42 | } 43 | 44 | __doc__ = description 45 | 46 | def main(self): 47 | if "http" in self.env["xml_file"]: 48 | try: 49 | tree = ET.ElementTree(file=urllib2.urlopen(self.env["xml_file"])) 50 | except urllib2.URLError as err: 51 | raise ProcessorError(err) 52 | else: 53 | try: 54 | tree = ET.ElementTree(file=self.env["xml_file"]) 55 | except IOError as err: 56 | raise ProcessorError(err) 57 | root = tree.getroot() 58 | schema = root.tag.split("}")[0] + "}" 59 | match = root.findall("%s%s" % (schema, "tool")) 60 | revision = "%srevision" % schema 61 | result = "" 62 | try: 63 | major = match[-1].find(revision).find("%smajor" % schema).text 64 | minor = match[-1].find(revision).find("%sminor" % schema).text 65 | micro = match[-1].find(revision).find("%smicro" % schema).text 66 | except IndexError: 67 | raise ProcessorError("Version not found!") 68 | result = "%s.%s.%s" % (major, minor, micro) 69 | self.env["version"] = result 70 | self.output("Version: %s" % self.env["version"]) 71 | 72 | 73 | if __name__ == "__main__": 74 | PROCESSOR = AndroidSDKVersioner() 75 | PROCESSOR.execute_shell() 76 | -------------------------------------------------------------------------------- /Intellij/IntellijURLProvider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Intellij URL Provider.""" 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import xml.etree.cElementTree as ET 18 | 19 | from autopkglib.URLGetter import URLGetter 20 | 21 | 22 | __all__ = ["IntellijURLProvider"] 23 | 24 | intellij_version_url = "https://www.jetbrains.com/updates/updates.xml" 25 | 26 | 27 | class IntellijURLProvider(URLGetter): 28 | """Provide URL for latest Intellij IDEA build.""" 29 | 30 | description = "Provides URL and version for the latest release of Intellij." 31 | input_variables = { 32 | "base_url": { 33 | "required": False, 34 | "description": ( 35 | "Default is " "https://www.jetbrains.com/updates/updates.xml" 36 | ), 37 | }, 38 | "edition": { 39 | "required": False, 40 | "description": ( 41 | 'Either "C" for "Community" or "U" for "Ultimate" ' 42 | 'edition. Defaults to "C".' 43 | ), 44 | }, 45 | } 46 | output_variables = {"url": {"description": "URL to the latest release of Intellij"}} 47 | 48 | __doc__ = description 49 | 50 | def get_intellij_version(self, intellij_version_url): 51 | """Retrieve version number from XML.""" 52 | # Read XML 53 | raw_xml = self.download(intellij_version_url, text=True) 54 | # Select the latest released build 55 | root = ET.fromstring(raw_xml) 56 | product = root.find('product[@name="IntelliJ IDEA"]') 57 | channel = product.find('channel[@status="release"]') 58 | builds = channel.findall("build") 59 | version = builds[0].attrib["version"] 60 | # Return pkg url. 61 | return str(version) 62 | 63 | def main(self): 64 | """Main function.""" 65 | # Determine values. 66 | version_url = self.env.get("version_url", intellij_version_url) 67 | version = self.get_intellij_version(version_url) 68 | download_url = "https://download.jetbrains.com/idea/" "ideaI%s-%s.dmg" % ( 69 | self.env.get("edition", "C"), 70 | version, 71 | ) 72 | 73 | self.env["url"] = download_url 74 | self.output("URL: %s" % self.env["url"]) 75 | 76 | 77 | if __name__ == "__main__": 78 | processor = IntellijURLProvider() 79 | processor.execute_shell() 80 | -------------------------------------------------------------------------------- /Xcode/XcodeVersionEmitter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """Get all Version information from Xcode.""" 18 | 19 | import os.path 20 | 21 | from autopkglib import Processor 22 | 23 | 24 | try: 25 | # python 2 26 | from urlparse import urlsplit 27 | except ImportError: 28 | from urllib.parse import urlsplit 29 | 30 | 31 | __all__ = ["XcodeVersionEmitter"] 32 | 33 | 34 | class XcodeVersionEmitter(Processor): 35 | """Output a version number based on the URL. Skipped by default.""" 36 | 37 | description = __doc__ 38 | input_variables = { 39 | "dont_skip": { 40 | "required": False, 41 | "default": False, 42 | "description": ("If this evaluates as truthy, do not skip this step."), 43 | }, 44 | "url": {"required": True, "description": ("URL to parse the version from.")}, 45 | "output_filepath": { 46 | "required": True, 47 | "description": ("Path to which xcode version tag is emitted."), 48 | }, 49 | } 50 | output_variables = { 51 | "derived_filename": {"description": "The derived filename to emit."} 52 | } 53 | 54 | __doc__ = description 55 | 56 | def main(self): 57 | """Main.""" 58 | if not self.env["dont_skip"]: 59 | self.output("dont_skip is false, so skipping this Processor.") 60 | return 61 | url = self.env["url"] 62 | url_split_object = urlsplit(url) 63 | # "https://download.developer.apple.com/Developer_Tools/Xcode_10.2.1/Xcode_10.2.1.xip" # noqa 64 | # "https://developer.apple.com//services-account/download?path=/Developer_Tools/Xcode_11_Beta_2/Xcode_11_Beta_2.xip" # noqa 65 | filename = os.path.splitext(os.path.basename(url_split_object.path))[0].lower() 66 | self.output("Derived filename: {}".format(filename)) 67 | self.env["derived_filename"] = filename 68 | 69 | destination = os.path.expandvars(self.env["output_filepath"]) 70 | with open(destination, "w") as f: 71 | f.write(filename) 72 | self.output( 73 | "Derived filename ({}) written to disk at {}".format( 74 | filename, destination 75 | ) 76 | ) 77 | 78 | 79 | if __name__ == "__main__": 80 | PROCESSOR = XcodeVersionEmitter() 81 | PROCESSOR.execute_shell() 82 | -------------------------------------------------------------------------------- /munkitools/munkitools3.download.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Note: munkitools does not include a code signature. If your 9 | organization requires code signature, it is recommend to internally sign 10 | the application. 11 | 12 | Downloads and imports version 3 of the Munki tools via 13 | the official releases listing on GitHub. You can set INCLUDE_PRERELEASES 14 | to any value to have this recipe pull prerelease versions. 15 | 16 | Note that Munki 3 includes an additional component pkg, munkitools_app_usage. 17 | This recipe imports this to the Munki with the appropriate 'requires' key, 18 | however as it is considered an optional component, this recipe does not 19 | add it as an update_for any Munki component. Admins should add 20 | munkitools_app_usage to a manifest manually if its installation on clients 21 | is desired. 22 | 23 | This recipe cannot be overridden to pull a download from an 24 | alternate location such as munkibuilds.org - it will only download the 25 | official releases. For this, use the munkitools2-autobuild.munki 26 | recipe with a manually-provided DOWNLOAD_URL variable. 27 | 28 | The GitHubReleasesInfoProvider processor used by this recipe also 29 | respects an input variable: 'sort_by_highest_tag_names', which 30 | if set, will ignore the post dates of the releases and instead sort 31 | descending by tag names according to LooseVersion semantics. 32 | 33 | MUNKI_ICON should be overridden with your icon name. 34 | 35 | Identifier 36 | com.facebook.autopkg.download.munkitools3 37 | Input 38 | 39 | INCLUDE_PRERELEASES 40 | 41 | NAME 42 | munkitools3 43 | 44 | MinimumVersion 45 | 0.5.0 46 | Process 47 | 48 | 49 | Processor 50 | DeprecationWarning 51 | Arguments 52 | 53 | warning_message 54 | This recipe will soon be removed. Please remove it from your list of recipes. 55 | 56 | 57 | 58 | Arguments 59 | 60 | asset_regex 61 | ^munkitools-3.*?pkg$ 62 | github_repo 63 | munki/munki 64 | include_prereleases 65 | %INCLUDE_PRERELEASES% 66 | 67 | Processor 68 | GitHubReleasesInfoProvider 69 | 70 | 71 | Processor 72 | URLDownloader 73 | 74 | 75 | Processor 76 | EndOfCheckPhase 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /android_sdk/PropertiesWriter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | """See docstring for PropertiesWriter class.""" 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | from __future__ import absolute_import 25 | 26 | import ConfigParser 27 | from collections import OrderedDict 28 | 29 | from autopkglib import Processor, ProcessorError 30 | 31 | __all__ = ["PropertiesWriter"] 32 | 33 | 34 | # this code stolen from http://stackoverflow.com/a/25084055 35 | class EqualsSpaceRemover: 36 | output_file = None 37 | 38 | def __init__(self, new_output_file): 39 | self.output_file = new_output_file 40 | 41 | def write(self, what): 42 | self.output_file.write(what.replace(" = ", "=")) 43 | 44 | 45 | class PropertiesWriter(Processor): 46 | # pylint: disable=missing-docstring 47 | description = "Read the version.properties file inside the SQLDeveloper.app." 48 | input_variables = { 49 | "file_path": { 50 | "required": True, 51 | "description": "Path to source.properties file to create.", 52 | }, 53 | "properties": { 54 | "required": True, 55 | "description": "Dictionary of keys/values to write to file.", 56 | }, 57 | } 58 | output_variables = {} 59 | 60 | __doc__ = description 61 | 62 | def main(self): 63 | cp = ConfigParser.SafeConfigParser() 64 | cp.optionxform = str 65 | 66 | sort = sorted(self.env["properties"].items(), key=lambda t: t[0]) 67 | properties = OrderedDict(sort) 68 | 69 | for key, value in properties.iteritems(): 70 | cp.set("", str(key), value) 71 | # Write the file out 72 | with open(self.env["file_path"], "wb") as f: 73 | try: 74 | cp.write(EqualsSpaceRemover(f)) 75 | except IOError as err: 76 | raise ProcessorError(err) 77 | # Now delete the first line, the section header 78 | with open(self.env["file_path"], "rb") as old: 79 | lines = old.readlines() 80 | lines[0] = "# Generated by AutoPkg\n" 81 | with open(self.env["file_path"], "wb") as new: 82 | for line in lines: 83 | new.write(line) 84 | 85 | 86 | if __name__ == "__main__": 87 | PROCESSOR = PropertiesWriter() 88 | PROCESSOR.execute_shell() 89 | -------------------------------------------------------------------------------- /SQLDeveloper/SQLDeveloperVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for SQLDeveloperVersioner class.""" 19 | 20 | from __future__ import absolute_import 21 | 22 | import ConfigParser 23 | import os.path 24 | 25 | from autopkglib import Processor, ProcessorError 26 | 27 | __all__ = ["SQLDeveloperVersioner"] 28 | 29 | 30 | # this code stolen directly from 31 | # http://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788 32 | class FakeSecHead(object): 33 | def __init__(self, fp): 34 | self.fp = fp 35 | self.sechead = "[properties]\n" 36 | 37 | def readline(self): 38 | if self.sechead: 39 | try: 40 | return self.sechead 41 | finally: 42 | self.sechead = None 43 | else: 44 | return self.fp.readline() 45 | 46 | 47 | class SQLDeveloperVersioner(Processor): 48 | # pylint: disable=missing-docstring 49 | description = "Read the version.properties file inside the SQLDeveloper.app." 50 | input_variables = { 51 | "app_path": { 52 | "required": True, 53 | "description": "Path to app to find the version.properties file in.", 54 | } 55 | } 56 | output_variables = {"version": {"description": "Actual version of app."}} 57 | 58 | __doc__ = description 59 | 60 | def main(self): 61 | # Unsurprisingly, SQLDeveloper fails to include a useful version in 62 | # the app's Info.plist. Instead, the actual version is buried deep 63 | # inside in a file called "version.properties". Thanks, Oracle. 64 | # You know, I was a having a pretty good day up until now... 65 | relative_path = ( 66 | "Contents/Resources/sqldeveloper/sqldeveloper/bin/version.properties" 67 | ) 68 | file_path = os.path.join(self.env["app_path"], relative_path) 69 | # this code stolen directly from 70 | # http://stackoverflow.com/questions/2819696/parsing-properties-file-in-python/2819788#2819788 71 | cp = ConfigParser.SafeConfigParser() 72 | try: 73 | cp.readfp(FakeSecHead(open(file_path))) 74 | except IOError as err: 75 | raise ProcessorError(err) 76 | self.env["version"] = cp.get("properties", "ver_full") 77 | self.output("Version: %s" % self.env["version"]) 78 | 79 | 80 | if __name__ == "__main__": 81 | PROCESSOR = SQLDeveloperVersioner() 82 | PROCESSOR.execute_shell() 83 | -------------------------------------------------------------------------------- /Shared_Processors/DirectoryList.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for DirectoryList class.""" 9 | 10 | 11 | from __future__ import absolute_import 12 | 13 | import os 14 | from glob import glob 15 | 16 | from autopkglib import Processor, ProcessorError 17 | 18 | __all__ = ["DirectoryList"] 19 | 20 | 21 | class DirectoryList(Processor): 22 | """Returns a list of items in a subdirectory as a string, separated by 23 | commas. 24 | 25 | Does not recurse into subdirectories. 26 | """ 27 | 28 | input_variables = { 29 | "pattern": { 30 | "description": "Shell glob pattern to match files by", 31 | "required": True, 32 | }, 33 | "find_method": { 34 | "description": ( 35 | "Type of pattern to match. Currently only " 36 | 'supported type is "glob" (also the default)' 37 | ), 38 | "default": "glob", 39 | "required": False, 40 | }, 41 | "remove_extension": { 42 | "description": ("Remove the extension at the end. Default to False."), 43 | "default": False, 44 | "required": False, 45 | }, 46 | "suffix_string": { 47 | "description": ( 48 | "String to append to each found item name in dir. Defaults to ','" 49 | ), 50 | "default": ",", 51 | "required": False, 52 | }, 53 | } 54 | output_variables = {"found_filenames": {"description": "Found filename"}} 55 | 56 | description = __doc__ 57 | 58 | def globfind(self, pattern): 59 | """Returns multiple files matching a glob.""" 60 | # pylint: disable=no-self-use 61 | 62 | glob_matches = glob(pattern) 63 | 64 | if len(glob_matches) < 1: 65 | raise ProcessorError("No matching filename found") 66 | 67 | glob_matches.sort() 68 | 69 | # return glob_matches 70 | new_glob = [] 71 | for glob_item in glob_matches: 72 | new_string = os.path.basename(glob_item) 73 | if self.env["remove_extension"]: 74 | new_string = os.path.splitext(new_string)[0] 75 | new_glob.append(new_string) 76 | return new_glob 77 | 78 | def main(self): 79 | pattern = self.env.get("pattern") 80 | method = self.env.get("find_method") 81 | 82 | format_string = "%s" % self.env["suffix_string"] 83 | search_string = "{0}" 84 | if method == "glob": 85 | self.env["found_filenames"] = search_string.format( 86 | format_string.join(self.globfind(pattern)) 87 | ).strip() 88 | else: 89 | raise ProcessorError("Unsupported find_method: %s" % method) 90 | self.output("Found matches: %s" % self.env["found_filenames"]) 91 | 92 | 93 | if __name__ == "__main__": 94 | PROCESSOR = DirectoryList() 95 | PROCESSOR.execute_shell() 96 | -------------------------------------------------------------------------------- /Chef_Processors/ChefArray.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree. 8 | # 9 | """See docstring for ChefArray class.""" 10 | 11 | from __future__ import absolute_import 12 | 13 | from autopkglib import Processor 14 | 15 | __all__ = ["ChefArray"] 16 | 17 | 18 | class ChefArray(Processor): 19 | description = ( 20 | "Produces an array that can be used with other " 21 | " Chef blocks. See " 22 | "https://docs.chef.io/ruby.html#arrays." 23 | ) 24 | input_variables = { 25 | "item_list": { 26 | "description": ( 27 | "Array of items to be put into the array block. This " 28 | "can also be a single string." 29 | ), 30 | "required": True, 31 | }, 32 | "no_wrap_quotes": { 33 | "description": "Do not add wrapping quotation marks.", 34 | "required": False, 35 | }, 36 | "remove_version": { 37 | "description": ("Removes the version string from the variable."), 38 | "required": False, 39 | }, 40 | } 41 | output_variables = {"array_block": {"description": "Chef array block."}} 42 | 43 | __doc__ = description 44 | 45 | def main(self): 46 | beginning_bracket = "[\n" 47 | iterator = "item" 48 | end_bracket = "]" 49 | each_text = ".each do |%s|\n" % iterator 50 | quotes = "'" 51 | itemlist = list() 52 | 53 | # Are we going to use wrapping quotes? 54 | if self.env.get("no_wrap_quotes"): 55 | quotes = "" 56 | 57 | # Check to see if one item was passed as a single string 58 | if isinstance(self.env["item_list"], basestring): 59 | if self.env["remove_version"]: 60 | # Remove the ['version'] text from the string 61 | version_string = "['%s']" % self.env["remove_version"] 62 | if version_string in self.env["item_list"]: 63 | self.env["item_list"] = self.env["item_list"].replace( 64 | version_string, "" 65 | ) 66 | self.env["array_block"] = self.env["item_list"] + each_text 67 | else: 68 | itemlist = self.env["item_list"] 69 | # Begin the block 70 | self.env["array_block"] = beginning_bracket 71 | # Loop through the array of items 72 | for item in itemlist: 73 | self.output("Item: %s" % item) 74 | self.env["array_block"] += " %s%s%s,\n" % (quotes, str(item), quotes) 75 | # End the block 76 | self.env["array_block"] += end_bracket 77 | # Remove the trailing comma on the last item 78 | self.env["array_block"] = self.env["array_block"].replace(",\n]", "\n]") 79 | self.env["array_block"] += each_text 80 | self.output("Chef block: \n%s" % self.env["array_block"]) 81 | 82 | 83 | if __name__ == "__main__": 84 | PROCESSOR = ChefArray() 85 | PROCESSOR.execute_shell() 86 | -------------------------------------------------------------------------------- /Duo/ConfigureMakeInstaller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for ConfigureMakeInstaller class.""" 19 | 20 | from __future__ import absolute_import 21 | 22 | import os 23 | import subprocess 24 | 25 | from autopkglib import Processor, ProcessorError 26 | 27 | __all__ = ["ConfigureMakeInstaller"] 28 | 29 | 30 | class ConfigureMakeInstaller(Processor): 31 | # pylint: disable=missing-docstring 32 | description = "Runs Configure, Make, Make Install on target directory." 33 | input_variables = { 34 | "installer_dir_path": { 35 | "required": True, 36 | "description": "Path to directory containing Configure file.", 37 | }, 38 | "prefix_path": { 39 | "required": False, 40 | "description": "Path to apply to --prefix argument.", 41 | }, 42 | "output_path": { 43 | "required": False, 44 | "description": ( 45 | "Path to output location. If not specified, " 46 | "'make install' may install things outside " 47 | "the cache directory. Be warned!" 48 | ), 49 | }, 50 | } 51 | output_variables = {} 52 | 53 | __doc__ = description 54 | 55 | def main(self): 56 | conf_path = self.env["installer_dir_path"] 57 | makefile = os.path.join(conf_path, "Makefile") 58 | os.chdir(conf_path) 59 | cmd = ["./configure"] 60 | if self.env["prefix_path"]: 61 | cmd.append("--prefix=" + self.env["prefix_path"]) 62 | 63 | # ./configure 64 | self.output("Command: %s" % cmd) 65 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 66 | (conf_out, conf_err) = proc.communicate() 67 | if conf_err: 68 | raise ProcessorError("./configure error: %s" % conf_err) 69 | self.output(conf_out) 70 | 71 | # make 72 | self.output("Running make") 73 | cmd = ["/usr/bin/make", "-f", makefile] 74 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 75 | (m_out, m_err) = proc.communicate() 76 | # if m_err: 77 | # raise ProcessorError("make error: %s" % m_err) 78 | self.output(m_out) 79 | 80 | # make install 81 | self.output("Running make install") 82 | destpath = self.env.get("output_path") 83 | cmd = ["/usr/bin/make", "install", "-f", makefile] 84 | if destpath: 85 | cmd.append("DESTDIR=" + destpath) 86 | self.output("install cmd: %s" % cmd) 87 | proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 88 | (mi_out, mi_err) = proc.communicate() 89 | # if mi_err: 90 | # raise ProcessorError("make install error: %s" % mi_err) 91 | self.output(mi_out) 92 | 93 | 94 | if __name__ == "__main__": 95 | PROCESSOR = ConfigureMakeInstaller() 96 | PROCESSOR.execute_shell() 97 | -------------------------------------------------------------------------------- /SQLDeveloper/SQLDeveloper.munki.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Creates a DMG for SQLDeveloper and imports into Munki. You must provide your own .zip download using the -p argument. 9 | Identifier 10 | com.facebook.autopkg.munki.sqldeveloper 11 | Input 12 | 13 | JDK_NAME 14 | OracleJava8JDK 15 | MUNKI_REPO_SUBDIR 16 | apps/Oracle 17 | NAME 18 | SQLDeveloper 19 | pkginfo 20 | 21 | catalogs 22 | 23 | testing 24 | 25 | category 26 | Developer Tools 27 | description 28 | SQL Developer is a free integrated development environment that simplifies the development and management of Oracle Database. 29 | developer 30 | Oracle 31 | display_name 32 | SQL Developer 33 | name 34 | %NAME% 35 | 36 | 37 | MinimumVersion 38 | 0.5.1 39 | ParentRecipe 40 | com.facebook.autopkg.dmg.sqldeveloper 41 | Process 42 | 43 | 44 | Arguments 45 | 46 | faux_root 47 | %pkgroot 48 | installs_item_paths 49 | 50 | SQLDeveloper.app/Contents/Resources/sqldeveloper/sqldeveloper/bin/version.properties 51 | 52 | 53 | Processor 54 | MunkiInstallsItemsCreator 55 | 56 | 57 | Arguments 58 | 59 | additional_pkginfo 60 | 61 | installs 62 | 63 | 64 | md5checksum 65 | 2e7650fee02f3ac91838397daf5f8817 66 | path 67 | /Applications/SQLDeveloper.app/Contents/Resources/sqldeveloper/sqldeveloper/bin/version.properties 68 | type 69 | file 70 | 71 | 72 | requires 73 | 74 | %JDK_NAME% 75 | 76 | version 77 | %version% 78 | 79 | 80 | Processor 81 | MunkiPkginfoMerger 82 | 83 | 84 | Arguments 85 | 86 | pkg_path 87 | %RECIPE_CACHE_DIR%/%NAME%-%version%.dmg 88 | repo_subdirectory 89 | %MUNKI_REPO_SUBDIR% 90 | 91 | Processor 92 | MunkiImporter 93 | 94 | 95 | Arguments 96 | 97 | path_list 98 | 99 | %RECIPE_CACHE_DIR%/%NAME%-%version%.dmg 100 | 101 | 102 | Processor 103 | PathDeleter 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Shared_Processors/SubDirectoryList.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for SubDirectoryList class.""" 9 | 10 | 11 | from __future__ import absolute_import 12 | 13 | import os 14 | 15 | from autopkglib import Processor, ProcessorError 16 | 17 | __all__ = ["SubDirectoryList"] 18 | 19 | 20 | class SubDirectoryList(Processor): 21 | """Finds a filename for use in other Processors. 22 | 23 | Currently only supports glob filename patterns. 24 | """ 25 | 26 | input_variables = { 27 | "root_path": { 28 | "description": "Path to start looking for files.", 29 | "required": True, 30 | }, 31 | "suffix_string": { 32 | "description": ( 33 | "String to append to each found item name in dir. Defaults to ','" 34 | ), 35 | "default": ",", 36 | "required": False, 37 | }, 38 | } 39 | output_variables = { 40 | "found_filenames": { 41 | "description": ( 42 | "String containing a list of all files found " 43 | "relative to root_path, separated by " 44 | "suffix_string." 45 | ) 46 | }, 47 | "found_directories": { 48 | "description": ( 49 | "String containg a list of all directories " 50 | "found relative to root_path, separated by " 51 | "suffix_string." 52 | ) 53 | }, 54 | "relative_root": {"description": ("Relative root path")}, 55 | } 56 | 57 | description = __doc__ 58 | 59 | def main(self): 60 | sip_dirs = ["usr", "usr/local", "private", "private/etc", "Library"] 61 | format_string = "%s" % self.env["suffix_string"] 62 | # search_string = ' \'{0}\'' 63 | search_string = "{0}" 64 | dir_list = list() 65 | file_list = list() 66 | if not os.path.isdir(self.env["root_path"]): 67 | raise ProcessorError("Can't find root path!") 68 | for dirName, subdirList, fileList in os.walk(self.env["root_path"]): 69 | relative_path = os.path.relpath(dirName, self.env["root_path"]) 70 | # We need to remove the SIP folders so Chef doesn't try to create them 71 | if not relative_path == "." and not (relative_path in sip_dirs): 72 | dir_list.append(relative_path) 73 | # search_string.format(format_string.join(dirName)).strip() 74 | for fname in fileList: 75 | if ".DS_Store" in fname: 76 | continue 77 | # print('\t%s' % fname) 78 | relpath = os.path.relpath( 79 | os.path.join(fname, dirName), self.env["root_path"] 80 | ) 81 | self.output("Relative path: %s" % relpath) 82 | if relpath == ".": 83 | # we want to avoid prepending './' to files at root dir 84 | relpath = "" 85 | # print "Real relative path: %s" % relpath 86 | file_list.append(os.path.join(relpath, fname)) 87 | self.env["found_directories"] = search_string.format( 88 | format_string.join(dir_list) 89 | ).strip() 90 | self.env["found_filenames"] = search_string.format( 91 | format_string.join(file_list) 92 | ).strip() 93 | 94 | 95 | if __name__ == "__main__": 96 | PROCESSOR = SubDirectoryList() 97 | PROCESSOR.execute_shell() 98 | -------------------------------------------------------------------------------- /Xcode/AppleDataGatherer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """See docstring for AppleDataGatherer class""" 18 | 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | import os 25 | 26 | from autopkglib import Processor, ProcessorError 27 | 28 | 29 | try: 30 | # python 2 31 | from urllib import quote 32 | except ImportError: 33 | from urllib.parse import quote 34 | 35 | 36 | __all__ = ["AppleDataGatherer"] 37 | 38 | 39 | class AppleDataGatherer(Processor): 40 | """Gather Xcode-specific curl data payloads into a file on disk.""" 41 | 42 | description = __doc__ 43 | input_variables = { 44 | "apple_id": { 45 | "required": True, 46 | "description": ("AppleID that can log into the Apple dev portal."), 47 | }, 48 | "password": { 49 | "required": False, 50 | "description": ("Password for AppleID that can log into Apple dev portal."), 51 | }, 52 | "password_file": { 53 | "required": False, 54 | "description": ( 55 | "A path to a file to read the password from. Using this will " 56 | "ignore the 'password' argument." 57 | ), 58 | }, 59 | "appID_key": {"required": True, "description": ("App ID key to log into.")}, 60 | } 61 | output_variables = {"data_pathname": {"description": "Path to the data file."}} 62 | 63 | __doc__ = description 64 | 65 | def main(self): 66 | """Store the login data file.""" 67 | appleIDstring = "appleId={}&".format(quote(self.env["apple_id"])) 68 | appIDKeystring = "appIdKey={}&".format(self.env["appID_key"]) 69 | if not self.env.get("password") and not self.env.get("password_file"): 70 | raise ProcessorError( 71 | "You must provide either a password, or a password_file argument." 72 | ) 73 | password = self.env.get("password") 74 | if self.env.get("password_file"): 75 | with open(self.env["password_file"]) as f: 76 | password = f.read() 77 | passwordstring = "accountPassword={}".format(password) 78 | 79 | login_data = appleIDstring + appIDKeystring + passwordstring 80 | download_dir = os.path.join(self.env["RECIPE_CACHE_DIR"], "downloads") 81 | filename = "login_data" 82 | # create download_dir if needed 83 | if not os.path.exists(download_dir): 84 | try: 85 | os.makedirs(download_dir) 86 | except OSError as err: 87 | raise ProcessorError( 88 | "Can't create %s: %s" % (download_dir, err.strerror) 89 | ) 90 | self.output("Writing data to file") 91 | self.env["data_pathname"] = os.path.join(download_dir, filename) 92 | with open(self.env["data_pathname"], "w") as f: 93 | f.write(login_data) 94 | 95 | 96 | if __name__ == "__main__": 97 | PROCESSOR = AppleDataGatherer() 98 | PROCESSOR.execute_shell() 99 | -------------------------------------------------------------------------------- /Xcode/XcodeFileNamer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """Create a filename for Xcode based on version information.""" 18 | 19 | from autopkglib import Processor 20 | 21 | 22 | __all__ = ["XcodeFileNamer"] 23 | 24 | 25 | class XcodeFileNamer(Processor): 26 | """Create a filename for Xcode based on version information.""" 27 | 28 | description = __doc__ 29 | input_variables = { 30 | "should_produce_versioned_name": { 31 | "description": ( 32 | "Whether or not we should produce a versioned name. " 33 | "If this is non-empty, it's evaluated as true." 34 | ), 35 | "required": True, 36 | }, 37 | "major_version": { 38 | "description": "Major version of Xcode - i.e. Xcode 7, 8.", 39 | "required": True, 40 | }, 41 | "minor_version": { 42 | "description": "Minor version of Xcode - i.e. Xcode X.1, X.2.", 43 | "required": True, 44 | }, 45 | "patch_version": { 46 | "description": ( 47 | "Patch version of Xcode - i.e. Xcode X.Y.0, X.Y.1. " 48 | "Patch version will be normalized to 0 if missing (i.e. 8.3 " 49 | "becomes 8.3.0)." 50 | ), 51 | "required": True, 52 | }, 53 | "is_beta": { 54 | "description": ("Boolean that is true if this Xcode is a beta version."), 55 | "required": True, 56 | }, 57 | "beta_version": { 58 | "description": ( 59 | "The beta number - 1, 2, 3, etc. Only used if is_beta is True. " 60 | "Assumed to be 0 if not provided." 61 | ), 62 | "required": False, 63 | }, 64 | "should_lowercase": { 65 | "description": ( 66 | "If this value is non-empty, use a lower-case filename - xcode_X.Y.0_suffix.app." 67 | ), 68 | "required": False, 69 | }, 70 | "suffix": { 71 | "description": ( 72 | "Any additional suffix string to append to the name prior to the .app extension." 73 | ), 74 | "required": False, 75 | }, 76 | } 77 | output_variables = { 78 | "xcode_filename": {"description": "Allow producing a versioned Xcode name."} 79 | } 80 | 81 | __doc__ = description 82 | 83 | def main(self): 84 | """Main.""" 85 | if not self.env["should_produce_versioned_name"] and self.env["is_beta"]: 86 | # Default name for Xcode Beta 87 | self.env["xcode_filename"] = "Xcode-beta" 88 | return 89 | elif not self.env["should_produce_versioned_name"]: 90 | # Default name for Xcode 91 | self.env["xcode_filename"] = "Xcode" 92 | return 93 | # end up with xcode_10.2.0_beta_4 or xcode_10.2.1 94 | prefix = "Xcode" 95 | if self.env.get("should_lowercase"): 96 | prefix = "xcode" 97 | name = "{}_{}.{}.{}".format( 98 | prefix, 99 | self.env["major_version"], 100 | self.env["minor_version"], 101 | self.env["patch_version"], 102 | ) 103 | if self.env["is_beta"]: 104 | name = name + "_beta_{}".format(self.env.get("beta_version", "0")) 105 | name += self.env.get("suffix", "") 106 | self.output("Xcode name: {}".format(name)) 107 | self.env["xcode_filename"] = name 108 | 109 | 110 | if __name__ == "__main__": 111 | PROCESSOR = XcodeFileNamer() 112 | PROCESSOR.execute_shell() 113 | -------------------------------------------------------------------------------- /AdoptOpenJDK/AdoptOpenJDKURLProvider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | """See docstring for AdoptOpenJDKURLProvider class""" 17 | 18 | from __future__ import absolute_import, division, print_function, unicode_literals 19 | 20 | import json 21 | 22 | from autopkglib import ProcessorError 23 | from autopkglib.URLGetter import URLGetter 24 | 25 | 26 | try: 27 | from urllib.parse import urljoin 28 | except ImportError: 29 | from urlparse import urljoin 30 | 31 | 32 | __all__ = ["AdoptOpenJDKURLProvider"] 33 | 34 | URL = "https://api.adoptopenjdk.net/v2/info/releases/" 35 | 36 | 37 | class AdoptOpenJDKURLProvider(URLGetter): 38 | """Provides a version and dmg download for the AdoptOpenJDK.""" 39 | 40 | description = __doc__ 41 | input_variables = { 42 | "jdk_version": {"required": True, "description": "Version of JDK to fetch."}, 43 | "jdk_type": { 44 | "required": False, 45 | "description": "Fetch 'jdk', or 'jre'. Defaults to 'jdk'.", 46 | }, 47 | "jvm_type": { 48 | "required": False, 49 | "description": ( 50 | "Fetch a 'hotspot' or 'openj9' JVM target. Defaults to 'hotspot'." 51 | ), 52 | }, 53 | "binary_type": { 54 | "required": False, 55 | "description": "Fetch a 'pkg' or 'tgz' download. Defaults to 'pkg'.", 56 | }, 57 | "release": { 58 | "required": False, 59 | "description": "Fetch a specific release. Defaults to 'latest'.", 60 | }, 61 | } 62 | output_variables = { 63 | "version": {"description": "Version of the product."}, 64 | "url": {"description": "Download URL."}, 65 | "checksum": {"description": "Checksum of the targeted product."}, 66 | } 67 | 68 | def get_checksum(self, checksum_url, binary_type): 69 | """Get the expected checksum for the release.""" 70 | checksum_data = self.download(checksum_url, text=True) 71 | return checksum_data.split()[0] 72 | 73 | def main(self): 74 | """Find the download URL""" 75 | jvm_type = self.env.get("jvm_type", "hotspot") 76 | if jvm_type not in ["hotspot", "openj9"]: 77 | raise ProcessorError("jvm_type can only be 'hotspot' or 'openj9'") 78 | jdk_type = self.env.get("jdk_type", "jdk") 79 | if jdk_type not in ["jdk", "jre"]: 80 | raise ProcessorError("jdk_type can only be 'jdk' or 'jre'") 81 | binary_type = self.env.get("binary_type", "pkg") 82 | if binary_type not in ["pkg", "tgz"]: 83 | raise ProcessorError("jdk_type can only be 'pkg' or 'tgz'") 84 | release = self.env.get("release", "latest") 85 | queries = "?os=mac&openjdk_impl={}&type={}&release={}".format( 86 | jvm_type, jdk_type, release 87 | ) 88 | # Fetch the API data 89 | query_suffix = urljoin("openjdk{}".format(self.env["jdk_version"]), queries) 90 | api_url = urljoin(URL, query_suffix) 91 | self.output("Query URL: {}".format(api_url)) 92 | api_data = self.download(api_url, text=True) 93 | api_results = json.loads(api_data) 94 | # Determine what we're looking for - pkg or tgz 95 | if binary_type == "pkg": 96 | checksum_url = api_results["binaries"][0]["installer_checksum_link"] 97 | url = api_results["binaries"][0]["installer_link"] 98 | else: 99 | checksum_url = api_results["binaries"][0]["checksum_link"] 100 | url = api_results["binaries"][0]["binary_link"] 101 | # Use semantic versioning for the version string, although historically this 102 | # hasn't been anything particularly problematic 103 | version = api_results["binaries"][0]["version_data"]["semver"] 104 | self.env["version"] = version 105 | self.output("Version: {}".format(version)) 106 | # Get the checksum from the internet 107 | checksum = self.get_checksum(checksum_url, binary_type) 108 | self.env["checksum"] = checksum 109 | self.output("checksum: {}".format(checksum)) 110 | # Pick the URL 111 | self.env["url"] = url 112 | self.output("Found URL {}".format(self.env["url"])) 113 | 114 | 115 | if __name__ == "__main__": 116 | PROCESSOR = AdoptOpenJDKURLProvider() 117 | PROCESSOR.execute_shell() 118 | -------------------------------------------------------------------------------- /Shared_Processors/README.md: -------------------------------------------------------------------------------- 1 | # Shared Processors 2 | 3 | ## FileAppender 4 | 5 | This processor will simply append a string on to the end of a file. This is useful if an AutoPkg recipe needs to add more variables or other data into a file that already exists (as part of a download, or something created from a previous FileCreator processor). 6 | 7 | ### Example Usage: 8 | ``` 9 | 10 | Processor 11 | com.facebook.autopkg.shared/FileAppender 12 | Arguments 13 | 14 | file_path 15 | %pkgroot%/attributes/default.rb 16 | file_content 17 | this_will_be_added_to_the_end 18 | 19 | 20 | ``` 21 | 22 | ## PackageInfoVersioner 23 | 24 | This processor provides a way to get a version number from the PackageInfo file inside a distribution/bundle style package. This processor specifically looks for the "pkg-info" XML tag inside the PackageInfo file and uses that as the version. This is helpful for bundle packages that provide multiple components with unique / differing version numbers, and there's no single item you can reliably use for versioning. 25 | 26 | The simplest usage is to use something like FileFinder to locate the PackageInfo file inside the bundle package you've downloaded or unarchived and then call this processor. 27 | 28 | ### Example Usage: 29 | ``` 30 | 31 | Processor 32 | com.facebook.autopkg.shared/PackageInfoVersioner 33 | Arguments 34 | 35 | package_info_path 36 | %found_filename%/PackageInfo 37 | 38 | 39 | ``` 40 | 41 | ## Rsync 42 | 43 | This processor calls out to a locally installed rsync (defaults to `/usr/bin/rsync`) to rsync between a source and destination. You can specify a path to a specific rsync binary if needed. 44 | 45 | Arguments can be passed in, and the string provided to the "rsync_arguments" processor input variable will be passed directly into the subprocess call to rsync. See the rsync man page for acceptable arguments. *NOTE: The leading hyphens before your arguments are required!* 46 | 47 | Please note that we have so far only used this for local source -> destination copying, and have not tested a very wide a variety of rsync arguments - so there may be some things that get passed in that don't behave properly in this context. If you do find some arguments that cause problems, please let us know! 48 | 49 | ### Example Usage: 50 | ``` 51 | 52 | Processor 53 | com.facebook.autopkg.shared/Rsync 54 | Arguments 55 | 56 | source_path 57 | %RECIPE_CACHE_DIR%/unpack/folder 58 | destination_path 59 | %pkgroot%/merged_folder 60 | rsync_arguments 61 | -Phav 62 | 63 | 64 | ``` 65 | 66 | ## SHAChecksum 67 | 68 | This processors calls out to `/usr/bin/shasum` to calculate a checksum on a file. You can specify the SHA type (to be passed to the `-a` argument) as an input variable. 69 | 70 | ### Example Usage: 71 | This example will calculate the SHA-256 sum: 72 | 73 | ``` 74 | 75 | Processor 76 | com.facebook.autopkg.shared/SHAChecksum 77 | Comment 78 | Calculate SHA256 checksum 79 | Arguments 80 | 81 | source_file 82 | %RECIPE_CACHE_DIR%/%NAME%-%version%.pkg 83 | checksum_type 84 | 256 85 | 86 | 87 | ``` 88 | 89 | ## SubDirectoryList 90 | This is a more complex processor with more specific usage. For a given root path, this processor will walk through and create two lists: one for all files found relative to the root path, and one for all directories found relative to the root path. 91 | 92 | Both of these lists are stored as strings, with each item separated by the contents of the "suffix_string" input variable (which defaults to "," comma). 93 | 94 | This doesn't have too much use in most AutoPkg recipes, but is the foundational key for translating packages into other management suites that require the pre-creation of subdirectories before placing files on the disk. 95 | 96 | ### Example Usage: 97 | Here's a simple example for how to get the list of contents inside an unpacked package - such as the Munki app package. 98 | 99 | ``` 100 | 101 | Processor 102 | com.facebook.autopkg.shared/SubDirectoryList 103 | Comment 104 | MUNKI ADMIN - get list of folder contents 105 | Arguments 106 | 107 | root_path 108 | %pkgroot%/files/default/munki/admin/%version%/ 109 | 110 | 111 | ``` 112 | The resulting `%found_directories%` will contain a list of all folders that are inside this root path, and the `%found_files%` will contain a list of all files that were found. 113 | 114 | This could be useful for recipes that convert packages into Puppet or Chef recipes, which may require directories to be created on disk prior to files being placed there. 115 | -------------------------------------------------------------------------------- /android_sdk/AndroidXMLParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for AndroidXMLParser class.""" 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | from __future__ import absolute_import 25 | 26 | import urllib2 27 | import xml.etree.cElementTree as ET 28 | 29 | from autopkglib import Processor, ProcessorError 30 | 31 | __all__ = ["AndroidXMLParser"] 32 | 33 | 34 | class AndroidXMLParser(Processor): 35 | # pylint: disable=missing-docstring 36 | description = "Parse the provided XML file for a variable match." 37 | input_variables = { 38 | "xml_file": {"required": True, "description": "Path or URL to XML file."}, 39 | "namespace": { 40 | "required": True, 41 | "description": "Namespace to search for to find a tag inside.", 42 | }, 43 | "tags": { 44 | "required": True, 45 | "description": ( 46 | "Dictionary of tags to search for, and variables to " 47 | "name them - {'vendor-display': 'VendorDisplay'" 48 | ), 49 | }, 50 | } 51 | output_variables = { 52 | "xml_output_variables": { 53 | "description": ( 54 | "Output variables per 'tags' supplied as input. Note " 55 | "that this output variable is used as both a " 56 | "placeholder for documentation and for auditing " 57 | "purposes. One should use the actual named output " 58 | "variables as given as values to 'plist_keys' to refer" 59 | "to the output of this processor." 60 | ) 61 | } 62 | } 63 | 64 | __doc__ = description 65 | 66 | def main(self): 67 | if "http" in self.env["xml_file"]: 68 | try: 69 | tree = ET.ElementTree(file=urllib2.urlopen(self.env["xml_file"])) 70 | except urllib2.URLError as err: 71 | raise ProcessorError(err) 72 | else: 73 | try: 74 | tree = ET.ElementTree(file=self.env["xml_file"]) 75 | except IOError as err: 76 | raise ProcessorError(err) 77 | root = tree.getroot() 78 | schema = root.tag.split("}")[0] + "}" 79 | match = root.findall("%s%s" % (schema, self.env["namespace"])) 80 | for key, outputVar in self.env["tags"].iteritems(): 81 | for item in match[-1]: 82 | if item.tag.replace(schema, "") == key: 83 | self.env[outputVar] = item.text 84 | self.output("Found %s as %s" % (key, self.env[outputVar])) 85 | break 86 | if key == "uses-license" and ("license" in self.env["tags"].keys()): 87 | # Special case since the license isn't a traditional key 88 | license_ref = item.attrib["ref"] 89 | self.output("Found license ref: %s" % license_ref) 90 | self.env[outputVar] = license_ref 91 | self.env[self.env["tags"]["license"]] = ( 92 | root[0].text.encode("ascii", "ignore").encode("string-escape") 93 | ) 94 | if key == "url": 95 | # It's easy to find the URL here, the structure is always the same 96 | archives = "%sarchives" % schema 97 | archive = "%sarchive" % schema 98 | url = "%surl" % schema 99 | # Look for a host os 100 | host_os = "%shost-os" % schema 101 | archive_list = match[-1].find(archives).findall(archive) 102 | for arch in archive_list: 103 | if arch.find(host_os) is not None: 104 | # If there's a "host-os" in the archive 105 | if "macosx" in arch.find(host_os).text: 106 | # Look for a Mac version 107 | self.env[outputVar] = arch.find(url).text.encode( 108 | "ascii", "ignore" 109 | ) 110 | # self.output("Found %s as %s" % (key, self.env[outputVar])) 111 | break 112 | else: 113 | # No host os was provided, so assume they're not platform specific 114 | # So we return the first item 115 | self.env[outputVar] = ( 116 | match[-1].find(archives).find(archive).find(url).text 117 | ) 118 | self.output("Found: %s" % self.env[outputVar]) 119 | 120 | 121 | if __name__ == "__main__": 122 | PROCESSOR = AndroidXMLParser() 123 | PROCESSOR.execute_shell() 124 | -------------------------------------------------------------------------------- /Xcode/XcodeVersioner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Copyright (c) Facebook, Inc. and its affiliates. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | """Get all Version information from Xcode.""" 18 | 19 | 20 | from collections import namedtuple 21 | 22 | from autopkglib import Processor, ProcessorError 23 | 24 | 25 | try: 26 | import objc 27 | except ImportError: 28 | pass 29 | 30 | __all__ = ["XcodeVersioner"] 31 | 32 | 33 | class XcodeVersioner(Processor): 34 | """Break down a version number into its separate components.""" 35 | 36 | description = __doc__ 37 | input_variables = { 38 | "version": { 39 | "required": True, 40 | "description": ( 41 | "CFBundleShortVersionString from an Xcode Info.plist. Produced by " 42 | "PlistReader." 43 | ), 44 | }, 45 | "app_path": { 46 | "required": True, 47 | "description": ( 48 | "Path to Xcode app to look up version information from the bundle." 49 | ), 50 | }, 51 | } 52 | output_variables = { 53 | "major_version": {"description": "Major version of Xcode - i.e. Xcode 7, 8."}, 54 | "minor_version": { 55 | "description": "Minor version of Xcode - i.e. Xcode X.1, X.2." 56 | }, 57 | "patch_version": { 58 | "description": ( 59 | "Patch version of Xcode - i.e. Xcode X.Y.0, X.Y.1. " 60 | "Patch version will be normalized to 0 if missing (i.e. 8.3 " 61 | "becomes 8.3.0)." 62 | ) 63 | }, 64 | "is_beta": { 65 | "description": ("Boolean that is true if this Xcode is a beta version.") 66 | }, 67 | "beta_version": {"description": ("The beta number - 1, 2, 3, etc.")}, 68 | "build_version": {"description": ("Build version of Xcode - e.g. 11B500")}, 69 | } 70 | 71 | __doc__ = description 72 | 73 | def _load_objc_framework(self, f_name, f_path, class_whitelist): 74 | loaded = {} 75 | framework_bundle = objc.loadBundle( # NOQA 76 | f_name, bundle_path=f_path, module_globals=loaded 77 | ) 78 | desired = {} 79 | for x in class_whitelist: 80 | if x in loaded: 81 | desired[x] = loaded[x] 82 | return namedtuple("AttributedFramework", desired.keys())(**desired) 83 | 84 | def xcode_info(self, app_path): 85 | DVTFoundation_path = ( 86 | "%s/Contents/SharedFrameworks/" + "DVTFoundation.framework" 87 | ) % app_path 88 | desired_classes = ["DVTToolsInfo"] 89 | DVTFoundation = self._load_objc_framework( 90 | "DVTFoundation", DVTFoundation_path, desired_classes 91 | ) 92 | x_info = DVTFoundation.DVTToolsInfo.toolsInfo() 93 | x_v = x_info.toolsVersion() 94 | x_b = x_info.toolsBuildVersion() 95 | app_info = [] 96 | app_info.append(["major_version", str(x_v.versionMajorComponent())]) 97 | app_info.append(["minor_version", str(x_v.versionMinorComponent())]) 98 | app_info.append(["patch_version", str(x_v.versionUpdateComponent())]) 99 | app_info.append(["build_version", x_b.name()]) 100 | is_beta = bool(x_info.isBeta()) 101 | app_info.append(["is_beta", is_beta]) 102 | if is_beta: 103 | app_info.append(["beta_version", str(x_info.toolsBetaVersion())]) 104 | else: 105 | app_info.append(["beta_version", "0"]) 106 | return app_info 107 | 108 | def main(self): 109 | """Main.""" 110 | main_version_string = self.env["version"] 111 | split_string = main_version_string.split(".") 112 | if len(split_string) < 2: 113 | raise ProcessorError( 114 | "Version string should be in format X.Y, unless Apple broke " 115 | "literally everything again." 116 | ) 117 | self.env["major_version"] = str(split_string[0]) 118 | self.output("Major version: %s" % self.env["major_version"]) 119 | self.env["minor_version"] = str(split_string[1]) 120 | self.output("Minor version: %s" % self.env["minor_version"]) 121 | try: 122 | self.env["patch_version"] = split_string[2] 123 | except IndexError: 124 | self.output("Normalizing patch to 0") 125 | self.env["patch_version"] = str("0") 126 | self.env["is_beta"] = False 127 | xcode_info_results = self.xcode_info(self.env["app_path"]) 128 | xcode_data = {} 129 | for info_pair in xcode_info_results: 130 | xcode_data[info_pair[0]] = info_pair[1] 131 | if xcode_data["is_beta"]: 132 | self.output("Beta version: %s" % xcode_data["beta_version"]) 133 | self.env["is_beta"] = xcode_data["is_beta"] 134 | self.env["beta_version"] = xcode_data["beta_version"] 135 | self.output("Patch version: %s" % self.env["patch_version"]) 136 | 137 | self.env["build_version"] = xcode_data["build_version"] 138 | self.output("Build version: %s" % self.env["build_version"]) 139 | 140 | 141 | if __name__ == "__main__": 142 | PROCESSOR = XcodeVersioner() 143 | PROCESSOR.execute_shell() 144 | -------------------------------------------------------------------------------- /munkitools/munkitools3.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Note: munkitools does not include a code signature. If your 9 | organization requires code signature, it is recommend to internally sign 10 | the application. 11 | 12 | Downloads and imports version 3 of the Munki tools via 13 | the official releases listing on GitHub. You can set INCLUDE_PRERELEASES 14 | to any value to have this recipe pull prerelease versions. 15 | 16 | Note that Munki 3 includes an additional component pkg, munkitools_app_usage. 17 | This recipe imports this to the Munki with the appropriate 'requires' key, 18 | however as it is considered an optional component, this recipe does not 19 | add it as an update_for any Munki component. Admins should add 20 | munkitools_app_usage to a manifest manually if its installation on clients 21 | is desired. 22 | 23 | This recipe cannot be overridden to pull a download from an 24 | alternate location such as munkibuilds.org - it will only download the 25 | official releases. For this, use the munkitools2-autobuild.munki 26 | recipe with a manually-provided DOWNLOAD_URL variable. 27 | 28 | The GitHubReleasesInfoProvider processor used by this recipe also 29 | respects an input variable: 'sort_by_highest_tag_names', which 30 | if set, will ignore the post dates of the releases and instead sort 31 | descending by tag names according to LooseVersion semantics. 32 | 33 | MUNKI_ICON should be overridden with your icon name. 34 | 35 | Identifier 36 | com.facebook.autopkg.pkg.munkitools3 37 | Input 38 | 39 | INCLUDE_PRERELEASES 40 | 41 | NAME 42 | munkitools3 43 | 44 | MinimumVersion 45 | 0.5.0 46 | ParentRecipe 47 | com.facebook.autopkg.download.munkitools3 48 | Process 49 | 50 | 51 | Processor 52 | DeprecationWarning 53 | Arguments 54 | 55 | warning_message 56 | This recipe will soon be removed. Please remove it from your list of recipes. 57 | 58 | 59 | 60 | Arguments 61 | 62 | destination_path 63 | %RECIPE_CACHE_DIR%/unpack 64 | flat_pkg_path 65 | %pathname% 66 | 67 | Processor 68 | FlatPkgUnpacker 69 | 70 | 71 | Arguments 72 | 73 | pkgdirs 74 | 75 | pkgroot 76 | %RECIPE_CACHE_DIR%/repack 77 | 78 | Processor 79 | PkgRootCreator 80 | 81 | 82 | Arguments 83 | 84 | pattern 85 | %RECIPE_CACHE_DIR%/unpack/munkitools_core-* 86 | 87 | Processor 88 | FileFinder 89 | 90 | 91 | Arguments 92 | 93 | destination_pkg 94 | %RECIPE_CACHE_DIR%/repack/munkitools_core.pkg 95 | source_flatpkg_dir 96 | %found_filename% 97 | 98 | Processor 99 | FlatPkgPacker 100 | 101 | 102 | Arguments 103 | 104 | pattern 105 | %RECIPE_CACHE_DIR%/unpack/munkitools_admin-* 106 | 107 | Processor 108 | FileFinder 109 | 110 | 111 | Arguments 112 | 113 | destination_pkg 114 | %RECIPE_CACHE_DIR%/repack/munkitools_admin.pkg 115 | source_flatpkg_dir 116 | %found_filename% 117 | 118 | Processor 119 | FlatPkgPacker 120 | 121 | 122 | Arguments 123 | 124 | pattern 125 | %RECIPE_CACHE_DIR%/unpack/munkitools_app-* 126 | 127 | Processor 128 | FileFinder 129 | 130 | 131 | Arguments 132 | 133 | destination_pkg 134 | %RECIPE_CACHE_DIR%/repack/munkitools_app.pkg 135 | source_flatpkg_dir 136 | %found_filename% 137 | 138 | Processor 139 | FlatPkgPacker 140 | 141 | 142 | Arguments 143 | 144 | pattern 145 | %RECIPE_CACHE_DIR%/unpack/munkitools_app_usage-* 146 | 147 | Processor 148 | FileFinder 149 | 150 | 151 | Arguments 152 | 153 | destination_pkg 154 | %RECIPE_CACHE_DIR%/repack/munkitools_app_usage.pkg 155 | source_flatpkg_dir 156 | %found_filename% 157 | 158 | Processor 159 | FlatPkgPacker 160 | 161 | 162 | Arguments 163 | 164 | pattern 165 | %RECIPE_CACHE_DIR%/unpack/munkitools_launchd-* 166 | 167 | Processor 168 | FileFinder 169 | 170 | 171 | Arguments 172 | 173 | destination_pkg 174 | %RECIPE_CACHE_DIR%/repack/munkitools_launchd.pkg 175 | source_flatpkg_dir 176 | %found_filename% 177 | 178 | Processor 179 | FlatPkgPacker 180 | 181 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /android_sdk/AndroidExtraXMLParser.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | 18 | """See docstring for AndroidExtraXMLParser class.""" 19 | 20 | # Disabling warnings for env members and imports that only affect recipe- 21 | # specific processors. 22 | # pylint: disable=e1101,f0401 23 | 24 | from __future__ import absolute_import, print_function 25 | 26 | import urllib2 27 | import xml.etree.cElementTree as ET 28 | 29 | from autopkglib import Processor, ProcessorError 30 | 31 | __all__ = ["AndroidExtraXMLParser"] 32 | 33 | 34 | def get_element_children_dict(element, schema): 35 | result_dict = dict() 36 | tag = "" 37 | if len(element.getchildren()) >= 1: 38 | for child in element.getchildren(): 39 | tag = child.tag.replace(schema, "") 40 | if not child.getchildren(): 41 | result_dict[tag] = child.text 42 | # the tag name gets the value of the text 43 | else: 44 | # if there are children, each child needs to be converted into a dict 45 | templist = list() 46 | for newchild in child.getchildren(): 47 | templist.append(get_element_children_dict(newchild, schema)) 48 | result_dict[tag] = templist 49 | else: 50 | # no grandchildren 51 | result_dict[element.tag.replace(schema, "")] = element.text 52 | return result_dict 53 | 54 | 55 | def find_value_in_dict(thedict, key): 56 | """Iterate through a dict to find all matching keys, even if inside another 57 | dict.""" 58 | resultlist = list() 59 | if key not in thedict: 60 | # it might be buried inside a dict as a value 61 | for value in thedict.values(): 62 | if type(value) == list: 63 | templist = list() 64 | for newvalue in value: 65 | result = find_value_in_dict(newvalue, key) 66 | if result: 67 | templist.append(result) 68 | if len(templist) == 1: 69 | resultlist = templist[0] 70 | else: 71 | resultlist.extend(templist) 72 | else: 73 | "Adding to dict 2 %s" % key 74 | resultlist.append(thedict[key]) 75 | return resultlist 76 | 77 | 78 | class AndroidExtraXMLParser(Processor): 79 | # pylint: disable=missing-docstring 80 | description = "Parse the addons XML file for a variable match." 81 | input_variables = { 82 | "xml_file": {"required": True, "description": "Path or URL to XML file."}, 83 | "name": {"required": True, "description": "Item name to match."}, 84 | "tags": { 85 | "required": True, 86 | "description": ( 87 | "Dictionary of tags to search for, and variables to " 88 | "name them - {'vendor-display': 'VendorDisplay'" 89 | ), 90 | }, 91 | } 92 | output_variables = {"found_value": {"description": "Result of found attribute."}} 93 | 94 | __doc__ = description 95 | 96 | def main(self): 97 | if "http" in self.env["xml_file"]: 98 | try: 99 | tree = ET.ElementTree(file=urllib2.urlopen(self.env["xml_file"])) 100 | except urllib2.URLError as err: 101 | raise ProcessorError(err) 102 | else: 103 | try: 104 | tree = ET.ElementTree(file=self.env["xml_file"]) 105 | except IOError as err: 106 | raise ProcessorError(err) 107 | root = tree.getroot() 108 | schema = root.tag.split("}")[0] + "}" 109 | # Look for everything else 110 | match = root.findall("%s%s" % (schema, "extra")) 111 | # Now look through the records 112 | for record in match: 113 | result_dict = get_element_children_dict(record, schema) 114 | # We match records by name-display field 115 | if record.find("%sname-display" % schema).text != self.env["name"]: 116 | continue 117 | for key, outputVar in self.env["tags"].iteritems(): 118 | print("Key: %s" % key) 119 | if key == "license": 120 | # Look for license - it's a special case 121 | match = root.findall("%s%s" % (schema, "license")) 122 | self.env[self.env["tags"]["license"]] = ( 123 | match[-1].text.encode("ascii", "ignore").encode("string-escape") 124 | ) 125 | self.output("Found license.") 126 | continue 127 | if key == "uses-license": 128 | self.env[self.env["tags"]["uses-license"]] = record.find( 129 | "%s%s" % (schema, "uses-license") 130 | ).attrib["ref"] 131 | self.output( 132 | "Found license-ref: %s" 133 | % self.env[self.env["tags"]["uses-license"]] 134 | ) 135 | continue 136 | # Look for revision - third special case 137 | if key == "revision": 138 | major = find_value_in_dict(result_dict, "revision")[0][0].get( 139 | "major", "" 140 | ) 141 | minor = find_value_in_dict(result_dict, "revision")[0][1].get( 142 | "minor", "" 143 | ) 144 | micro = find_value_in_dict(result_dict, "revision")[0][2]["micro"] 145 | self.env[self.env["tags"]["revision"]] = "%s.%s.%s" % ( 146 | major, 147 | minor, 148 | micro, 149 | ) 150 | self.output("Revision: %s" % self.env[self.env["tags"]["revision"]]) 151 | continue 152 | value = find_value_in_dict(result_dict, key) 153 | print("Found value: %s" % value) 154 | 155 | 156 | if __name__ == "__main__": 157 | PROCESSOR = AndroidExtraXMLParser() 158 | PROCESSOR.execute_shell() 159 | -------------------------------------------------------------------------------- /munkitools/munkitools4.pkg.recipe: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Copyright 6 | Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved 7 | Description 8 | Note: munkitools does not include a code signature. If your 9 | organization requires code signature, it is recommend to internally sign 10 | the application. 11 | 12 | Downloads and imports version 4 of the Munki tools via 13 | the official releases listing on GitHub. You can set INCLUDE_PRERELEASES 14 | to any value to have this recipe pull prerelease versions. 15 | 16 | Note that Munki 4 includes two additional component pkgs, munkitools_python 17 | and munkitools_no_python. 18 | This recipe imports this to the Munki with the appropriate 'requires' key, 19 | however as it is considered an optional component, this recipe does not 20 | add it as an update_for any Munki component. Admins should add 21 | munkitools_app_usage to a manifest manually if its installation on clients 22 | is desired. 23 | 24 | This recipe cannot be overridden to pull a download from an 25 | alternate location such as munkibuilds.org - it will only download the 26 | official releases. For this, use the munkitools2-autobuild.munki 27 | recipe with a manually-provided DOWNLOAD_URL variable. 28 | 29 | The GitHubReleasesInfoProvider processor used by this recipe also 30 | respects an input variable: 'sort_by_highest_tag_names', which 31 | if set, will ignore the post dates of the releases and instead sort 32 | descending by tag names according to LooseVersion semantics. 33 | 34 | MUNKI_ICON should be overridden with your icon name. 35 | 36 | Identifier 37 | com.facebook.autopkg.pkg.munkitools4 38 | Input 39 | 40 | INCLUDE_PRERELEASES 41 | 42 | NAME 43 | munkitools4 44 | 45 | MinimumVersion 46 | 0.5.0 47 | ParentRecipe 48 | com.facebook.autopkg.download.munkitools4 49 | Process 50 | 51 | 52 | Arguments 53 | 54 | destination_path 55 | %RECIPE_CACHE_DIR%/unpack 56 | flat_pkg_path 57 | %pathname% 58 | 59 | Processor 60 | FlatPkgUnpacker 61 | 62 | 63 | Arguments 64 | 65 | pkgdirs 66 | 67 | pkgroot 68 | %RECIPE_CACHE_DIR%/repack 69 | 70 | Processor 71 | PkgRootCreator 72 | 73 | 74 | Arguments 75 | 76 | pattern 77 | %RECIPE_CACHE_DIR%/unpack/munkitools_core-* 78 | 79 | Processor 80 | FileFinder 81 | 82 | 83 | Arguments 84 | 85 | destination_pkg 86 | %RECIPE_CACHE_DIR%/repack/munkitools_core.pkg 87 | source_flatpkg_dir 88 | %found_filename% 89 | 90 | Processor 91 | FlatPkgPacker 92 | 93 | 94 | Arguments 95 | 96 | pattern 97 | %RECIPE_CACHE_DIR%/unpack/munkitools_admin-* 98 | 99 | Processor 100 | FileFinder 101 | 102 | 103 | Arguments 104 | 105 | destination_pkg 106 | %RECIPE_CACHE_DIR%/repack/munkitools_admin.pkg 107 | source_flatpkg_dir 108 | %found_filename% 109 | 110 | Processor 111 | FlatPkgPacker 112 | 113 | 114 | Arguments 115 | 116 | pattern 117 | %RECIPE_CACHE_DIR%/unpack/munkitools_app-* 118 | 119 | Processor 120 | FileFinder 121 | 122 | 123 | Arguments 124 | 125 | destination_pkg 126 | %RECIPE_CACHE_DIR%/repack/munkitools_app.pkg 127 | source_flatpkg_dir 128 | %found_filename% 129 | 130 | Processor 131 | FlatPkgPacker 132 | 133 | 134 | Arguments 135 | 136 | pattern 137 | %RECIPE_CACHE_DIR%/unpack/munkitools_app_usage-* 138 | 139 | Processor 140 | FileFinder 141 | 142 | 143 | Arguments 144 | 145 | destination_pkg 146 | %RECIPE_CACHE_DIR%/repack/munkitools_app_usage.pkg 147 | source_flatpkg_dir 148 | %found_filename% 149 | 150 | Processor 151 | FlatPkgPacker 152 | 153 | 154 | Arguments 155 | 156 | pattern 157 | %RECIPE_CACHE_DIR%/unpack/munkitools_launchd-* 158 | 159 | Processor 160 | FileFinder 161 | 162 | 163 | Arguments 164 | 165 | destination_pkg 166 | %RECIPE_CACHE_DIR%/repack/munkitools_launchd.pkg 167 | source_flatpkg_dir 168 | %found_filename% 169 | 170 | Processor 171 | FlatPkgPacker 172 | 173 | 174 | Arguments 175 | 176 | pattern 177 | %RECIPE_CACHE_DIR%/unpack/munkitools_python-* 178 | 179 | Processor 180 | FileFinder 181 | 182 | 183 | Arguments 184 | 185 | destination_pkg 186 | %RECIPE_CACHE_DIR%/repack/munkitools_python.pkg 187 | source_flatpkg_dir 188 | %found_filename% 189 | 190 | Processor 191 | FlatPkgPacker 192 | 193 | 194 | Arguments 195 | 196 | pattern 197 | %RECIPE_CACHE_DIR%/unpack/munkitools_no_python-* 198 | 199 | Processor 200 | FileFinder 201 | 202 | 203 | Arguments 204 | 205 | destination_pkg 206 | %RECIPE_CACHE_DIR%/repack/munkitools_no_python.pkg 207 | source_flatpkg_dir 208 | %found_filename% 209 | 210 | Processor 211 | FlatPkgPacker 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /Chef_Processors/ChefLaunchd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for ChefLaunchd class.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | from autopkglib import Processor 13 | 14 | __all__ = ["ChefLaunchd"] 15 | 16 | 17 | class ChefLaunchd(Processor): 18 | description = ( 19 | "Produces a cookbook_file Chef block. See " 20 | "https://docs.chef.io/resource_launchd.html." 21 | ) 22 | input_variables = { 23 | "resource_name": { 24 | "required": True, 25 | "description": ( 26 | "Name for the resource. This can be a single " 27 | "string or an array of strings. If an array is " 28 | "provided, the first item in the array will be the " 29 | "resource name and the rest will be turned " 30 | "into an array." 31 | ), 32 | }, 33 | "launchd_resource_array": { 34 | "required": False, 35 | "description": "Does the resource_name represent an array variable?", 36 | }, 37 | "launchd_action": { 38 | "required": True, 39 | "description": "Resource action. See documentation.", 40 | }, 41 | "launchd_notifies": { 42 | "required": False, 43 | "description": ( 44 | "Which resource takes action when this resource's state changes." 45 | ), 46 | }, 47 | "launchd_launchd_name": { 48 | "required": False, 49 | "description": ("The name of the launchd."), 50 | }, 51 | "launchd_subscribes": { 52 | "required": False, 53 | "description": ( 54 | "Specify that this resource is to listen " 55 | "to another resource, and then take action " 56 | "when that resource's state changes." 57 | ), 58 | }, 59 | "launchd_only_if": {"required": False, "description": "only_if guard phrase."}, 60 | "launchd_not_if": {"required": False, "description": "not_if guard phrase."}, 61 | "launchd_extra_indentation": { 62 | "required": False, 63 | "description": "Indent this block. Defaults to empty.", 64 | }, 65 | "launchd_indentation_end": { 66 | "required": False, 67 | "description": "Should this end an indented section? Defaults to empty.", 68 | }, 69 | "launchd_path": { 70 | "required": False, 71 | "description": "Explicit path to plist file.", 72 | }, 73 | } 74 | output_variables = {"chef_block": {"description": "Chef block."}} 75 | 76 | __doc__ = description 77 | 78 | def main(self): 79 | # chef block variables 80 | prefix = "launchd_" 81 | block_name = "launchd" 82 | 83 | # formatting variables 84 | extra_formatting = "" 85 | end_text = "end\n" 86 | self.env["chef_block"] = "" 87 | each_do_beginning = "[\n" 88 | each_do_end = ".each do |item|\n" 89 | self.env["chef_block"] = each_do_beginning 90 | name = "item" 91 | notif_text = "not_if" 92 | onlyif_text = "only_if" 93 | indent_block = "" 94 | 95 | # Should this block be indented? 96 | if self.env.get("%sextra_indentation" % prefix): 97 | self.output("Adding indentation.") 98 | indent_block = " " 99 | end_text = " " + end_text 100 | extra_formatting = " " 101 | # Should this end an indented block? 102 | if self.env.get("%sindentation_end" % prefix): 103 | end_text = end_text + "end\n" 104 | 105 | # Check to see if only one item was passed 106 | if len(self.env["resource_name"].split(",")) == 1: 107 | if self.env.get("%sresource_array" % prefix): 108 | # it's a node variable representating an array 109 | self.env["chef_block"] = ( 110 | indent_block 111 | + block_name 112 | + " " 113 | + self.env["resource_name"] 114 | + each_do_end 115 | ) 116 | else: 117 | self.env["chef_block"] = ( 118 | indent_block 119 | + block_name 120 | + " " 121 | + self.env["resource_name"] 122 | + " do\n" 123 | ) 124 | else: 125 | for resource_name in self.env["resource_name"].split(","): 126 | self.env["chef_block"] += " %s,\n" % resource_name 127 | self.env["chef_block"] += "]" + each_do_end 128 | # Remove trailing comma 129 | self.env["chef_block"] = self.env["chef_block"].replace(",\n]", "\n]") 130 | self.env["chef_block"] += "%s %s do\n" % (block_name, name) 131 | # Insert an extra tab before everything 132 | extra_formatting = " " 133 | end_text = indent_block + "end\n\n" 134 | 135 | input_list = sorted(self.input_variables.keys()) 136 | # Start the block 137 | # Remove the indentation keys 138 | input_list.remove("%sextra_indentation" % prefix) 139 | input_list.remove("%sindentation_end" % prefix) 140 | # Place not_if guards first 141 | if self.env.get("%snot_if" % prefix): 142 | self.env["chef_block"] += "%s %s %s\n" % ( 143 | extra_formatting, 144 | notif_text, 145 | self.env["%snot_if" % prefix], 146 | ) 147 | input_list.remove("%snot_if" % prefix) 148 | # Place only_if guards next 149 | if self.env.get("%sonly_if" % prefix): 150 | self.env["chef_block"] += "%s %s %s\n" % ( 151 | extra_formatting, 152 | onlyif_text, 153 | self.env["%sonly_if" % prefix], 154 | ) 155 | input_list.remove("%sonly_if" % prefix) 156 | # Remove the special keys 157 | input_list.remove("%sresource_array" % prefix) 158 | input_list.remove("resource_name") 159 | # Loop through all remaining keys 160 | for key in input_list: 161 | if self.env.get(key, ""): 162 | key_text = "%s" % key.replace("%s" % prefix, "") 163 | self.env["chef_block"] += "%s %s %s\n" % ( 164 | extra_formatting, 165 | key_text, 166 | self.env[key], 167 | ) 168 | # Clear out the key so it doesn't poison future runs 169 | self.env[key] = "" 170 | # end it 171 | self.env["chef_block"] += end_text + "\n" 172 | self.output("Chef block:\n%s" % self.env["chef_block"]) 173 | # Clean up the keys that weren't iterated through 174 | self.env["%sextra_indentation" % prefix] = "" 175 | self.env["%sindentation_end" % prefix] = "" 176 | self.env["%snot_if" % prefix] = "" 177 | self.env["%sonly_if" % prefix] = "" 178 | 179 | 180 | if __name__ == "__main__": 181 | PROCESSOR = ChefLaunchd() 182 | PROCESSOR.execute_shell() 183 | -------------------------------------------------------------------------------- /Chef_Processors/ChefRemotePackage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for ChefRemotePackage class.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | from autopkglib import Processor 13 | 14 | __all__ = ["ChefRemotePackage"] 15 | 16 | 17 | class ChefRemotePackage(Processor): 18 | description = "Produces a cpe_remote_package Chef block." 19 | input_variables = { 20 | "resource_name": { 21 | "required": True, 22 | "description": ( 23 | "Name for the resource. This can be a single " 24 | "string or an array of strings. If an array is " 25 | "provided, the first item in the array will be the " 26 | "resource name and the rest will be turned " 27 | "into an array." 28 | ), 29 | }, 30 | "resource_array": { 31 | "required": False, 32 | "description": "Does the resource_name represent an array variable?", 33 | }, 34 | "app": {"required": False, "description": "Name of the app being installed."}, 35 | "checksum": {"required": True, "description": "SHA256 checksum for package."}, 36 | "cleanup": { 37 | "required": False, 38 | "description": ( 39 | "Specify whether we should keep the downloaded package." 40 | ), 41 | }, 42 | "pkg_name": { 43 | "required": False, 44 | "description": ( 45 | "Name of the package if it is not the same as ", 46 | "`app`-`version`, or if the name has spaces.", 47 | ), 48 | }, 49 | "receipt": { 50 | "required": True, 51 | "description": ( 52 | "The package receipt to determine if it's already installed." 53 | ), 54 | }, 55 | "remote": { 56 | "required": False, 57 | "description": ( 58 | "Specify whether we should try to download the package." 59 | ), 60 | }, 61 | "version": { 62 | "required": True, 63 | "description": ( 64 | "The version of the package receipt to determine " 65 | "if it's already installed." 66 | ), 67 | }, 68 | "only_if": {"required": False, "description": "only_if guard phrase."}, 69 | "not_if": {"required": False, "description": "not_if guard phrase."}, 70 | "extra_indentation": { 71 | "required": False, 72 | "description": "Indent this block. Defaults to empty.", 73 | }, 74 | "indentation_end": { 75 | "required": False, 76 | "description": "Should this end an indented section? Defaults to empty.", 77 | }, 78 | } 79 | output_variables = {"chef_block": {"description": "Chef block."}} 80 | 81 | __doc__ = description 82 | 83 | def main(self): 84 | # chef block variables 85 | prefix = "" 86 | block_name = "cpe_remote_pkg" 87 | 88 | # formatting variables 89 | extra_formatting = "" 90 | end_text = "end\n" 91 | self.env["chef_block"] = "" 92 | each_do_beginning = "[\n" 93 | each_do_end = ".each do |item|\n" 94 | self.env["chef_block"] = each_do_beginning 95 | name = "item" 96 | notif_text = "not_if" 97 | onlyif_text = "only_if" 98 | indent_block = "" 99 | 100 | # Should this block be indented? 101 | if self.env.get("%sextra_indentation" % prefix): 102 | self.output("Adding indentation.") 103 | indent_block = " " 104 | end_text = " " + end_text 105 | extra_formatting = " " 106 | # Should this end an indented block? 107 | if self.env.get("%sindentation_end" % prefix): 108 | end_text = end_text + "end\n" 109 | 110 | # Check to see if only one item was passed 111 | if len(self.env["resource_name"].split(",")) == 1: 112 | if self.env.get("%sresource_array" % prefix): 113 | # it's a node variable representating an array 114 | self.env["chef_block"] = ( 115 | indent_block 116 | + block_name 117 | + " " 118 | + self.env["resource_name"] 119 | + each_do_end 120 | ) 121 | else: 122 | self.env["chef_block"] = ( 123 | indent_block 124 | + block_name 125 | + " " 126 | + self.env["resource_name"] 127 | + " do\n" 128 | ) 129 | else: 130 | for resource_name in self.env["resource_name"].split(","): 131 | self.env["chef_block"] += " %s,\n" % resource_name 132 | self.env["chef_block"] += "]" + each_do_end 133 | # Remove trailing comma 134 | self.env["chef_block"] = self.env["chef_block"].replace(",\n]", "\n]") 135 | self.env["chef_block"] += "%s %s do\n" % (block_name, name) 136 | # Insert an extra tab before everything 137 | extra_formatting = " " 138 | end_text = indent_block + "end\n" 139 | 140 | input_list = sorted(self.input_variables.keys()) 141 | # Start the block 142 | # Remove the indentation keys 143 | try: 144 | input_list.remove("%sextra_indentation" % prefix) 145 | input_list.remove("%sindentation_end" % prefix) 146 | except ValueError: 147 | pass 148 | # Place not_if guards first 149 | if self.env.get("%snot_if" % prefix): 150 | self.env["chef_block"] += "%s %s %s\n" % ( 151 | extra_formatting, 152 | notif_text, 153 | self.env["%snot_if" % prefix], 154 | ) 155 | input_list.remove("%snot_if" % prefix) 156 | # Place only_if guards next 157 | if self.env.get("%sonly_if" % prefix): 158 | self.env["chef_block"] += "%s %s %s\n" % ( 159 | extra_formatting, 160 | onlyif_text, 161 | self.env["%sonly_if" % prefix], 162 | ) 163 | input_list.remove("%sonly_if" % prefix) 164 | # Remove the special keys 165 | try: 166 | input_list.remove("%sresource_array" % prefix) 167 | input_list.remove("resource_name") 168 | except ValueError: 169 | pass 170 | # Loop through all remaining keys 171 | for key in input_list: 172 | if self.env.get(key, ""): 173 | key_text = "%s" % key.replace("%s" % prefix, "") 174 | self.env["chef_block"] += "%s %s %s\n" % ( 175 | extra_formatting, 176 | key_text, 177 | self.env[key], 178 | ) 179 | # Clear out the key so it doesn't poison future runs 180 | self.env[key] = "" 181 | # end it 182 | self.env["chef_block"] += end_text 183 | self.output("Chef block:\n%s" % self.env["chef_block"]) 184 | # Clean up the keys that weren't iterated through 185 | self.env["%sextra_indentation" % prefix] = "" 186 | self.env["%sindentation_end" % prefix] = "" 187 | self.env["%snot_if" % prefix] = "" 188 | self.env["%sonly_if" % prefix] = "" 189 | 190 | 191 | if __name__ == "__main__": 192 | PROCESSOR = ChefRemotePackage() 193 | PROCESSOR.execute_shell() 194 | -------------------------------------------------------------------------------- /Chef_Processors/ChefMacOSXUserDefaults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for ChefMacOSXUserDefaults class.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | from autopkglib import Processor 13 | 14 | __all__ = ["ChefMacOSXUserDefaults"] 15 | 16 | 17 | class ChefMacOSXUserDefaults(Processor): 18 | description = ( 19 | "Produces a mac_os_x_user_defaults Chef block. See README in mac_os_x." 20 | ) 21 | input_variables = { 22 | "resource_name": { 23 | "required": True, 24 | "description": ( 25 | "Name for the resource. This can be a single " 26 | "string or an array of strings. If an array is " 27 | "provided, the first item in the array will be the " 28 | "resource name and the rest will be turned " 29 | "into an array." 30 | ), 31 | }, 32 | "userdefaults_resource_array": { 33 | "required": False, 34 | "description": "Does the resource_name represent an array variable?", 35 | }, 36 | "userdefaults_action": { 37 | "required": False, 38 | "description": "Resource action. Only action allowed is :write.", 39 | }, 40 | "userdefaults_domain": {"required": True, "description": "Domain to write."}, 41 | "userdefaults_global": { 42 | "required": False, 43 | "description": "Bool for global domain.", 44 | }, 45 | "userdefaults_current_host": { 46 | "required": False, 47 | "description": "Bool for current host.", 48 | }, 49 | "userdefaults_key": {"required": True, "description": "Key to write to."}, 50 | "userdefaults_value": { 51 | "required": True, 52 | "description": "Value to write to key.", 53 | }, 54 | "userdefaults_type": { 55 | "required": False, 56 | "description": ("Type of key to write."), 57 | }, 58 | "userdefaults_user": {"required": False, "description": ("User to write to.")}, 59 | "userdefaults_sudo": { 60 | "required": False, 61 | "description": ("Bool to use sudo or not."), 62 | }, 63 | "userdefaults_is_set": { 64 | "required": False, 65 | "description": ("Bool to determine if is set or not."), 66 | }, 67 | "userdefaults_only_if": { 68 | "required": False, 69 | "description": "only_if guard phrase.", 70 | }, 71 | "userdefaults_not_if": { 72 | "required": False, 73 | "description": "not_if guard phrase.", 74 | }, 75 | "userdefaults_extra_indentation": { 76 | "required": False, 77 | "description": "Indent this block. Defaults to empty.", 78 | }, 79 | "userdefaults_indentation_end": { 80 | "required": False, 81 | "description": "Should this end an indented section? Defaults to empty.", 82 | }, 83 | } 84 | output_variables = {"chef_block": {"description": "Chef block."}} 85 | 86 | __doc__ = description 87 | 88 | def main(self): 89 | # chef block variables 90 | prefix = "userdefaults_" 91 | block_name = "mac_os_x_userdefaults" 92 | 93 | # formatting variables 94 | extra_formatting = "" 95 | end_text = "end\n" 96 | self.env["chef_block"] = "" 97 | each_do_beginning = "[\n" 98 | each_do_end = ".each do |item|\n" 99 | self.env["chef_block"] = each_do_beginning 100 | name = "item" 101 | notif_text = "not_if" 102 | onlyif_text = "only_if" 103 | indent_block = "" 104 | 105 | # Should this block be indented? 106 | if self.env.get("%sextra_indentation" % prefix): 107 | self.output("Adding indentation.") 108 | indent_block = " " 109 | end_text = " " + end_text 110 | extra_formatting = " " 111 | # Should this end an indented block? 112 | if self.env.get("%sindentation_end" % prefix): 113 | end_text = end_text + "end\n" 114 | 115 | # Check to see if only one item was passed 116 | if len(self.env["resource_name"].split(",")) == 1: 117 | if self.env.get("%sresource_array" % prefix): 118 | # it's a node variable representating an array 119 | self.env["chef_block"] = ( 120 | indent_block 121 | + block_name 122 | + " " 123 | + self.env["resource_name"] 124 | + each_do_end 125 | ) 126 | else: 127 | self.env["chef_block"] = ( 128 | indent_block 129 | + block_name 130 | + " " 131 | + self.env["resource_name"] 132 | + " do\n" 133 | ) 134 | else: 135 | for resource_name in self.env["resource_name"].split(","): 136 | self.env["chef_block"] += " %s,\n" % resource_name 137 | self.env["chef_block"] += "]" + each_do_end 138 | # Remove trailing comma 139 | self.env["chef_block"] = self.env["chef_block"].replace(",\n]", "\n]") 140 | self.env["chef_block"] += "%s %s do\n" % (block_name, name) 141 | # Insert an extra tab before everything 142 | extra_formatting = " " 143 | end_text = indent_block + "end\n\n" 144 | 145 | input_list = sorted(self.input_variables.keys()) 146 | # Start the block 147 | # Remove the indentation keys 148 | input_list.remove("%sextra_indentation" % prefix) 149 | input_list.remove("%sindentation_end" % prefix) 150 | # Place not_if guards first 151 | if self.env.get("%snot_if" % prefix): 152 | self.env["chef_block"] += "%s %s %s\n" % ( 153 | extra_formatting, 154 | notif_text, 155 | self.env["%snot_if" % prefix], 156 | ) 157 | input_list.remove("%snot_if" % prefix) 158 | # Place only_if guards next 159 | if self.env.get("%sonly_if" % prefix): 160 | self.env["chef_block"] += "%s %s %s\n" % ( 161 | extra_formatting, 162 | onlyif_text, 163 | self.env["%sonly_if" % prefix], 164 | ) 165 | input_list.remove("%sonly_if" % prefix) 166 | # Remove the special keys 167 | input_list.remove("%sresource_array" % prefix) 168 | input_list.remove("resource_name") 169 | # Loop through all remaining keys 170 | for key in input_list: 171 | if self.env.get(key, ""): 172 | key_text = "%s" % key.replace("%s" % prefix, "") 173 | self.env["chef_block"] += "%s %s %s\n" % ( 174 | extra_formatting, 175 | key_text, 176 | self.env[key], 177 | ) 178 | # Clear out the key so it doesn't poison future runs 179 | self.env[key] = "" 180 | # end it 181 | self.env["chef_block"] += end_text + "\n" 182 | self.output("Chef block:\n%s" % self.env["chef_block"]) 183 | # Clean up the keys that weren't iterated through 184 | self.env["%sextra_indentation" % prefix] = "" 185 | self.env["%sindentation_end" % prefix] = "" 186 | self.env["%snot_if" % prefix] = "" 187 | self.env["%sonly_if" % prefix] = "" 188 | 189 | 190 | if __name__ == "__main__": 191 | PROCESSOR = ChefMacOSXUserDefaults() 192 | PROCESSOR.execute_shell() 193 | -------------------------------------------------------------------------------- /Chef_Processors/ChefRemoteDirectory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) Facebook, Inc. and its affiliates. 5 | # 6 | # This source code is licensed under the BSD-style license found in the 7 | # LICENSE file in the root directory of this source tree.# 8 | """See docstring for ChefRemoteDirectory class.""" 9 | 10 | from __future__ import absolute_import 11 | 12 | from autopkglib import Processor 13 | 14 | __all__ = ["ChefRemoteDirectory"] 15 | 16 | 17 | class ChefRemoteDirectory(Processor): 18 | description = ( 19 | "Produces a remote_directory Chef block. See " 20 | "https://docs.chef.io/resource_remote_directory.html." 21 | ) 22 | input_variables = { 23 | "resource_name": { 24 | "required": True, 25 | "description": ( 26 | "Name for the resource. This can be a single " 27 | "string or an array of strings. If an array is " 28 | "provided, the first item in the array will be the " 29 | "resource name and the rest will be turned " 30 | "into an array." 31 | ), 32 | }, 33 | "action": { 34 | "required": False, 35 | "description": "Resource action. See documentation.", 36 | }, 37 | "cookbook": { 38 | "required": False, 39 | "description": "The cookbook in which a file is located.", 40 | }, 41 | "files_backup": { 42 | "required": False, 43 | "description": ( 44 | "The number of backup copies to keep for files in the directory." 45 | ), 46 | }, 47 | "files_group": { 48 | "required": False, 49 | "description": ( 50 | "Configure group permissions for files. A string or ID " 51 | "that identifies the group owner by group name." 52 | ), 53 | }, 54 | "files_mode": {"required": False, "description": "The octal mode for a file."}, 55 | "files_owner": { 56 | "required": False, 57 | "description": ( 58 | "Configure owner permissions for files. A string or ID " 59 | "that identifies the group owner by group name." 60 | ), 61 | }, 62 | "group": { 63 | "required": False, 64 | "description": "Use to configure permissions for directories.", 65 | }, 66 | "ignore_failure": { 67 | "required": False, 68 | "description": ( 69 | "Continue running a recipe if a resource fails for any reason." 70 | ), 71 | }, 72 | "inherits": { 73 | "required": False, 74 | "description": ( 75 | "Windows only. Whether a file inherits rights from " 76 | "its parent directory." 77 | ), 78 | }, 79 | "mode": { 80 | "required": False, 81 | "description": ( 82 | "A quoted 3-5 character string that defines the octal mode." 83 | ), 84 | }, 85 | "notifies": { 86 | "required": False, 87 | "description": ( 88 | "Which resource takes action when this resource's state changes." 89 | ), 90 | }, 91 | "overwrite": { 92 | "required": False, 93 | "description": "Overwrite a file when it is different.", 94 | }, 95 | "owner": { 96 | "required": False, 97 | "description": "Use to configure permissions for directories.", 98 | }, 99 | "path": {"required": False, "description": "The path to the directory."}, 100 | "provider": { 101 | "required": False, 102 | "description": "Optional. Explicitly specify a provider.", 103 | }, 104 | "purge": { 105 | "required": False, 106 | "description": "Purge extra files found in the target directory.", 107 | }, 108 | "recursive": { 109 | "required": False, 110 | "description": "Create or delete directories recursively.", 111 | }, 112 | "retries": { 113 | "required": False, 114 | "description": ( 115 | "The number of times to catch exceptions and retry the resource." 116 | ), 117 | }, 118 | "retry_delay": { 119 | "required": False, 120 | "description": "The retry delay (in seconds).", 121 | }, 122 | "rights": { 123 | "required": False, 124 | "description": ( 125 | "Microsoft Windows only. The permissions for users and " 126 | "groups in a Microsoft Windows environment." 127 | ), 128 | }, 129 | "source": { 130 | "required": True, 131 | "description": "The base name of the source file.", 132 | }, 133 | "subscribes": { 134 | "required": False, 135 | "description": ( 136 | "Specify that this resource is to listen to another " 137 | "resource, and then take action when that resource's " 138 | "state changes.." 139 | ), 140 | }, 141 | "only_if": {"required": False, "description": "only_if guard phrase."}, 142 | "not_if": {"required": False, "description": "not_if guard phrase."}, 143 | } 144 | output_variables = {"chef_block": {"description": "Chef block."}} 145 | 146 | __doc__ = description 147 | 148 | def main(self): 149 | extra_formatting = "" 150 | block_name = "remote_directory" 151 | self.env["remote_directory"] = "" 152 | if not isinstance(self.env["chef_block"], basestring): 153 | # Not a string, assume it's an array of strings 154 | each_do_beginning = "[\n" 155 | each_do_end = "].each do |item|\n\t" 156 | self.env["remote_directory"] = each_do_beginning 157 | for resource_name in self.env["chef_block"]: 158 | self.env["remote_directory"] += "\t%s,\n" % resource_name 159 | self.env["remote_directory"] += each_do_end 160 | name = "item" 161 | # insert an extra tab before everything 162 | extra_formatting = "\t" 163 | end_text = "\tend\nend\n\n" 164 | else: 165 | name = self.env["chef_block"] 166 | notif_text = "\tnot_if" 167 | onlyif_text = "\tonly_if" 168 | 169 | input_list = sorted(self.input_variables.keys()) 170 | # Start the block 171 | self.env["remote_directory"] += "%s %s do\n" % (block_name, name) 172 | # Place not_if guards first 173 | if self.env.get("not_if"): 174 | self.env["remote_directory"] += "%s\t%s %s\n" % ( 175 | extra_formatting, 176 | notif_text, 177 | self.env["not_if"], 178 | ) 179 | input_list.remove("not_if") 180 | # Place only_if guards next 181 | if self.env.get("only_if"): 182 | self.env["remote_directory"] += "%s\t%s %s\n" % ( 183 | extra_formatting, 184 | onlyif_text, 185 | self.env["only_if"], 186 | ) 187 | input_list.remove("only_if") 188 | input_list.remove("resource_name") 189 | # Loop through all keys 190 | for key in input_list: 191 | if self.env.get(key, ""): 192 | key_text = "\t%s" % key 193 | self.env["remote_directory"] += "%s\t%s %s\n" % ( 194 | extra_formatting, 195 | key_text, 196 | self.env[key], 197 | ) 198 | # clear out the key so it doesn't poison future runs 199 | self.env[key] = "" 200 | # end it 201 | self.env["remote_directory"] += end_text 202 | self.output("Chef block:\n%s" % self.env["remote_directory"]) 203 | 204 | 205 | if __name__ == "__main__": 206 | PROCESSOR = ChefRemoteDirectory() 207 | PROCESSOR.execute_shell() 208 | --------------------------------------------------------------------------------