Beispiel #1
0
 public Job(DistroBase distro)
 {
     this.distro     = distro;
     this.profile    = null;
     this.target     = BuildTarget.NoTarget;
     this.outputPath = null;
 }
Beispiel #2
0
 public Job(BuildProfile profile, BuildTarget target, string outputPath = null)
 {
     this.profile    = profile;
     this.target     = target;
     this.outputPath = outputPath;
     this.distro     = null;
 }
Beispiel #3
0
 /// <summary>
 /// Construct a result that represents a Trimmer error.
 /// </summary>
 public static ProfileBuildResult Error(BuildProfile profile, string error)
 {
     return(new ProfileBuildResult()
     {
         profile = profile,
         error = error,
         report = null,
     });
 }
Beispiel #4
0
        protected void OnEnable()
        {
            profile       = (EditableProfile)target;
            editorProfile = target as EditorProfile;
            buildProfile  = target as BuildProfile;

            options = SortOptionsByCategoryAndName(profile.EditProfile);

            // Invalidate source profile dropdown
            sourceProfiles      = null;
            sourceProfilesNames = null;
        }
Beispiel #5
0
        /// <summary>
        /// Determine all the scripting define symbols set by a build profile for the given build target.
        /// </summary>
        static void GetScriptingDefineSymbols(BuildProfile buildProfile, BuildTarget target, HashSet <string> symbols)
        {
            var includesAnyOption = false;

            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, target);
                includesAnyOption |= ((inclusion & OptionInclusion.Option) != 0);

                option.GetScriptingDefineSymbols(inclusion, symbols);
            }

            if (!includesAnyOption)
            {
                symbols.Add(NO_TRIMMER);
            }
        }
Beispiel #6
0
        /// <summary>
        /// For builds where BuildPlayerOptions is not available, apply the
        /// required scripting define symbols to the the player settings.
        /// </summary>
        static void ApplyScriptingDefineSymbolsToPlayerSettings(BuildProfile buildProfile, BuildTarget target)
        {
            // Run options' PreprocessBuild and collect scripting define symbols
            var targetGroup = BuildPipeline.GetBuildTargetGroup(target);

            previousScriptingDefineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
            var symbols = GetCurrentScriptingDefineSymbols(targetGroup);

            // Remove all symbols previously added by Trimmer
            symbols.RemoveWhere(d => d.StartsWith(Option.DEFINE_PREFIX));
            symbols.Remove(NO_TRIMMER);

            // Add Trimmer's symbols
            GetScriptingDefineSymbols(buildProfile, target, symbols);

            // Apply scripting define symbols
            PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", symbols.ToArray()));
        }
Beispiel #7
0
        /// <summary>
        /// Build a profile for its default targets and with the default build options.
        /// </summary>
        public static void Build(BuildProfile profile, IBuildsCompleteListener onComplete = null)
        {
            var targets = profile.BuildTargets.ToArray();
            var jobs    = new BuildRunner.Job[targets.Length];

            for (int i = 0; i < targets.Length; i++)
            {
                jobs[i] = new BuildRunner.Job()
                {
                    profile = profile,
                    target  = targets[i],
                };
            }

            var runner = ScriptableObject.CreateInstance <BuildRunner>();

            runner.Run(jobs, onComplete, TrimmerPrefs.RestoreActiveBuildTarget);
        }
Beispiel #8
0
        /// <summary>
        /// Add Trimmer's scripting define symbols to the build player option's extraScriptingDefines.
        /// </summary>
        static void AddScriptingDefineSymbols(BuildProfile buildProfile, ref BuildPlayerOptions options)
        {
    #if !UNITY_2020_1_OR_NEWER
            // Before Unity 2020.1 BuildPlayerOptions.extraScriptingDefines didn't exist,
            // fall back to changing player settings
            ApplyScriptingDefineSymbolsToPlayerSettings(buildProfile, options.target);
    #else
            var symbols = new HashSet <string>();

            if (options.extraScriptingDefines != null)
            {
                symbols.AddRange(options.extraScriptingDefines);
            }

            GetScriptingDefineSymbols(buildProfile, options.target, symbols);

            options.extraScriptingDefines = symbols.ToArray();
    #endif
        }
Beispiel #9
0
        /// <summary>
        /// Build a specific target of a profile with the default build options.
        /// </summary>
        /// <param name="profile">Profile to build</param>
        /// <param name="target">Target to build, needs to be part of profile</param>
        public static void Build(BuildProfile profile, BuildTarget target, IBuildsCompleteListener onComplete = null)
        {
            if (profile.BuildTargets != null && profile.BuildTargets.Any() && !profile.BuildTargets.Contains(target))
            {
                var err = $"Build target {target} is not part of the build profile {profile.name}";
                if (onComplete != null)
                {
                    onComplete.OnComplete(false, new[] { ProfileBuildResult.Error(profile, err) });
                }
                else
                {
                    Debug.LogError(err);
                }
                return;
            }

            var runner = ScriptableObject.CreateInstance <BuildRunner>();

            runner.Run(new[] { new BuildRunner.Job(profile, target) }, onComplete, TrimmerPrefs.RestoreActiveBuildTarget);
        }
Beispiel #10
0
        void SourceProfileGUI()
        {
            if (editorProfile != null)
            {
                EditorGUILayout.BeginHorizontal();
                {
                    if (sourceProfiles == null)
                    {
                        sourceProfiles      = BuildProfile.AllBuildProfiles.Prepend(null).ToArray();
                        sourceProfilesNames = sourceProfiles.Select(p => p == null ? "Editor" : p.name).ToArray();
                    }

                    var sourceProfile = editorProfile.EditorSourceProfile;

                    int selected    = Array.IndexOf(sourceProfiles, sourceProfile);
                    var newSelected = EditorGUILayout.Popup("Source Profile", selected, sourceProfilesNames);

                    if (selected != newSelected)
                    {
                        BuildProfile newProfile = null;
                        if (newSelected > 0)
                        {
                            newProfile = sourceProfiles[newSelected];
                        }
                        editorProfile.EditorSourceProfile = newProfile;
                    }

                    GUI.enabled = (sourceProfile != null);
                    if (GUILayout.Button("Edit", EditorStyles.miniButton, GUILayout.Width(40)))
                    {
                        Selection.activeObject = sourceProfile;
                        EditorApplication.ExecuteMenuItem("Window/Inspector");
                    }
                    GUI.enabled = true;
                }
                EditorGUILayout.EndHorizontal();
            }
        }
Beispiel #11
0
        /// <summary>
        /// Build a profile with the given build options, synchronously starting the build.
        /// </summary>
        /// <remarks>
        /// The `BuildPlayerOptions` will be passed through the profile's Options'
        /// <see cref="Option.PrepareBuild"/>, which can modify it before the build is started.
        ///
        /// > [!NOTE]
        /// > If you do not set `options.locationPathName` and no option sets
        /// > it in the `PrepareBuild` callback, then a save dialog will be shown.
        ///
        /// > [!WARNING]
        /// > With this method it's possible to build for a build target even if this
        /// > target is not the active build target. This can lead to issues where
        /// > build code for the given target is not run.
        /// </remarks>
        public static BuildReport BuildSync(BuildProfile buildProfile, BuildPlayerOptions options)
        {
            // Prepare build
            BuildType      = TrimmerBuildType.Profile;
            currentProfile = buildProfile;

            // Add Trimmer scripting define symbols
            AddScriptingDefineSymbols(buildProfile, ref options);

            // Run options' PrepareBuild
            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                if ((option.Capabilities & OptionCapabilities.ConfiguresBuild) == 0)
                {
                    continue;
                }
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, options.target);
                options = option.PrepareBuild(options, inclusion);
            }

            // Ask for location if none has been set
            if (string.IsNullOrEmpty(options.locationPathName))
            {
                if (Application.isBatchMode)
                {
                    // Cannot pick path in batch mode
                    throw new Exception($"Trimmer: No build path set by profile or in build player options.");
                }
                else
                {
                    options.locationPathName = PickBuildLocation(options.target);
                    if (string.IsNullOrEmpty(options.locationPathName))
                    {
                        Debug.Log("Cancelled build location dialog");
                        return(null);
                    }
                }
            }

            // Make sure the path has the right extension
            // Call internal method:
            // string PostprocessBuildPlayer.GetExtensionForBuildTarget(BuildTargetGroup targetGroup, BuildTarget target, BuildOptions options)
            var PostprocessBuildPlayer = typeof(BuildPipeline).Assembly.GetType("UnityEditor.PostprocessBuildPlayer");

            if (PostprocessBuildPlayer == null)
            {
                Debug.LogWarning("Could not find PostprocessBuildPlayer to determine build file extension.");
            }
            else
            {
                var GetExtensionForBuildTarget = PostprocessBuildPlayer.GetMethod("GetExtensionForBuildTarget", BindingFlags.Public | BindingFlags.Static);
                if (GetExtensionForBuildTarget == null)
                {
                    Debug.LogWarning("Could not find GetExtensionForBuildTarget to determine build file extension.");
                }
                else
                {
                    var args = new object[] { options.targetGroup, options.target, options.options };
                    var ext  = (string)GetExtensionForBuildTarget.Invoke(null, args);

                    var current = Path.GetExtension(options.locationPathName);
                    if (current.Length > 0)
                    {
                        current = current.Substring(1); // Remove leading dot
                    }

                    if (!string.IsNullOrEmpty(ext) &&
                        Path.GetExtension(options.locationPathName).EqualsIgnoringCase(current))
                    {
                        options.locationPathName += "." + ext;
                    }
                }
            }

            // Run the build
            OptionHelper.currentBuildOptions = options;

            var report = BuildPipeline.BuildPlayer(options);

            if (report.summary.result != BuildResult.Succeeded)
            {
                OnBuildError(report);
            }
            else
            {
                Debug.Log(string.Format("Trimmer: Built {0} to '{1}'", options.target, options.locationPathName));
                buildProfile.SetLastBuildPath(options.target, options.locationPathName);
            }

            currentProfile = null;
            OptionHelper.currentBuildOptions = default;
            return(report);
        }
Beispiel #12
0
        public static void Build(IBuildsCompleteListener onComplete = null)
        {
            string commandLineBuildPath = null;
            string profileName          = null;
            var    buildActiveTarget    = false;

            if (Application.isBatchMode)
            {
                string[] args = Environment.GetCommandLineArgs();
                for (int i = 0; i < args.Length; i++)
                {
                    if (args[i].EqualsIgnoringCase("-profileName"))
                    {
                        if (i + 1 == args.Length || args[i + 1].StartsWith("-"))
                        {
                            throw new Exception("-profileName needs to be followed by a profile name.");
                        }
                        profileName = args[++i];
                    }
                    else if (args[i].EqualsIgnoringCase("-output"))
                    {
                        if (i + 1 == args.Length || args[i + 1].StartsWith("-"))
                        {
                            throw new Exception("-output needs to be followed by a path.");
                        }
                        commandLineBuildPath = args[++i];
                    }
                    else if (args[i].EqualsIgnoringCase("-buildTarget"))
                    {
                        // Unity will validate the value of the -buildTarget option
                        buildActiveTarget = true;
                    }
                }
            }

            BuildProfile profile = null;

            if (Application.isBatchMode && profileName != null)
            {
                profile = BuildProfile.Find(profileName);
                if (profile == null)
                {
                    var err = "Build profile named '" + profileName + "' cloud not be found.";
                    if (onComplete != null)
                    {
                        onComplete.OnComplete(false, new[] { ProfileBuildResult.Error(null, err) });
                    }
                    else
                    {
                        Debug.LogError(err);
                    }
                    return;
                }

                Debug.Log("Building " + profile.name + ", selected from command line.");
            }

            if (profile == null)
            {
                if (EditorProfile.Instance.ActiveProfile == null)
                {
                    var err = "No profile specified and not active profile set: Nothing to build";
                    if (onComplete != null)
                    {
                        onComplete.OnComplete(false, new[] { ProfileBuildResult.Error(null, err) });
                    }
                    else
                    {
                        Debug.LogError(err);
                    }
                    return;
                }
                profile = EditorProfile.Instance.ActiveProfile;
                Debug.Log("Building active profile.");
            }

            // Throw if command line build failed to cause non-zero exit code
            if (Application.isBatchMode && onComplete == null)
            {
                onComplete = ScriptableObject.CreateInstance <CommandLineBuildsCompleteListener>();
            }

            BuildRunner.Job[] jobs;
            if (buildActiveTarget)
            {
                jobs = new[] {
                    new BuildRunner.Job(profile, EditorUserBuildSettings.activeBuildTarget, commandLineBuildPath)
                };
            }
            else
            {
                var targets = profile.BuildTargets.ToArray();
                jobs = new BuildRunner.Job[targets.Length];
                for (int i = 0; i < targets.Length; i++)
                {
                    jobs[i] = new BuildRunner.Job()
                    {
                        profile    = profile,
                        target     = targets[i],
                        outputPath = commandLineBuildPath,
                    };
                }
            }

            var runner = ScriptableObject.CreateInstance <BuildRunner>();

            runner.Run(jobs, onComplete, TrimmerPrefs.RestoreActiveBuildTarget && !Application.isBatchMode);
        }
Beispiel #13
0
        /// <summary>
        /// Entry point for Unity Cloud builds.
        /// </summary>
        /// <remarks>
        /// If you don't configure anything, Unity Cloud Build will build without a
        /// profile, all Options will use their default value and will be removed.
        ///
        /// Add the name of the Build Profile you want to build with to the target name
        /// in Unity Cloud Build, enclosed in double underscores, e.g. `__Profile Name__`.
        /// Note that since the target name can contain only alphanumeric characters,
        /// spaces, dashes and underscores, those characters cannot appear in the profile
        /// name either.
        ///
        /// Also note that the ability for Options to set build options is limited,
        /// currently only setting a custom  scene list is supported.
        /// </remarks>
        public static void UnityCloudBuild(BuildManifestObject manifest)
        {
            BuildType = TrimmerBuildType.CloudBuild;

            Debug.Log("UnityCloudBuild: Parsing profile name...");

            // Get profile name from could build target name
            string targetName;

            if (!manifest.TryGetValue("cloudBuildTargetName", out targetName))
            {
                Debug.LogError("Could not get target name from cloud build manifest.");
            }
            else
            {
                var match = Regex.Match(targetName, @"__([\w\-. ]+)__");
                if (match.Success)
                {
                    targetName = match.Groups[1].Value;
                    Debug.Log("Parsed build profile name from target name: " + targetName);
                }
            }

            Debug.Log("UnityCloudBuild: Looking for profile...");

            BuildProfile buildProfile = null;

            if (!string.IsNullOrEmpty(targetName))
            {
                buildProfile = BuildProfile.Find(targetName);
                if (buildProfile == null)
                {
                    Debug.LogError("Build Profile named '" + targetName + "' could not be found.");
                    return;
                }
            }

            if (buildProfile == null)
            {
                Debug.LogWarning("No Build Profile selected. Add the Build Profile enclosed in double underscores (__) to the target name.");
                return;
            }

            Debug.Log("UnityCloudBuild: Running PrepareBuild callbacks...");

            // Prepare build
            var options = GetDefaultOptions(EditorUserBuildSettings.activeBuildTarget);

            currentProfile = buildProfile;

            // Run options' PrepareBuild
            foreach (var option in GetCurrentEditProfile().OrderBy(o => o.PostprocessOrder))
            {
                if ((option.Capabilities & OptionCapabilities.ConfiguresBuild) == 0)
                {
                    continue;
                }
                var inclusion = buildProfile == null ? OptionInclusion.Remove : buildProfile.GetInclusionOf(option, options.target);
                options = option.PrepareBuild(options, inclusion);
            }

            // Cloud Build doesn't allow changing BuildPlayerOptions.extraScriptingDefines,
            // so we have to apply scripting define symbols to player settings
            ApplyScriptingDefineSymbolsToPlayerSettings(buildProfile, options.target);

            Debug.Log("UnityCloudBuild: Apply scenes...");

            // Apply scenes
            if (options.scenes != null && options.scenes.Length > 0)
            {
                var scenes = new EditorBuildSettingsScene[options.scenes.Length];
                for (int i = 0; i < scenes.Length; i++)
                {
                    scenes[i] = new EditorBuildSettingsScene(
                        options.scenes[i],
                        true
                        );
                }
                EditorBuildSettings.scenes = scenes;
            }

            OptionHelper.currentBuildOptions = options;
            Debug.Log("UnityCloudBuild: Done!");
        }
Beispiel #14
0
 public BuildPath(BuildProfile profile, BuildTarget target, string path)
 {
     this.profile = profile;
     this.target  = target;
     this.path    = path;
 }