Example #1
0
        protected async Task Upload(BuildPath zipPath, TaskToken task)
        {
            var archive = zipPath.path;

            if (!File.Exists(archive))
            {
                throw new System.Exception("UploadDistro: Archive file does not exist: " + archive);
            }

            // Append a / to the url if necessary, otherwise curl treats the last part as a file name
            var url = uploadUrl;

            if (url[url.Length - 1] != '/')
            {
                url += "/";
            }

            string input = null;

            if (!string.IsNullOrEmpty(login.User))
            {
                input = string.Format("-u \"{0}:{1}\"", login.User, login.GetPassword(keychainService));
            }

            var arguments = string.Format(
                "-T '{0}' {1} --ssl -v '{2}'",
                archive, input != null ? "-K -" : "", url
                );

            task.Report(0, $"Uploading {Path.GetFileName(archive)} to {uploadUrl}");
            await Execute(new ExecutionArgs(curlPath, arguments) { input = input }, task);
        }
Example #2
0
        /// <summary>
        /// Set default values taken from the assigned group.
        /// </summary>
        /// <param name="group">The group this schema has been added to.</param>
        protected override void OnSetGroup(AddressableAssetGroup group)
        {
            //this can happen during the load of the addressables asset
            if (group.Settings != null)
            {
                if (BuildPath == null || string.IsNullOrEmpty(BuildPath.GetValue(group.Settings)))
                {
                    m_BuildPath = new ProfileValueReference();
                    BuildPath.SetVariableByName(group.Settings, AddressableAssetSettings.kLocalBuildPath);
                }

                if (LoadPath == null || string.IsNullOrEmpty(LoadPath.GetValue(group.Settings)))
                {
                    m_LoadPath = new ProfileValueReference();
                    LoadPath.SetVariableByName(group.Settings, AddressableAssetSettings.kLocalLoadPath);
                }
            }

            if (m_AssetBundleProviderType.Value == null)
            {
                m_AssetBundleProviderType.Value = typeof(AssetBundleProvider);
            }
            if (m_BundledAssetProviderType.Value == null)
            {
                m_BundledAssetProviderType.Value = typeof(BundledAssetProvider);
            }
        }
Example #3
0
 string ReplaceVariablesIndividual(string input, BuildPath buildPath)
 {
     input = input.Replace("{target}", "'" + buildPath.target.ToString() + "'");
     input = input.Replace("{path}", "'" + buildPath.path + "'");
     input = input.Replace("{project}", "'" + Application.dataPath + "'");
     return(input);
 }
Example #4
0
        /// <summary>
        /// Get the paths to all existing builds for all build target in all linked Build Profiles.
        /// </summary>
        public virtual IEnumerable <BuildPath> GetBuildPaths()
        {
            var paths = new Dictionary <BuildTarget, BuildPath>();

            foreach (var profile in builds)
            {
                if (profile == null)
                {
                    continue;
                }
                foreach (var target in profile.BuildTargets)
                {
                    var path = profile.GetLastBuildPath(target);
                    if (string.IsNullOrEmpty(path) || (!File.Exists(path) && !Directory.Exists(path)))
                    {
                        paths[target] = new BuildPath(profile, target, null);
                    }
                    else
                    {
                        paths[target] = new BuildPath(profile, target, path);
                    }
                }
            }
            return(paths.Values);
        }
Example #5
0
        public void TestAmountCity()
        {
            BuildPath bp       = new BuildPath(lines);
            int       expected = 4;

            Assert.AreEqual(expected, bp.Cities.Count);
        }
Example #6
0
        public void TestAmountDirection()
        {
            BuildPath bp       = new BuildPath(lines);
            int       expected = 3;

            Assert.AreEqual(expected, bp.Directions.Count);
        }
Example #7
0
        public void TestMainMethod()
        {
            BuildPath bp       = new BuildPath(lines);
            string    expected = "Брест → Москва, Москва → Иркутск, Иркутск → Владивосток";

            Assert.AreEqual(expected, bp.result);
        }
Example #8
0
 /// <summary>
 /// Notarize a macOS build.
 /// </summary>
 /// <remarks>
 /// This method will silently ignore non-macOS builds.
 /// </remarks>
 /// <param name="buildPath">Build path</param>
 public async Task NotarizeIfMac(BuildPath buildPath, TaskToken task)
 {
     if (buildPath.target == BuildTarget.StandaloneOSX)
     {
         var child = task.StartChild("Notarize macOS Build");
         try {
             await Notarize(buildPath, child);
         } finally {
             child.Remove();
         }
     }
 }
Example #9
0
    public static void RemoveNoNamedBundle(string path)
    {
        if (string.IsNullOrEmpty(path))
        {
            return;
        }
        var bundleName = path + "/" + BuildPath.GetLastName(path);

        if (!File.Exists(bundleName))
        {
            return;
        }
        var bundle = AssetBundle.LoadFromFile(bundleName);

        if (bundle == null)
        {
            return;
        }
        var mainFest = bundle.LoadAsset <AssetBundleManifest>("AssetBundleManifest");

        if (mainFest == null)
        {
            return;
        }
        var oldBundles = mainFest.GetAllAssetBundles();
        var newBundles = new HashSet <string>(AssetDatabase.GetAllAssetBundleNames());

        foreach (var name in oldBundles)
        {
            if (!newBundles.Contains(name))
            {
                var fullName = path + "/" + name;
                if (File.Exists(fullName))
                {
                    File.Delete(fullName);
                }
                fullName = path + "/" + name + ".manifest";
                if (File.Exists(fullName))
                {
                    File.Delete(fullName);
                }
                fullName = path + "/" + name + ".meta";
                if (File.Exists(fullName))
                {
                    File.Delete(fullName);
                }
            }
        }
        bundle.Unload(true);
        AssetDatabase.Refresh();
        DeleteEmptyFolder(path);
        AssetDatabase.Refresh();
    }
Example #10
0
        IEnumerator Distribute(BuildPath buildPath)
        {
            Debug.Log("ItchDistro: Pushing " + buildPath.target);

            var path = OptionHelper.GetBuildBasePath(buildPath.path);

            var channel = ChannelNames[buildPath.target];

            if (!string.IsNullOrEmpty(channelSuffix))
            {
                channel += "-" + channelSuffix;
            }

            var version = Application.version;

            var buildInfo = BuildInfo.FromPath(path);

            if (buildInfo != null)
            {
                if (!buildInfo.version.IsDefined)
                {
                    Debug.LogWarning("ItchDistro: build.json exists but contains no version.");
                }
                else
                {
                    version = buildInfo.version.MajorMinorPatchBuild;
                }
            }

            var args = string.Format(
                "push '{0}' '{1}:{2}' --userversion '{3}' --ignore='*.DS_Store' --ignore='build.json'",
                path, project, channel, Application.version
                );

            yield return(Execute(butlerPath, args));

            var exitcode = GetSubroutineResult <int>();

            yield return(exitcode == 0);
        }
Example #11
0
        protected IEnumerator Upload(BuildPath zipPath)
        {
            var archive = zipPath.path;

            if (!File.Exists(archive))
            {
                Debug.LogError("UploadDistro: Archive file does not exist: " + archive);
                yield return(false); yield break;
            }

            // Append a / to the url if necessary, otherwise curl treats the last part as a file name
            var url = uploadUrl;

            if (url[url.Length - 1] != '/')
            {
                url += "/";
            }

            string input = null;

            if (!string.IsNullOrEmpty(login.User))
            {
                input = string.Format("-u \"{0}:{1}\"", login.User, login.GetPassword(keychainService));
            }

            var arguments = string.Format(
                "-T '{0}' {1} --ssl -v '{2}'",
                archive, input != null ? "-K -" : "", url
                );

            Debug.Log("UploadDistro: Uploading " + Path.GetFileName(archive) + " to " + uploadUrl);
            yield return(Execute(curlPath, arguments, input));

            var exitcode = GetSubroutineResult <int>();

            yield return(exitcode == 0);
        }
Example #12
0
        async Task Distribute(BuildPath buildPath, TaskToken task)
        {
            task.Report(0, description: $"Pushing {buildPath.target}");

            var path = OptionHelper.GetBuildBasePath(buildPath.path);

            var channel = ChannelNames[buildPath.target];

            if (!string.IsNullOrEmpty(channelSuffix))
            {
                channel += "-" + channelSuffix;
            }

            var version = Application.version;

            var buildInfo = BuildInfo.FromPath(path);

            if (buildInfo != null)
            {
                if (!buildInfo.version.IsDefined)
                {
                    Debug.LogWarning("ItchDistro: build.json exists but contains no version.");
                }
                else
                {
                    version = buildInfo.version.MajorMinorPatchBuild;
                }
            }

            var args = string.Format(
                "push '{0}' '{1}:{2}' --userversion '{3}' --ignore='*.DS_Store' --ignore='build.json'",
                path, project, channel, Application.version
                );

            await Execute(new ExecutionArgs(butlerPath, args), task);
        }
Example #13
0
        protected IEnumerator Zip(BuildPath buildPath)
        {
            var target = buildPath.target;
            var path   = buildPath.path;

            if (!File.Exists(path) && !Directory.Exists(path))
            {
                Debug.LogError("ZipDistro: Path to compress does not exist: " + path);
                yield return(null); yield break;
            }

            if (ZipIgnorePatterns == null)
            {
                ZipIgnorePatterns = new Regex[ZipIgnore.Length];
                for (int i = 0; i < ZipIgnore.Length; i++)
                {
                    var regex = Regex.Escape(ZipIgnore[i]).Replace(@"\*", ".*").Replace(@"\?", ".");
                    ZipIgnorePatterns[i] = new Regex(regex);
                }
            }

            var sevenZPath = Get7ZipPath();

            if (sevenZPath == null)
            {
                yield return(null); yield break;
            }

            // Path can point to executable file but there might be files
            // in the containing directory we need as well
            var basePath = OptionHelper.GetBuildBasePath(path);

            // Check the files in containing directory
            var files = new List <string>(Directory.GetFileSystemEntries(basePath));

            for (int i = files.Count - 1; i >= 0; i--)
            {
                var filename = Path.GetFileName(files[i]);
                foreach (var pattern in ZipIgnorePatterns)
                {
                    if (pattern.IsMatch(filename))
                    {
                        files.RemoveAt(i);
                        goto ContinueOuter;
                    }
                }
                ContinueOuter :;
            }

            if (files.Count == 0)
            {
                Debug.LogError("ZipDistro: Nothing to ZIP in directory: " + basePath);
                yield return(null); yield break;
            }

            // Determine output path first to make it consistent and use absolute path
            // since the script will be run in a different working directory
            var prettyName = GetPrettyName(target);

            if (prettyName == null)
            {
                prettyName = Path.GetFileNameWithoutExtension(basePath);
            }

            var versionSuffix = "";

            if (appendVersion)
            {
                var buildInfo = BuildInfo.FromPath(path);
                if (buildInfo != null)
                {
                    if (!buildInfo.version.IsDefined)
                    {
                        Debug.LogWarning("ZipDistro: build.json exists but contains no version");
                    }
                    else
                    {
                        versionSuffix = " " + buildInfo.version.MajorMinorPatch;
                    }
                }

                if (versionSuffix.Length == 0)
                {
                    versionSuffix = " " + Application.version;
                }
            }

            var extension = FileExtensions[(int)format];
            var zipName   = prettyName + versionSuffix + extension;

            zipName = zipName.Replace(" ", "_");

            var outputPath = Path.Combine(Path.GetDirectoryName(basePath), zipName);

            outputPath = Path.GetFullPath(outputPath);

            // Delete existing archive, otherwise 7za will update it
            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }

            // In case it only contains a single file, just zip that file
            var singleFile = false;

            if (files.Count == 1)
            {
                singleFile = true;
                basePath   = files[0];
            }

            // Run 7za command to create ZIP file
            var excludes = "";

            foreach (var pattern in ZipIgnore)
            {
                excludes += @" -xr\!'" + pattern + "'";
            }

            var inputName = Path.GetFileName(basePath);
            var args      = string.Format(
                "a '{0}' '{1}' -r -mx{2} {3}",
                outputPath, inputName, (int)compression, excludes
                );

            var startInfo = new System.Diagnostics.ProcessStartInfo();

            startInfo.FileName         = sevenZPath;
            startInfo.Arguments        = args;
            startInfo.WorkingDirectory = Path.GetDirectoryName(basePath);

            Debug.Log("ZipDistro: Archiving " + inputName);
            yield return(Execute(startInfo));

            var exitcode = GetSubroutineResult <int>();

            if (exitcode != 0)
            {
                yield return(null); yield break;
            }

            if (!singleFile && prettyName != inputName)
            {
                yield return(RenameRoot(outputPath, inputName, prettyName));

                var success = GetSubroutineResult <bool>();
                if (!success)
                {
                    yield return(null); yield break;
                }
            }

            Debug.Log("ZipDistro: Archived to: " + outputPath);
            yield return(new BuildPath(target, outputPath));
        }
Example #14
0
        /// <summary>
        /// Notarize a macOS build.
        /// </summary>
        /// <remarks>
        /// This method will throw if the given build is not a macOS build.
        /// </remarks>
        /// <param name="macBuildPath">Path to the app bundle</param>
        public async Task Notarize(BuildPath macBuildPath, TaskToken task)
        {
            if (macBuildPath.target != BuildTarget.StandaloneOSX)
            {
                throw new Exception($"NotarizationDistro: Notarization is only available for macOS builds (got {macBuildPath.target})");
            }

            var path = macBuildPath.path;

            // Check settings
            if (string.IsNullOrEmpty(appSignIdentity))
            {
                throw new Exception("NotarizationDistro: App sign identity not set.");
            }

            if (entitlements == null)
            {
                throw new Exception("NotarizationDistro: Entitlements file not set.");
            }

            // Check User
            if (string.IsNullOrEmpty(ascLogin.User))
            {
                throw new Exception("NotarizationDistro: No App Store Connect user set.");
            }

            if (ascLogin.GetPassword(keychainService) == null)
            {
                throw new Exception("NotarizationDistro: No App Store Connect password found in Keychain.");
            }

            task.Report(0, 6, "Checking if app is already notarized");

            // Try stapling in case the build has already been notarized
            if (await Staple(path, silentError: true, task))
            {
                Debug.Log("Build already notarized, nothing more to do...");
                return;
            }

            task.Report(1, description: "Signing app");

            // Sign plugins
            // codesign --deep --force does not resign nested plugins,
            // --force only applies to the main bundle. If we want to
            // resign nested plugins, we have to call codesign for each.
            // This is required for library validation with the hardened runtime.
            var plugins = Path.Combine(path, "Contents/Plugins");

            if (Directory.Exists(plugins))
            {
                await Sign(Directory.GetFiles(plugins, "*.dylib", SearchOption.TopDirectoryOnly), task);
                await Sign(Directory.GetFiles(plugins, "*.bundle", SearchOption.TopDirectoryOnly), task);
                await Sign(Directory.GetDirectories(plugins, "*.bundle", SearchOption.TopDirectoryOnly), task);
            }

            // Sign application
            var entitlementsPath = AssetDatabase.GetAssetPath(entitlements);

            await Sign(path, task, entitlementsPath);

            task.Report(2, description: "Zipping app");

            // Zip app
            var zipPath = path + ".zip";

            await Zip(path, zipPath, task);

            task.Report(3, description: "Uploading app");

            // Upload for notarization
            string requestUUID = null;

            try {
                requestUUID = await Upload(zipPath, task);

                if (requestUUID == null)
                {
                    throw new Exception("NotarizationDistro: Could not parse request UUID from upload output");
                }
            } finally {
                // Delete ZIP regardless of upload result
                File.Delete(zipPath);
            }

            task.Report(4, description: "Waiting for notarization result");

            // Wait for notarization to complete
            var status = await WaitForCompletion(requestUUID, task);

            if (status != "success")
            {
                throw new Exception($"NotarizationDistro: Got '{status}' notarization status");
            }

            task.Report(5, description: "Stapling ticket to app");

            // Staple
            await Staple(path, silentError : false, task);
        }
Example #15
0
        /// <summary>
        /// Notarize a macOS build.
        /// </summary>
        /// <param name="path">Path to the app bundle</param>
        /// <returns>The string path to the notarized macOS app bundle</returns>
        public IEnumerator Notarize(BuildPath macBuildPath)
        {
            if (macBuildPath.target != BuildTarget.StandaloneOSX) {
            Debug.LogError($"NotarizationDistro: Notarization is only available for macOS builds (got {macBuildPath.target})");
            yield return null; yield break;
            }

            var path = macBuildPath.path;

            // Check settings
            if (string.IsNullOrEmpty(appSignIdentity)) {
            Debug.LogError("NotarizationDistro: App sign identity not set.");
            yield return null; yield break;
            }

            if (entitlements == null) {
            Debug.LogError("NotarizationDistro: Entitlements file not set.");
            yield return null; yield break;
            }

            // Check User
            if (string.IsNullOrEmpty(ascLogin.User)) {
            Debug.LogError("NotarizationDistro: No App Store Connect user set.");
            yield return null; yield break;
            }

            if (ascLogin.GetPassword(keychainService) == null) {
            Debug.LogError("NotarizationDistro: No App Store Connect password found in Keychain.");
            yield return null; yield break;
            }

            Debug.Log("Checking if app is already notarized...");

            // Try stapling in case the build has already been notarized
            yield return Staple(path, false);
            if (GetSubroutineResult<bool>()) {
            Debug.Log("Build already notarized, nothing more to do...");
            yield return path; yield break;
            }

            Debug.Log("Singing app...");

            // Sign plugins
            // codesign --deep --force does not resign nested plugins,
            // --force only applies to the main bundle. If we want to
            // resign nested plugins, we have to call codesign for each.
            // This is required for library validation with the hardened runtime.
            var plugins = Path.Combine(path, "Contents/Plugins");
            if (Directory.Exists(plugins)) {
            yield return SignAll(Directory.GetFiles(plugins, "*.dylib", SearchOption.TopDirectoryOnly));
            if (!GetSubroutineResult<bool>()) {
                yield return false; yield break;
            }

            yield return SignAll(Directory.GetFiles(plugins, "*.bundle", SearchOption.TopDirectoryOnly));
            if (!GetSubroutineResult<bool>()) {
                yield return false; yield break;
            }

            yield return SignAll(Directory.GetDirectories(plugins, "*.bundle", SearchOption.TopDirectoryOnly));
            if (!GetSubroutineResult<bool>()) {
                yield return false; yield break;
            }
            }

            // Sign application
            var entitlementsPath = AssetDatabase.GetAssetPath(entitlements);
            yield return Sign(path, entitlementsPath);
            if (!GetSubroutineResult<bool>()) {
            yield return null; yield break;
            }

            Debug.Log("Signed! Zipping app...");

            // Zip app
            var zipPath = path + ".zip";
            yield return Zip(path, zipPath);
            if (!GetSubroutineResult<bool>()) {
            yield return null; yield break;
            }

            Debug.Log("Zipped! Uploading...");

            // Upload for notarization
            yield return Upload(zipPath);

            // Delete ZIP regardless of upload result
            File.Delete(zipPath);

            var requestUUID = GetSubroutineResult<string>();
            if (requestUUID == null) {
            yield return null; yield break;
            }

            Debug.Log("Uploaded! Waiting for result...");

            // Wait for notarization to complete
            yield return WaitForCompletion(requestUUID);
            var status = GetSubroutineResult<string>();
            if (status != "success") {
            yield return null; yield break;
            }

            Debug.Log("Done! Stapling...");

            // Staple
            yield return Staple(path, true);
            if (!GetSubroutineResult<bool>()) {
            yield return null; yield break;
            }

            Debug.Log("NotarizationDistro: Finished");
            yield return path;
        }