Пример #1
0
 public void Dispose()
 {
     TargetAssemblyDefinition?.Dispose();
     PrimaryAssemblyDefinition?.Dispose();
     GlobalAssemblyResolver?.Dispose();
     Logger?.Dispose();
 }
Пример #2
0
        /// <summary>
        /// The actual repacking process, called by main after parsing arguments.
        /// When referencing this assembly, call this after setting the merge properties.
        /// </summary>
        public void Repack()
        {
            var timer = new Stopwatch();

            timer.Start();
            Options.Validate();
            PrintRepackHeader();

            var actualOutFile = Path.GetFullPath(Options.OutputFile);

            Options.OutputFile = actualOutFile;

            _reflectionHelper = new ReflectionHelper(this);
            ResolveSearchDirectories();

            // Read input assemblies only after all properties are set.
            ReadInputAssemblies();

            if (MergedAssemblyFiles.Any(m => string.Compare(m, actualOutFile, StringComparison.OrdinalIgnoreCase) == 0))
            {
                Options.OutputFile = GetTempFile(Options.OutputFile);
            }

            _platformFixer  = new PlatformFixer(this, PrimaryAssemblyMainModule.Runtime);
            _mappingHandler = new MappingHandler();
            bool hadStrongName = PrimaryAssemblyDefinition.Name.HasPublicKey;

            ModuleKind kind = PrimaryAssemblyMainModule.Kind;

            if (Options.TargetKind.HasValue)
            {
                switch (Options.TargetKind.Value)
                {
                case Kind.Dll: kind = ModuleKind.Dll; break;

                case Kind.Exe: kind = ModuleKind.Console; break;

                case Kind.WinExe: kind = ModuleKind.Windows; break;
                }
            }
            TargetRuntime runtime = ParseTargetPlatform();

            // change assembly's name to correspond to the file we create
            string mainModuleName = Options.UsePrimaryAssemblyName
                ? PrimaryAssemblyDefinition.Name.Name
                : Path.GetFileNameWithoutExtension(Options.OutputFile);

            if (TargetAssemblyDefinition == null)
            {
                AssemblyNameDefinition asmName = Clone(PrimaryAssemblyDefinition.Name);
                asmName.Name             = mainModuleName;
                TargetAssemblyDefinition = AssemblyDefinition.CreateAssembly(asmName, mainModuleName,
                                                                             new ModuleParameters()
                {
                    Kind             = kind,
                    Architecture     = PrimaryAssemblyMainModule.Architecture,
                    AssemblyResolver = GlobalAssemblyResolver,
                    Runtime          = runtime
                });
            }
            else
            {
                // TODO: does this work or is there more to do?
                TargetAssemblyMainModule.Kind    = kind;
                TargetAssemblyMainModule.Runtime = runtime;

                TargetAssemblyDefinition.Name.Name = mainModuleName;
                TargetAssemblyMainModule.Name      = mainModuleName;
            }
            // set the main module attributes
            TargetAssemblyMainModule.Attributes             = PrimaryAssemblyMainModule.Attributes;
            TargetAssemblyMainModule.Win32ResourceDirectory = MergeWin32Resources(PrimaryAssemblyMainModule.Win32ResourceDirectory);

            if (Options.Version != null)
            {
                TargetAssemblyDefinition.Name.Version = Options.Version;
            }

            _lineIndexer = new IKVMLineIndexer(this, Options.LineIndexation);
            var signingStep       = new SigningStep(this, Options);
            var isUnixEnvironment = Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix;
            var isMonoRuntime     = Type.GetType("Mono.Runtime") != null;

            using (var sourceServerDataStep = GetSourceServerDataStep(isUnixEnvironment))
            {
                List <IRepackStep> repackSteps = new List <IRepackStep>
                {
                    signingStep,
                    new ReferencesRepackStep(Logger, this),
                    new TypesRepackStep(Logger, this, _repackImporter, Options),
                    new ResourcesRepackStep(Logger, this, Options),
                    new AttributesRepackStep(Logger, this, _repackImporter, Options),
                    new ReferencesFixStep(Logger, this, _repackImporter, Options),
                    new XamlResourcePathPatcherStep(Logger, this),
                    sourceServerDataStep
                };

                foreach (var step in repackSteps)
                {
                    step.Perform();
                }

                var parameters = new WriterParameters
                {
                    StrongNameKeyPair    = signingStep.KeyInfo?.KeyPair,
                    StrongNameKeyBlob    = signingStep.KeyInfo?.KeyBlob,
                    WriteSymbols         = Options.DebugInfo && PrimaryAssemblyMainModule.SymbolReader != null,
                    SymbolWriterProvider = PrimaryAssemblyMainModule.SymbolReader?.GetWriterProvider(),
                };
                // create output directory if it does not exist
                var outputDir = Path.GetDirectoryName(Options.OutputFile);
                if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
                {
                    Logger.Info("Output directory does not exist. Creating output directory: " + outputDir);
                    Directory.CreateDirectory(outputDir);
                }

                Logger.Info("Writing output assembly to disk");
                TargetAssemblyDefinition.Write(Options.OutputFile, parameters);
                sourceServerDataStep.Write();

                for (int i = 1; i < MergedAssemblies.Count; ++i)
                {
                    MergedAssemblies[i].Dispose();
                }

                TargetAssemblyDefinition.Dispose();
                GlobalAssemblyResolver.Dispose();

                if (Options.OutputFile != actualOutFile)
                {
                    MoveTempFile(Options.OutputFile, actualOutFile);
                    Options.OutputFile = actualOutFile;
                }

                // If this is an executable and we are on linux/osx we should copy file permissions from
                // the primary assembly
                if (isUnixEnvironment && isMonoRuntime)
                {
                    Stat stat;
                    Logger.Info("Copying permissions from " + PrimaryAssemblyFile);
                    Syscall.stat(PrimaryAssemblyFile, out stat);
                    Syscall.chmod(Options.OutputFile, stat.st_mode);
                }
                if (hadStrongName && !TargetAssemblyDefinition.Name.HasPublicKey)
                {
                    Options.StrongNameLost = true;
                }

                // nice to have, merge .config (assembly configuration file) & .xml (assembly documentation)
                ConfigMerger.Process(this);
                if (Options.XmlDocumentation)
                {
                    DocumentationMerger.Process(this);
                }
            }

            Logger.Info($"Finished in {timer.Elapsed}");
        }