Exemplo n.º 1
0
        public List <IBuild> GetBuildsAtPath(string InProjectName, string InPath, int MaxRecursion = 3)
        {
            List <DirectoryInfo> AllDirs = new List <DirectoryInfo>();

            //AndroidBuildSource BuildSource = null;
            List <IBuild> Builds = new List <IBuild>();

            // c:\path\to\build
            DirectoryInfo PathDI = new DirectoryInfo(InPath);

            if (PathDI.Exists)
            {
                if (PathDI.Name.IndexOf("Android", StringComparison.OrdinalIgnoreCase) >= 0)
                {
                    AllDirs.Add(PathDI);
                }

                // find all directories that begin with Android
                DirectoryInfo[] AndroidDirs = PathDI.GetDirectories("Android*", SearchOption.TopDirectoryOnly);

                AllDirs.AddRange(AndroidDirs);

                List <DirectoryInfo> DirsToRecurse = AllDirs;

                // now get subdirs
                while (MaxRecursion-- > 0)
                {
                    List <DirectoryInfo> DiscoveredDirs = new List <DirectoryInfo>();

                    DirsToRecurse.ToList().ForEach((D) =>
                    {
                        DiscoveredDirs.AddRange(D.GetDirectories("*", SearchOption.TopDirectoryOnly));
                    });

                    AllDirs.AddRange(DiscoveredDirs);
                    DirsToRecurse = DiscoveredDirs;
                }

                string AndroidBuildFilter = Globals.Params.ParseValue("AndroidBuildFilter", "");
                foreach (DirectoryInfo Di in AllDirs)
                {
                    IEnumerable <AndroidBuild> FoundBuilds = AndroidBuild.CreateFromPath(InProjectName, Di.FullName);

                    if (FoundBuilds != null)
                    {
                        if (!string.IsNullOrEmpty(AndroidBuildFilter))
                        {
                            //IndexOf used because Contains must be case-sensitive
                            FoundBuilds = FoundBuilds.Where(B => B.SourceApkPath.IndexOf(AndroidBuildFilter, StringComparison.OrdinalIgnoreCase) >= 0);
                        }
                        Builds.AddRange(FoundBuilds);
                    }
                }
            }

            return(Builds);
        }
        public IAppInstall InstallApplication(UnrealAppConfig AppConfig)
        {
            // todo - pass this through
            AndroidBuild Build = AppConfig.Build as AndroidBuild;

            // Ensure APK exists
            if (Build == null)
            {
                throw new AutomationException("Invalid build for Android!");
            }

            // kill any currently running instance:
            KillRunningProcess(Build.AndroidPackageName);

            bool SkipDeploy = Globals.Params.ParseParam("SkipDeploy");

            if (SkipDeploy == false)
            {
                // Establish remote directory locations
                string         DeviceStorageQueryCommand = AndroidPlatform.GetStorageQueryCommand();
                IProcessResult StorageQueryResult        = RunAdbDeviceCommand(DeviceStorageQueryCommand);
                string         StorageLocation           = StorageQueryResult.Output.Trim(); // "/mnt/sdcard";

                // remote dir used to save things
                string RemoteDir = StorageLocation + "/UE4Game/" + AppConfig.ProjectName;

                // if not a bulk/dev build, remote dir will be under /{StorageLocation}/Android/data/{PackageName}
                if ((Build.Flags & (BuildFlags.Bulk | BuildFlags.CanReplaceExecutable)) == 0)
                {
                    RemoteDir = StorageLocation + "/Android/data/" + Build.AndroidPackageName + "/files/UE4Game/" + AppConfig.ProjectName;
                }

                string DependencyDir = RemoteDir + "/deps";

                // device artifact path, always clear between runs
                DeviceArtifactPath = string.Format("{0}/{1}/Saved", RemoteDir, AppConfig.ProjectName);
                RunAdbDeviceCommand(string.Format("shell rm -r {0}", DeviceArtifactPath));

                // path for OBB files
                string OBBRemoteDestination = string.Format("{0}/obb/{1}", StorageLocation, Build.AndroidPackageName);

                if (Globals.Params.ParseParam("cleandevice"))
                {
                    Log.Info("Cleaning previous builds due to presence of -cleandevice");

                    // we need to ununstall then install the apk - don't care if it fails, may have been deleted
                    Log.Info("Uninstalling {0}", Build.AndroidPackageName);
                    RunAdbDeviceCommand(string.Format("uninstall {0}", Build.AndroidPackageName));

                    Log.Info("Removing {0}", RemoteDir);
                    RunAdbDeviceCommand(string.Format("shell rm -r {0}", RemoteDir));

                    Log.Info("Removing {0}", OBBRemoteDestination);
                    RunAdbDeviceCommand(string.Format("shell rm -r {0}", OBBRemoteDestination));
                }

                // remote dir on the device, create it if it doesn't exist
                RunAdbDeviceCommand(string.Format("shell mkdir -p {0}/", RemoteDir));

                IProcessResult AdbResult;
                string         AdbCommand;

                // path to the APK to install.
                string ApkPath = Build.SourceApkPath;

                // check for a local newer executable
                if (Globals.Params.ParseParam("dev"))
                {
                    //string ApkFileName = Path.GetFileName(ApkPath);

                    string ApkFileName2 = UnrealHelpers.GetExecutableName(AppConfig.ProjectName, UnrealTargetPlatform.Android, AppConfig.Configuration, AppConfig.ProcessType, "apk");

                    string LocalAPK = Path.Combine(Environment.CurrentDirectory, AppConfig.ProjectName, "Binaries/Android", ApkFileName2);

                    bool LocalFileExists = File.Exists(LocalAPK);
                    bool LocalFileNewer  = LocalFileExists && File.GetLastWriteTime(LocalAPK) > File.GetLastWriteTime(ApkPath);

                    Log.Verbose("Checking for newer binary at {0}", LocalAPK);
                    Log.Verbose("LocalFile exists: {0}. Newer: {1}", LocalFileExists, LocalFileNewer);

                    if (LocalFileExists && LocalFileNewer)
                    {
                        ApkPath = LocalAPK;
                    }
                }

                // first install the APK
                CopyFileToDevice(Build.AndroidPackageName, ApkPath, "");

                // obb files need to be named based on APK version (grrr), so find that out. This should return something like
                // versionCode=2 minSdk=21 targetSdk=21
                string PackageInfo = RunAdbDeviceCommand(string.Format("shell dumpsys package {0} | grep versionCode", Build.AndroidPackageName)).Output;
                var    Match       = Regex.Match(PackageInfo, @"versionCode=([\d\.]+)\s");
                if (Match.Success == false)
                {
                    throw new AutomationException("Failed to find version info for APK!");
                }
                string PackageVersion = Match.Groups[1].ToString();

                // Convert the files from the source to final destination names
                Dictionary <string, string> FilesToInstall = new Dictionary <string, string>();

                Console.WriteLine("trying to copy files over.");
                if (AppConfig.FilesToCopy != null)
                {
                    if (LocalDirectoryMappings.Count == 0)
                    {
                        Console.WriteLine("Populating Directory");
                        PopulateDirectoryMappings(DeviceArtifactPath);
                    }
                    Console.WriteLine("trying to copy files over.");
                    foreach (UnrealFileToCopy FileToCopy in AppConfig.FilesToCopy)
                    {
                        string PathToCopyTo = Path.Combine(LocalDirectoryMappings[FileToCopy.TargetBaseDirectory], FileToCopy.TargetRelativeLocation);
                        if (File.Exists(FileToCopy.SourceFileLocation))
                        {
                            FileInfo SrcInfo = new FileInfo(FileToCopy.SourceFileLocation);
                            SrcInfo.IsReadOnly = false;
                            FilesToInstall.Add(FileToCopy.SourceFileLocation, PathToCopyTo.Replace("\\", "/"));
                            Console.WriteLine("Copying {0} to {1}", FileToCopy.SourceFileLocation, PathToCopyTo);
                        }

                        else
                        {
                            Log.Warning("File to copy {0} not found", FileToCopy);
                        }
                    }
                }

                Build.FilesToInstall.Keys.ToList().ForEach(K =>
                {
                    string SrcPath  = K;
                    string DestPath = Build.FilesToInstall[K];

                    string DestFile = Path.GetFileName(DestPath);

                    // If we installed a new APK we need to change the package version
                    Match OBBMatch = Regex.Match(DestFile, @"main\.(\d+)\.com.*\.obb");
                    if (OBBMatch.Success)
                    {
                        string NewFileName = DestFile.Replace(OBBMatch.Groups[1].ToString(), PackageVersion);
                        DestPath           = DestPath.Replace(DestFile, NewFileName);
                    }

                    DestPath = Regex.Replace(DestPath, "%STORAGE%", StorageLocation, RegexOptions.IgnoreCase);

                    FilesToInstall.Add(SrcPath, DestPath);
                });



                // get a list of files in the destination OBB directory
                AdbResult = RunAdbDeviceCommand(string.Format("shell ls {0}", OBBRemoteDestination));

                // if != 0 then no folder exists
                if (AdbResult.ExitCode == 0)
                {
                    IEnumerable <string> CurrentRemoteFileList = AdbResult.Output.Replace("\r\n", "\n").Split('\n');
                    IEnumerable <string> NewRemoteFileList     = FilesToInstall.Values.Select(F => Path.GetFileName(F));

                    // delete any files that should not be there
                    foreach (string FileName in CurrentRemoteFileList)
                    {
                        if (FileName.StartsWith(".") || FileName.Length == 0)
                        {
                            continue;
                        }

                        if (NewRemoteFileList.Contains(FileName) == false)
                        {
                            RunAdbDeviceCommand(string.Format("shell rm {0}/{1}", OBBRemoteDestination, FileName));
                        }
                    }
                }

                foreach (var KV in FilesToInstall)
                {
                    string LocalFile  = KV.Key;
                    string RemoteFile = KV.Value;

                    CopyFileToDevice(Build.AndroidPackageName, LocalFile, RemoteFile);
                }

                // create a tempfile, insert the command line, and push it over
                string TmpFile = Path.GetTempFileName();

                CommandLineFilePath = string.Format("{0}/UE4CommandLine.txt", RemoteDir);

                // I've seen a weird thing where adb push truncates by a byte, so add some padding...
                File.WriteAllText(TmpFile, AppConfig.CommandLine + "    ");
                AdbCommand = string.Format("push {0} {1}", TmpFile, CommandLineFilePath);
                RunAdbDeviceCommand(AdbCommand);


                File.Delete(TmpFile);
            }
            else
            {
                Log.Info("Skipping install of {0} (-skipdeploy)", Build.AndroidPackageName);
            }

            AndroidAppInstall AppInstall = new AndroidAppInstall(this, AppConfig.ProjectName, Build.AndroidPackageName, AppConfig.CommandLine);

            return(AppInstall);
        }
        public static IEnumerable <AndroidBuild> CreateFromPath(string InProjectName, string InPath)
        {
            string BuildPath = InPath;

            List <AndroidBuild> DiscoveredBuilds = new List <AndroidBuild>();

            DirectoryInfo Di = new DirectoryInfo(BuildPath);


            // find all install batchfiles
            FileInfo[] InstallFiles = Di.GetFiles("Install_*");

            foreach (FileInfo Fi in InstallFiles)
            {
                // todo
                if (Fi.FullName.Contains("armv7"))
                {
                    continue;
                }

                // Unreal naming. In test & shipping the platform name and config will be includedn
                string RegEx = "Install_(.+?)(client|game|server)-(Android)?-?(test|shipping)?-?(.+).bat";

                Match Info = Regex.Match(Fi.Name, RegEx, RegexOptions.IgnoreCase);

                bool TestInstall = Fi.Name.EndsWith("_TEST.bat", StringComparison.OrdinalIgnoreCase);

                // filter out non-matching or test installation batch files
                // test installation scripts are intended to be manually invoked
                if (Info.Success == false || TestInstall)
                {
                    if (TestInstall)
                    {
                        Log.Verbose("Ignoring test installation batch file {0}", Fi.Name);
                    }
                    continue;
                }

                string TargetName = Info.Groups[1].ToString();
                string TypeName   = Info.Groups[2].ToString();
                string ConfigName = Info.Groups[4].ToString();

                if (string.IsNullOrEmpty(ConfigName))
                {
                    ConfigName = "Development";
                }


                Log.Verbose("Pulling install data from {0}", Fi.FullName);

                string AbsPath = Fi.Directory.FullName;

                // read contents and replace linefeeds (regex doesn't stop on them :((
                string BatContents = File.ReadAllText(Fi.FullName).Replace(Environment.NewLine, "\n");

                // Replace .bat with .apk and strip up to and including the first _, that is then our APK name
                string SourceApkPath = Regex.Replace(Fi.Name, ".bat", ".apk", RegexOptions.IgnoreCase);
                SourceApkPath = SourceApkPath.Substring(SourceApkPath.IndexOf("_") + 1);
                SourceApkPath = Path.Combine(AbsPath, SourceApkPath);

                // save com.companyname.product
                string AndroidPackageName = Regex.Match(BatContents, @"uninstall\s+(com\..+)").Groups[1].ToString();

                // pull all OBBs (probably just one..)
                var OBBMatches = Regex.Matches(BatContents, @"push\s+(.+?)\s+(.+)");

                // save them as a dict of full paths as keys and dest paths as values
                Dictionary <string, string> FilesToInstall = OBBMatches.Cast <Match>().ToDictionary(M => Path.Combine(AbsPath, M.Groups[1].ToString()), M => M.Groups[2].ToString());

                if (string.IsNullOrEmpty(SourceApkPath))
                {
                    Log.Warning("No APK found for build at {0}", Fi.FullName);
                    continue;
                }

                if (string.IsNullOrEmpty(AndroidPackageName))
                {
                    Log.Warning("No product name found for build at {0}", Fi.FullName);
                    continue;
                }

                UnrealTargetConfiguration UnrealConfig;
                if (Enum.TryParse(ConfigName, true, out UnrealConfig) == false)
                {
                    Log.Warning("Could not determine Unreal Config type from '{0}'", ConfigName);
                    continue;
                }

                // Android builds are always packaged, and we can always replace the command line
                BuildFlags Flags = BuildFlags.Packaged | BuildFlags.CanReplaceCommandLine;

                // if there's data then the pak files are in an obb and we can sub in a new exe
                if (FilesToInstall.Count() > 0)
                {
                    Flags |= BuildFlags.CanReplaceExecutable;
                }
                if (AbsPath.Contains("Bulk"))
                {
                    Flags |= BuildFlags.Bulk;
                }

                AndroidBuild NewBuild = new AndroidBuild(UnrealConfig, AndroidPackageName, SourceApkPath, FilesToInstall, Flags);

                DiscoveredBuilds.Add(NewBuild);

                Log.Verbose("Found {0} {1} build at {2}", UnrealConfig, ((Flags & BuildFlags.Bulk) == BuildFlags.Bulk) ? "(bulk)" : "(not bulk)", AbsPath);
            }

            return(DiscoveredBuilds);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Given a platform, a build config, and true/false for client, returns the path to the binary for that config. E.g.
        /// Win64, Shipping, false = Binaries\Win64\FooServer-Win64-Shipping.exe
        /// </summary>
        /// <param name="TargetPlatform"></param>
        /// <param name="BuildConfig"></param>
        /// <param name="IsClient"></param>
        /// <returns></returns>
        virtual public string GetRelativeExecutablePath(UnrealTargetRole TargetType, UnrealTargetPlatform TargetPlatform, UnrealTargetConfiguration TargetConfiguration)
        {
            string ExePath;

            if (TargetType.UsesEditor())
            {
                ExePath = string.Format("Engine/Binaries/{0}/UE4Editor{1}", BuildHostPlatform.Current.Platform, Platform.GetExeExtension(TargetPlatform));
            }
            else
            {
                string BuildType = "";

                if (TargetType == UnrealTargetRole.Client)
                {
                    if (!UsesSharedBuildType)
                    {
                        BuildType = "Client";
                    }
                }
                else if (TargetType == UnrealTargetRole.Server)
                {
                    if (!UsesSharedBuildType)
                    {
                        BuildType = "Server";
                    }
                }

                bool IsRunningDev = Globals.Params.ParseParam("dev");

                // Turn FooGame into Foo
                string ExeBase = ProjectName.Replace("Game", "");

                if (TargetPlatform == UnrealTargetPlatform.Android)
                {
                    // use the archive results for android.
                    //var AndroidSource = new AndroidBuild(ProjectName, GetPlatformPath(TargetType, TargetPlatform), TargetConfiguration);

                    // We always (currently..) need to be able to replace the command line
                    BuildFlags Flags = BuildFlags.CanReplaceCommandLine;
                    if (IsRunningDev)
                    {
                        Flags |= BuildFlags.CanReplaceExecutable;
                    }
                    if (Globals.Params.ParseParam("bulk"))
                    {
                        Flags |= BuildFlags.Bulk;
                    }
                    else if (Globals.Params.ParseParam("notbulk"))
                    {
                        Flags |= BuildFlags.NotBulk;
                    }

                    var Build = GetMatchingBuilds(TargetType, TargetPlatform, TargetConfiguration, Flags).FirstOrDefault();

                    if (Build != null)
                    {
                        AndroidBuild AndroidBuild = Build as AndroidBuild;
                        ExePath = AndroidBuild.SourceApkPath;
                    }
                    else
                    {
                        throw new AutomationException("No suitable build for {0} found at {1}", TargetPlatform, string.Join(",", BuildPaths));
                    }

                    //ExePath = AndroidSource.SourceApkPath;
                }
                else
                {
                    string ExeFileName = string.Format("{0}{1}", ExeBase, BuildType);

                    if (TargetConfiguration != UnrealTargetConfiguration.Development)
                    {
                        ExeFileName += string.Format("-{0}-{1}", TargetPlatform.ToString(), TargetConfiguration.ToString());
                    }

                    ExeFileName += Platform.GetExeExtension(TargetPlatform);

                    string BasePath      = GetPlatformPath(TargetType, TargetPlatform);
                    string ProjectBinary = string.Format("{0}\\Binaries\\{1}\\{2}", ProjectName, TargetPlatform.ToString(), ExeFileName);
                    string StubBinary    = Path.Combine(BasePath, ExeFileName);
                    string DevBinary     = Path.Combine(Environment.CurrentDirectory, ProjectBinary);

                    string NonCodeProjectName   = "UE4Game" + Platform.GetExeExtension(TargetPlatform);
                    string NonCodeProjectBinary = Path.Combine(BasePath, "Engine", "Binaries", TargetPlatform.ToString());
                    NonCodeProjectBinary = Path.Combine(NonCodeProjectBinary, NonCodeProjectName);

                    // check the project binaries folder
                    if (File.Exists(Path.Combine(BasePath, ProjectBinary)))
                    {
                        ExePath = ProjectBinary;
                    }
                    else if (File.Exists(StubBinary))
                    {
                        ExePath = Path.Combine(BasePath, ExeFileName);
                    }
                    else if (IsRunningDev && File.Exists(DevBinary))
                    {
                        ExePath = DevBinary;
                    }
                    else if (File.Exists(NonCodeProjectBinary))
                    {
                        ExePath = NonCodeProjectBinary;
                    }
                    else
                    {
                        List <string> CheckedFiles = new List <String>()
                        {
                            Path.Combine(BasePath, ProjectBinary), StubBinary, NonCodeProjectBinary
                        };
                        if (IsRunningDev)
                        {
                            CheckedFiles.Add(DevBinary);
                        }

                        throw new AutomationException("Executable not found, upstream compile job may have failed.  Could not find executable {0} within {1}, binaries checked: {2}", ExeFileName, BasePath, String.Join(" - ", CheckedFiles));
                    }
                }
            }

            return(Utils.SystemHelpers.CorrectDirectorySeparators(ExePath));
        }
Exemplo n.º 5
0
        public static IEnumerable <AndroidBuild> CreateFromPath(string InProjectName, string InPath)
        {
            string BuildPath = InPath;

            List <AndroidBuild> DiscoveredBuilds = new List <AndroidBuild>();

            DirectoryInfo Di = new DirectoryInfo(BuildPath);


            // find all install batchfiles
            FileInfo[] InstallFiles = Di.GetFiles("Install_*");

            foreach (FileInfo Fi in InstallFiles)
            {
                bool PackageIs32Bit = Fi.FullName.Contains("armv7");

                UnrealTargetConfiguration UnrealConfig = UnrealHelpers.GetConfigurationFromExecutableName(InProjectName, Fi.FullName);
                UnrealTargetRole          UnrealRole   = UnrealHelpers.GetRoleFromExecutableName(InProjectName, Fi.FullName);

                if (UnrealConfig == UnrealTargetConfiguration.Unknown)
                {
                    Log.Info("Skipping unrecognized build {0}", Fi.FullName);
                    continue;
                }

                bool TestInstall  = Fi.Name.EndsWith("_TEST.bat", StringComparison.OrdinalIgnoreCase);
                bool PatchInstall = Fi.Name.EndsWith("_Patch.bat", StringComparison.OrdinalIgnoreCase);

                // filter out non-matching or test installation batch files
                // test installation scripts are intended to be manually invoked
                if (TestInstall || PatchInstall)
                {
                    if (TestInstall || PatchInstall)
                    {
                        Log.Verbose("Ignoring {0} installation batch file {1}", TestInstall ? "test" : "patch", Fi.Name);
                    }

                    continue;
                }

                Log.Verbose("Pulling install data from {0}", Fi.FullName);

                string AbsPath = Fi.Directory.FullName;

                // read contents and replace linefeeds (regex doesn't stop on them :((
                string BatContents = File.ReadAllText(Fi.FullName).Replace(Environment.NewLine, "\n");

                // Replace .bat with .apk and strip up to and including the first _, that is then our APK name
                var SourceApkMatch = Regex.Match(BatContents, @" install\s+(.+\.apk)");
                if (SourceApkMatch.Groups.Count <= 0)
                {
                    Log.Warning("Could not parse install command from {0}", Fi.FullName);
                    continue;
                }
                string SourceApkPath = Path.Combine(AbsPath, SourceApkMatch.Groups[1].ToString());

                // save com.companyname.product
                string AndroidPackageName = Regex.Match(BatContents, @"uninstall\s+(com\..+)").Groups[1].ToString();

                // pull all OBBs (probably just one..)
                var OBBMatches = Regex.Matches(BatContents, @"push\s+(.+?)\s+(.+)");

                // save them as a dict of full paths as keys and dest paths as values
                Dictionary <string, string> FilesToInstall = OBBMatches.Cast <Match>().ToDictionary(M => Path.Combine(AbsPath, M.Groups[1].ToString()), M => M.Groups[2].ToString());

                if (string.IsNullOrEmpty(SourceApkPath))
                {
                    Log.Warning("No APK found for build at {0}", Fi.FullName);
                    continue;
                }

                if (!File.Exists(SourceApkPath))
                {
                    Log.Warning("Resolved APK name but it doesn't exist {0}", SourceApkPath);
                    continue;
                }

                if (string.IsNullOrEmpty(AndroidPackageName))
                {
                    Log.Warning("No product name found for build at {0}", Fi.FullName);
                    continue;
                }

                // Android builds are always packaged, and we can always replace the command line
                BuildFlags Flags = BuildFlags.Packaged | BuildFlags.CanReplaceCommandLine;

                // if there's data then the pak files are in an obb and we can sub in a new exe
                if (FilesToInstall.Count() > 0)
                {
                    Flags |= BuildFlags.CanReplaceExecutable;
                }
                if (AbsPath.Contains("Bulk"))
                {
                    Flags |= BuildFlags.Bulk;
                }
                else
                {
                    Flags |= BuildFlags.NotBulk;
                }

                AndroidBuild NewBuild = new AndroidBuild(UnrealConfig, AndroidPackageName, SourceApkPath, FilesToInstall, Flags, PackageIs32Bit);

                DiscoveredBuilds.Add(NewBuild);

                Log.Verbose("Found {0} {1} build at {2}", UnrealConfig, ((Flags & BuildFlags.Bulk) == BuildFlags.Bulk) ? "(bulk)" : "(not bulk)", AbsPath);
            }

            // If we have both 32 and 64-bit builds, prefer 64-bit
            if (DiscoveredBuilds.Where(B => B.Is32Bit == false).Any())
            {
                DiscoveredBuilds = DiscoveredBuilds.Where(B => !B.Is32Bit).ToList();
            }

            return(DiscoveredBuilds);
        }