Example #1
0
        protected override string GenerateCommandLineCommands()
        {
            // For creating Resource.Designer.cs:
            //   Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt
            //     "package"
            //     "-M" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\AndroidManifest.xml"
            //     "-J" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way"
            //     "-F" "C:\Users\Jonathan\AppData\Local\Temp\ryob4gaw.way\resources.apk"
            //     "-S" "c:\users\jonathan\documents\visual studio 2010\Projects\MonoAndroidApplication4\MonoAndroidApplication4\obj\Debug\res"
            //     "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar"
            //     "--max-res-version" "10"

            // For packaging:
            //   Running command: C:\Program Files (x86)\Android\android-sdk-windows\platform-tools\aapt
            //     "package"
            //     "-f"
            //     "-m"
            //     "-M" "AndroidManifest.xml"
            //     "-J" "src"
            //     "--custom-package" "androidmsbuildtest.androidmsbuildtest"
            //     "-F" "bin\packaged_resources"
            //     "-S" "C:\Users\Jonathan\Documents\Visual Studio 2010\Projects\AndroidMSBuildTest\AndroidMSBuildTest\obj\Debug\res"
            //     "-I" "C:\Program Files (x86)\Android\android-sdk-windows\platforms\android-8\android.jar"
            //     "--extra-packages" "com.facebook.android:my.another.library"

            var cmd = new CommandLineBuilder ();

            cmd.AppendSwitch ("package");

            if (MonoAndroidHelper.LogInternalExceptions)
                cmd.AppendSwitch ("-v");
            if (NonConstantId)
                cmd.AppendSwitch ("--non-constant-id");
            cmd.AppendSwitch ("-f");
            cmd.AppendSwitch ("-m");
            string manifestFile;
            string manifestDir = Path.Combine (Path.GetDirectoryName (ManifestFile), currentAbi != null ? currentAbi : "manifest");
            Directory.CreateDirectory (manifestDir);
            manifestFile = Path.Combine (manifestDir, Path.GetFileName (ManifestFile));
            ManifestDocument manifest = new ManifestDocument (ManifestFile, this.Log);
            if (currentAbi != null)
                manifest.SetAbi (currentAbi);
            manifest.ApplicationName = ApplicationName;
            manifest.Save (manifestFile);
            currentResourceOutputFile = currentAbi != null ? string.Format ("{0}-{1}", ResourceOutputFile, currentAbi) : ResourceOutputFile;

            cmd.AppendSwitchIfNotNull ("-M ", manifestFile);
            Directory.CreateDirectory (JavaDesignerOutputDirectory);
            cmd.AppendSwitchIfNotNull ("-J ", JavaDesignerOutputDirectory);

            if (PackageName != null)
                cmd.AppendSwitchIfNotNull ("--custom-package ", PackageName.ToLowerInvariant ());

            if (!string.IsNullOrEmpty (currentResourceOutputFile))
                cmd.AppendSwitchIfNotNull ("-F ", currentResourceOutputFile + ".bk");
            // The order of -S arguments is *important*, always make sure this one comes FIRST
            cmd.AppendSwitchIfNotNull ("-S ", ResourceDirectory.TrimEnd ('\\'));
            if (AdditionalResourceDirectories != null)
                foreach (var resdir in AdditionalResourceDirectories)
                    cmd.AppendSwitchIfNotNull ("-S ", resdir.ItemSpec.TrimEnd ('\\'));
            if (AdditionalAndroidResourcePaths != null)
                foreach (var dir in AdditionalAndroidResourcePaths)
                    cmd.AppendSwitchIfNotNull ("-S ", Path.Combine (dir.ItemSpec.TrimEnd (System.IO.Path.DirectorySeparatorChar), "res"));

            if (LibraryProjectJars != null)
                foreach (var jar in LibraryProjectJars)
                    cmd.AppendSwitchIfNotNull ("-j ", jar);

            cmd.AppendSwitchIfNotNull ("-I ", JavaPlatformJarPath);

            // Add asset directory if it exists
            if (!string.IsNullOrWhiteSpace (AssetDirectory) && Directory.Exists (AssetDirectory))
                cmd.AppendSwitchIfNotNull ("-A ", AssetDirectory.TrimEnd ('\\'));

            if (!string.IsNullOrWhiteSpace (UncompressedFileExtensions))
                foreach (var ext in UncompressedFileExtensions.Split (new char[] { ';', ','}, StringSplitOptions.RemoveEmptyEntries))
                    cmd.AppendSwitchIfNotNull ("-0 ", ext);

            if (!string.IsNullOrEmpty (ExtraPackages))
                cmd.AppendSwitchIfNotNull ("--extra-packages ", ExtraPackages);

            // TODO: handle resource names
            if (ExplicitCrunch)
                cmd.AppendSwitch ("--no-crunch");

            cmd.AppendSwitch ("--auto-add-overlay");

            var extraArgsExpanded = ExpandString (ExtraArgs);
            if (extraArgsExpanded != ExtraArgs)
                Log.LogDebugMessage ("  ExtraArgs expanded: {0}", extraArgsExpanded);

            if (!string.IsNullOrWhiteSpace (extraArgsExpanded))
                cmd.AppendSwitch (extraArgsExpanded);

            if (!AndroidUseLatestPlatformSdk)
                cmd.AppendSwitchIfNotNull ("--max-res-version ", ApiLevel);

            return cmd.ToString ();
        }
        void Run()
        {
            PackageNamingPolicy pnp;
            JniType.PackageNamingPolicy = Enum.TryParse (PackageNamingPolicy, out pnp) ? pnp : PackageNamingPolicyEnum.LowercaseHash;
            var temp = Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ());
            Directory.CreateDirectory (temp);

            // We're going to do 3 steps here instead of separate tasks so
            // we can share the list of JLO TypeDefinitions between them
            var res = new DirectoryAssemblyResolver (Log.LogWarning, loadDebugSymbols:true);

            var selectedWhitelistAssemblies = new List<string> ();

            // Put every assembly we'll need in the resolver
            foreach (var assembly in ResolvedAssemblies) {
                res.Load (Path.GetFullPath (assembly.ItemSpec));
                if (MonoAndroidHelper.FrameworkAttributeLookupTargets.Any (a => Path.GetFileName (assembly.ItemSpec) == a))
                    selectedWhitelistAssemblies.Add (Path.GetFullPath (assembly.ItemSpec));
            }

            // However we only want to look for JLO types in user code
            var assemblies = ResolvedUserAssemblies.Select (p => p.ItemSpec).ToList ();
            var fxAdditions = MonoAndroidHelper.GetFrameworkAssembliesToTreatAsUserAssemblies (ResolvedAssemblies)
                .Where (a => assemblies.All (x => Path.GetFileName (x) != Path.GetFileName (a)));
            assemblies = assemblies.Concat (fxAdditions).ToList ();

            // Step 1 - Find all the JLO types
            var all_java_types = JavaTypeScanner.GetJavaTypes (assemblies, res, Log.LogWarning);

            WriteTypeMappings (all_java_types);

            var java_types = all_java_types.Where (t => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (t));

            // Step 2 - Generate Java stub code
            var keep_going = Generator.CreateJavaSources (
                Log,
                java_types,
                temp,
                UseSharedRuntime,
                int.Parse (AndroidSdkPlatform) <= 10,
                ResolvedAssemblies.Any (assembly => Path.GetFileName (assembly.ItemSpec) == "Mono.Android.Export.dll"));

            var temp_map_file = Path.Combine (temp, "acw-map.temp");

            // We need to save a map of .NET type -> ACW type for resource file fixups
            var managed = new Dictionary<string, TypeDefinition> ();
            var java    = new Dictionary<string, TypeDefinition> ();
            var acw_map = new StreamWriter (temp_map_file);

            foreach (var type in java_types) {
                string managedKey = type.FullName.Replace ('/', '.');
                string javaKey    = JniType.ToJniName (type).Replace ('/', '.');

                acw_map.WriteLine ("{0};{1}", type.GetPartialAssemblyQualifiedName (), javaKey);
                acw_map.WriteLine ("{0};{1}", type.GetAssemblyQualifiedName (), javaKey);

                TypeDefinition conflict;
                if (managed.TryGetValue (managedKey, out conflict)) {
                    Log.LogWarning (
                            "Duplicate managed type found! Mappings between managed types and Java types must be unique. " +
                            "First Type: '{0}'; Second Type: '{1}'.",
                            conflict.GetAssemblyQualifiedName (),
                            type.GetAssemblyQualifiedName ());
                    Log.LogWarning (
                            "References to the type '{0}' will refer to '{1}'.",
                            managedKey, conflict.GetAssemblyQualifiedName ());
                    continue;
                }
                if (java.TryGetValue (javaKey, out conflict)) {
                    Log.LogError (
                            "Duplicate Java type found! Mappings between managed types and Java types must be unique. " +
                            "First Type: '{0}'; Second Type: '{1}'",
                            conflict.GetAssemblyQualifiedName (),
                            type.GetAssemblyQualifiedName ());
                    keep_going = false;
                    continue;
                }
                managed.Add (managedKey, type);
                java.Add (javaKey, type);
                acw_map.WriteLine ("{0};{1}", managedKey, javaKey);
                acw_map.WriteLine ("{0};{1}", JniType.ToCompatJniName (type).Replace ('/', '.'), javaKey);
            }

            acw_map.Close ();

            //The previous steps found an error, so we must abort and not generate any further output
            //We must do so subsequent unchanged builds fail too.
            if (!keep_going) {
                File.Delete (temp_map_file);
                return;
            }

            MonoAndroidHelper.CopyIfChanged (temp_map_file, AcwMapFile);

            try { File.Delete (temp_map_file); } catch (Exception) { }

            // Only overwrite files if the contents actually changed
            foreach (var file in Directory.GetFiles (temp, "*", SearchOption.AllDirectories)) {
                var dest = Path.GetFullPath (Path.Combine (OutputDirectory, "src", file.Substring (temp.Length + 1)));

                MonoAndroidHelper.CopyIfChanged (file, dest);
            }

            // Step 3 - Merge [Activity] and friends into AndroidManifest.xml
            var manifest = new ManifestDocument (ManifestTemplate, this.Log);

            manifest.PackageName = PackageName;
            manifest.ApplicationName = ApplicationName ?? PackageName;
            manifest.Assemblies.AddRange (assemblies);
            manifest.Resolver = res;
            manifest.SdkDir = AndroidSdkDir;
            manifest.SdkVersion = AndroidSdkPlatform;
            manifest.Debug = Debug;
            manifest.NeedsInternet = NeedsInternet;

            var additionalProviders = manifest.Merge (all_java_types, selectedWhitelistAssemblies, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

            var temp_manifest = Path.Combine (temp, "AndroidManifest.xml");
            var real_manifest = Path.GetFullPath (MergedAndroidManifestOutput);

            manifest.Save (temp_manifest);

            // Only write the new manifest if it actually changed
            MonoAndroidHelper.CopyIfChanged (temp_manifest, real_manifest);

            // Create additional runtime provider java sources.
            string providerTemplateFile = UseSharedRuntime ? "MonoRuntimeProvider.Shared.java" : "MonoRuntimeProvider.Bundled.java";
            string providerTemplate = new StreamReader (typeof (JavaCallableWrapperGenerator).Assembly.GetManifestResourceStream (providerTemplateFile)).ReadToEnd ();

            foreach (var provider in additionalProviders) {
                var temp_provider = Path.Combine (temp, provider + ".java");
                File.WriteAllText (temp_provider, providerTemplate.Replace ("MonoRuntimeProvider", provider));
                var real_provider_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono"));
                Directory.CreateDirectory (real_provider_dir);
                var real_provider = Path.Combine (real_provider_dir, provider + ".java");
                MonoAndroidHelper.CopyIfChanged (temp_provider, real_provider);
            }

            // Create additional application java sources.

            Action<string,string,string,Func<string,string>> save = (resource, filename, destDir, applyTemplate) => {
                string temp_file = Path.Combine (temp, filename);
                string template = applyTemplate (new StreamReader (typeof (GenerateJavaStubs).Assembly.GetManifestResourceStream (resource)).ReadToEnd ());
                File.WriteAllText (temp_file, template);
                Directory.CreateDirectory (destDir);
                var real_file = Path.Combine (destDir, filename);
                MonoAndroidHelper.CopyIfChanged (temp_file, real_file);
            };

            StringWriter regCallsWriter = new StringWriter ();
            regCallsWriter.WriteLine ("\t\t// Application and Instrumentation ACWs must be registered first.");
            foreach (var type in java_types) {
                if (JniType.IsApplication (type) || JniType.IsInstrumentation (type)) {
                    string javaKey = JniType.ToJniName (type).Replace ('/', '.');
                    regCallsWriter.WriteLine ("\t\tmono.android.Runtime.register (\"{0}\", {1}.class, {1}.__md_methods);",
                        type.GetAssemblyQualifiedName (), javaKey);
                }
            }
            regCallsWriter.Close ();

            var real_app_dir = Path.GetFullPath (Path.Combine (OutputDirectory, "src", "mono", "android", "app"));
            string applicationTemplateFile = "ApplicationRegistration.java";
            save (applicationTemplateFile, applicationTemplateFile, real_app_dir,
                template => template.Replace ("// REGISTER_APPLICATION_AND_INSTRUMENTATION_CLASSES_HERE", regCallsWriter.ToString ()));

            // Create NotifyTimeZoneChanges java sources.
            string notifyTimeZoneChangesFile = "NotifyTimeZoneChanges.java";
            save (notifyTimeZoneChangesFile, notifyTimeZoneChangesFile, real_app_dir, template => template);

            // Delete our temp directory
            try { Directory.Delete (temp, true); } catch (Exception) { }
        }
Example #3
0
        private void BuildSnapshot(Engine.IBackup backup)
        {
            log.Debug("Building backup snapshot");

            var manifest = new ManifestDocument(_job, _id);
            manifest.AddTag("date", XmlConvert.ToString(_now, XmlDateTimeSerializationMode.Utc));
            manifest.AddTag("source", Environment.MachineName);
            manifest.AddTag("from", _job.JobRootPath);
            manifest.AddTag("fullBackup", XmlConvert.ToString(_forceFullBackup));

            var jid = _job.JobUID.Value;

            if (_forceFullBackup)
            {
                _report.AppendLine("Note: Running a full backup");
                _proxy.ClearAllFiles(jid);
            }

            backup.CreateShadowCopy();
            var rootPath = backup.GetSnapshotPath();
            var elements = backup.GetSnapshotElements();

            _report.AppendLine();
            _report.AppendLine(" * Backup process :");
            _report.AppendLine();

            var countNewFiles = 0L;
            var countChangeFiles = 0L;
            var countDeletedFiles = 0L;

            var hash = 0L;
            foreach (var element in elements)
            {
                var file = _proxy.FindFile(jid, element.Path);
                if (element.IsDirectory)
                {
                    log.InfoFormat("[{0}] - Directory - Add entry", element.Path);
                    var entry = _zipFile.AddDirectoryByName(element.Path);
                    entry.CreationTime = element.Created;
                    entry.AccessedTime = element.LastAccessed;
                    entry.ModifiedTime = element.LastModified;

                    if (file != null)
                        _proxy.SetSeenFlags(jid, element.Path);
                    else
                        _proxy.AddFile(
                            element.Path, jid,
                            element.FileSize,
                            element.Created.Ticks,
                            element.LastModified.Ticks,
                            0, _id
                            );

                    continue;
                }

                if (file == null)
                {
                    log.InfoFormat("[{0}] - New file / Archive", element.Path);
                    if (element.FileSize != 0)
                    {
                        var entryDoc = new SnapshotAccess(rootPath + element.Path);
                        var entry = _zipFile.AddEntry(element.Path, entryDoc.OpenDelegate, entryDoc.CloseDelegate);
                        entry.CreationTime = element.Created;
                        entry.AccessedTime = element.LastAccessed;
                        entry.ModifiedTime = element.LastModified;
                        hash = entry.Crc;
                    }
                    else
                    {
                        hash = 0L;
                        manifest.NotifyEmptyFile(element.Path);
                    }

                    _report.AppendLine("Backup new file " + element.Path);
                    ++countNewFiles;
                    _proxy.AddFile(
                        element.Path, jid,
                        element.FileSize,
                        element.Created.Ticks,
                        element.LastModified.Ticks,
                        hash,
                        _id
                        );
                    continue;
                }

                if (
                    file.Modified == element.LastModified.Ticks &&
                    file.Created == element.Created.Ticks &&
                    file.FileSize == element.FileSize
                    )
                {
                    log.DebugFormat("[{0}] - No change / No archive", element.Path);
                    _proxy.SetSeenFlags(jid, element.Path);
                    continue;
                }

                log.InfoFormat("[{0}] - File changed / Archiving", element.Path);
                _report.AppendLine("Backup modified file " + element.Path);
                ++countChangeFiles;

                if (element.FileSize != 0)
                {
                    var entryDoc2 = new SnapshotAccess(rootPath + element.Path);
                    var entry2 = _zipFile.AddEntry(element.Path, entryDoc2.OpenDelegate, entryDoc2.CloseDelegate);
                    entry2.CreationTime = element.Created;
                    entry2.AccessedTime = element.LastAccessed;
                    entry2.ModifiedTime = element.LastModified;
                    hash = entry2.Crc;
                }
                else
                {
                    hash = 0L;
                    manifest.NotifyEmptyFile(element.Path);
                }

                _proxy.UpdateFile(
                    element.Path, jid,
                    element.FileSize,
                    element.Created.Ticks,
                    element.LastModified.Ticks,
                    hash,
                    _id
                    );
            }

            using (var delFiles = _proxy.GetDeletedFiles(jid))
            {
                while (delFiles.MoveNext())
                {
                    _report.AppendLine("Deleted file " + delFiles.Current.SourcePath);
                    ++countDeletedFiles;
                    manifest.NotifyDelFile(delFiles.Current.SourcePath, delFiles.Current.FileSize);
                }
            }

            _report.AppendLine();
            _report.AppendLine(string.Format(" * Report: New files: {0} / Modified files: {1} / Deleted files: {2}", countNewFiles, countChangeFiles, countDeletedFiles));

            _zipFile.Comment = manifest.Manifest;
        }