├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── release.yml │ ├── translate-upload.yml │ └── translate.yml ├── .gitignore ├── .tx └── config ├── 0install-dotnet.xml.template ├── 0install.ps1 ├── 0install.sh ├── COPYING.txt ├── GitVersion.yml ├── README.md ├── appveyor.yml ├── build.ps1 ├── build.sh ├── doc ├── build.ps1 ├── build.sh ├── cli.md ├── client.md ├── docfx.json ├── docs │ └── toc.yml ├── file-system.md ├── index.md ├── model.md ├── publish.md ├── services.md └── toc.yml ├── icon.ico ├── icon.png ├── logo.svg ├── renovate.json ├── samples ├── MinimalZeroInstall.cs ├── MinimalZeroInstall.fs ├── MinimalZeroInstall.py └── MinimalZeroInstall.vb └── src ├── Archives ├── Archives.csproj ├── BuilderExtensions.cs ├── Builders │ ├── ArchiveBuilder.cs │ ├── IArchiveBuilder.cs │ ├── TarBuilder.cs │ ├── TarBz2Builder.cs │ ├── TarGzBuilder.cs │ ├── TarLzipBuilder.cs │ ├── TarZstandardBuilder.cs │ ├── ZipBuilder.cs │ └── _Namespace.md ├── Extractors │ ├── ArchiveExtractor.cs │ ├── CabExtractor.cs │ ├── CabExtractorContext.cs │ ├── DmgExtractor.cs │ ├── IArchiveExtractor.cs │ ├── MsiExtractor.cs │ ├── MsiPackage.cs │ ├── OldUnixExtraData.cs │ ├── RarExtractor.cs │ ├── RubyGemExtractor.cs │ ├── SevenZipExtractor.cs │ ├── TarBz2Extractor.cs │ ├── TarExtractor.cs │ ├── TarGzExtractor.cs │ ├── TarLzipExtractor.cs │ ├── TarLzmaExtractor.cs │ ├── TarXzExtractor.cs │ ├── TarZstandardExtractor.cs │ ├── ZipExtractor.cs │ └── _Namespace.md ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx └── _Namespace.md ├── Client ├── Client.csproj ├── IZeroInstallClient.cs ├── NoChangesException.cs ├── TemporarilyUnavailableException.cs ├── ZeroInstallClient.cs ├── ZeroInstallLauncher.cs └── _Namespace.md ├── Commands ├── App.config ├── Basic │ ├── AddFeed.cs │ ├── AddRemoveFeedCommand.cs │ ├── CatalogMan.Add.cs │ ├── CatalogMan.List.cs │ ├── CatalogMan.Refresh.cs │ ├── CatalogMan.Remove.cs │ ├── CatalogMan.Reset.cs │ ├── CatalogMan.Search.cs │ ├── CatalogMan.cs │ ├── Configure.cs │ ├── DefaultCommand.cs │ ├── Digest.cs │ ├── Download.cs │ ├── Export.cs │ ├── ExportHelp.cs │ ├── Exporters │ │ ├── Exporter.cs │ │ ├── HelpExporterBase.cs │ │ ├── HtmlHelpExporter.cs │ │ ├── _Namespace.md │ │ ├── import.cmd │ │ └── import.sh │ ├── Fetch.cs │ ├── Import.cs │ ├── List.cs │ ├── ListFeeds.cs │ ├── RemoveFeed.cs │ ├── Run.cs │ ├── Search.cs │ ├── Selection.cs │ ├── StoreMan.Directories.cs │ ├── StoreMan.Implementations.cs │ ├── StoreMan.Management.cs │ ├── StoreMan.cs │ ├── TrustMan.cs │ ├── Update.cs │ └── _Namespace.md ├── CliCommand.Factory.cs ├── CliCommand.cs ├── CliCommandHandler.cs ├── CliMultiCommand.cs ├── Commands.csproj ├── Desktop │ ├── AddAlias.cs │ ├── AddApp.cs │ ├── AppCommand.cs │ ├── Central.cs │ ├── ImportApps.cs │ ├── IntegrateApp.cs │ ├── IntegrationCommand.cs │ ├── ListApps.cs │ ├── RemoveAllApps.cs │ ├── RemoveApp.cs │ ├── RepairApps.cs │ ├── Self.Deploy.cs │ ├── Self.Remove.cs │ ├── Self.Update.cs │ ├── Self.cs │ ├── SelfManager.DesktopIntegration.cs │ ├── SelfManager.Firewall.cs │ ├── SelfManager.Ngen.cs │ ├── SelfManager.Service.cs │ ├── SelfManager.Target.cs │ ├── SelfManager.TaskScheduler.cs │ ├── SelfManager.cs │ ├── SyncApps.cs │ ├── UpdateApps.cs │ └── _Namespace.md ├── EnvironmentBuilderExtensions.cs ├── ExitCode.cs ├── ICliSubCommand.cs ├── ICommandHandler.cs ├── NeedsGuiException.cs ├── Program.cs ├── ProgramUtils.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ ├── Resources.zh.resx │ └── launchSettings.json ├── ScopedOperation.cs ├── UnsuitableInstallBaseException.cs ├── ZeroInstallInstance.cs ├── _Namespace.md ├── app.manifest ├── net472.targets ├── net8.0.targets └── net9.0.targets ├── DesktopIntegration ├── AccessPoints │ ├── AccessPoint.cs │ ├── AccessPointList.cs │ ├── AppAlias.cs │ ├── AutoPlay.cs │ ├── AutoStart.cs │ ├── CapabilitiyRegistration.cs │ ├── CommandAccessPoint.cs │ ├── ContextMenu.cs │ ├── DefaultAccessPoint.cs │ ├── DefaultProgram.cs │ ├── DesktopIcon.cs │ ├── FileType.cs │ ├── IconAccessPoint.cs │ ├── MenuEntry.cs │ ├── MockAccessPoint.cs │ ├── QuickLaunch.cs │ ├── SendTo.cs │ ├── UrlProtocol.cs │ └── _Namespace.md ├── AppEntry.cs ├── AppList.cs ├── CapabilityExtensions.cs ├── CategoryIntegrationManager.cs ├── ConflictData.cs ├── ConflictDataUtils.cs ├── ConflictException.cs ├── DesktopIntegration.csproj ├── GlobalSuppressions.cs ├── ICategoryIntegrationManager.cs ├── IIntegrationManager.cs ├── IconStores.cs ├── IntegrationManager.cs ├── IntegrationManagerBase.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx ├── Suggest.cs ├── SyncIntegrationManager.cs ├── SyncRaceException.cs ├── SyncResetMode.cs ├── Unix │ ├── AppAlias.cs │ ├── ContextMenu.cs │ ├── DefaultProgram.cs │ ├── FileType.cs │ ├── FreeDesktop.cs │ ├── UrlProtocol.cs │ └── _Namespace.md ├── ViewModel │ ├── AutoPlayModel.cs │ ├── CapabilityModel.cs │ ├── CapabilityModelExtensions.cs │ ├── ContextMenuModel.cs │ ├── DefaultProgramModel.cs │ ├── FileTypeModel.cs │ ├── IconCapabilityModel.cs │ ├── IntegrationState.AccessPoints.cs │ ├── IntegrationState.Capabilities.cs │ ├── IntegrationState.cs │ ├── UrlProtocolModel.cs │ └── _Namespace.md ├── Windows │ ├── AppAlias.cs │ ├── AppRegistration.cs │ ├── AutoPlay.cs │ ├── ComServer.cs │ ├── ContextMenu.cs │ ├── DefaultProgram.cs │ ├── FileType.Hash.cs │ ├── FileType.cs │ ├── PathEnv.cs │ ├── RegistryClasses.cs │ ├── Shortcut.AutoStart.cs │ ├── Shortcut.DesktopIcon.cs │ ├── Shortcut.MenuEntry.cs │ ├── Shortcut.QuickLaunch.cs │ ├── Shortcut.SendTo.cs │ ├── Shortcut.cs │ ├── Stub.manifest │ ├── StubBuilder.cs │ ├── UninstallEntry.cs │ ├── UrlProtocol.cs │ ├── _Namespace.md │ └── stub.template.cs └── _Namespace.md ├── Directory.Build.props ├── Model ├── Architecture.cs ├── ArchitectureExtensions.cs ├── Archive.cs ├── Arg.cs ├── ArgBase.cs ├── Binding.cs ├── Capabilities │ ├── AppRegistration.cs │ ├── AutoPlay.cs │ ├── AutoPlayEvent.cs │ ├── Capability.cs │ ├── CapabilityList.cs │ ├── CapabilityListExtensions.cs │ ├── ComServer.cs │ ├── ContextMenu.cs │ ├── DefaultCapability.cs │ ├── DefaultProgram.cs │ ├── FileType.cs │ ├── FileTypeExtension.cs │ ├── IconCapability.cs │ ├── InstallCommands.cs │ ├── KnownProtocolPrefix.cs │ ├── RemoveHook.cs │ ├── UrlProtocol.cs │ ├── Verb.cs │ ├── VerbCapability.cs │ └── _Namespace.md ├── Catalog.cs ├── Category.cs ├── Command.cs ├── Constraint.cs ├── CopyFromStep.cs ├── Cpu.cs ├── Dependency.cs ├── DependencyContainerExtensions.cs ├── Design │ ├── ArchitectureConverter.cs │ ├── ArchiveMimeTypeConverter.cs │ ├── ArgBaseConverter.cs │ ├── CategoryNameConverter.cs │ ├── CommandNameConverter.cs │ ├── DistributionNameConverter.cs │ ├── IconMimeTypeConverter.cs │ ├── InstallCommandsConverter.cs │ ├── LicenseNameConverter.cs │ ├── ManifestDigestConverter.cs │ ├── VerbNameConverter.cs │ └── _Namespace.md ├── DownloadRetrievalMethod.cs ├── Element.cs ├── ElementCollectionExtensions.cs ├── EntryPoint.cs ├── EnvironmentBinding.cs ├── ExecutableInBinding.cs ├── ExecutableInPath.cs ├── ExecutableInVar.cs ├── Feed.cs ├── FeedElement.cs ├── FeedReference.cs ├── FeedTarget.cs ├── FeedUri.cs ├── ForEachArgs.cs ├── GenericBinding.cs ├── GlobalSuppressions.cs ├── Group.cs ├── IArgBaseContainer.cs ├── IBindingContainer.cs ├── IDependencyContainer.cs ├── IDescriptionContainer.cs ├── IElementContainer.cs ├── IIconContainer.cs ├── IInterfaceUri.cs ├── IInterfaceUriBindingContainer.cs ├── IRecipeStep.cs ├── ISummaryContainer.cs ├── Icon.cs ├── Implementation.cs ├── ImplementationBase.cs ├── ImplementationVersion.cs ├── InterfaceReference.cs ├── ManifestDigest.cs ├── ManifestDigestPartialEqualityComparer.cs ├── Model.csproj ├── ModelUtils.cs ├── OS.cs ├── OverlayBinding.cs ├── PackageImplementation.cs ├── Preferences │ ├── FeedPreferences.cs │ ├── ImplementationPreferences.cs │ ├── InterfacePreferences.cs │ └── _Namespace.md ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx ├── Recipe.cs ├── RemoveStep.cs ├── RenameStep.cs ├── Requirements.cs ├── Restriction.cs ├── RetrievalMethod.cs ├── Runner.cs ├── Selection │ ├── ImplementationSelection.cs │ ├── SelectionCandidate.cs │ ├── SelectionCandidateExtensions.cs │ ├── Selections.cs │ ├── TestCase.cs │ ├── TestCaseSet.cs │ └── _Namespace.md ├── SingleFile.cs ├── TargetBase.cs ├── Trust │ ├── Domain.cs │ ├── DomainSet.cs │ ├── Key.cs │ └── TrustDB.cs ├── VersionDottedList.cs ├── VersionModifier.cs ├── VersionPart.cs ├── VersionRange.cs ├── VersionRangePart.cs ├── VersionRangePartExact.cs ├── VersionRangePartExclude.cs ├── VersionRangePartRange.cs ├── WorkingDir.cs ├── XmlUnknown.cs ├── ZeroInstallDeployment.cs ├── ZeroInstallEnvironment.cs └── _Namespace.md ├── Publish ├── BuilderExtensions.cs ├── Capture │ ├── CaptureSession.cs │ ├── CommandMapper.cs │ ├── RegUtils.cs │ ├── Snapshot.cs │ ├── SnapshotDiff.AppRegistration.cs │ ├── SnapshotDiff.AutoPlay.cs │ ├── SnapshotDiff.ContextMenu.cs │ ├── SnapshotDiff.DefaultProgram.cs │ ├── SnapshotDiff.FileType.cs │ ├── SnapshotDiff.UrlProtocol.cs │ ├── SnapshotDiff.cs │ └── _Namespace.md ├── EntryPoints │ ├── BashScript.cs │ ├── Candidate.cs │ ├── Design │ │ ├── DotNetVersionConverter.cs │ │ ├── JavaVersionConverter.cs │ │ └── _Namespace.md │ ├── DetectCandidates.cs │ ├── DotNetDll.cs │ ├── DotNetExe.cs │ ├── DotNetFrameworkExe.cs │ ├── IIconContainer.cs │ ├── InterpretedScript.cs │ ├── Java.cs │ ├── JavaClass.cs │ ├── JavaJar.cs │ ├── MacOSApp.cs │ ├── NativeExecutable.cs │ ├── PEHeader.Structs.cs │ ├── PEHeader.cs │ ├── PerlScript.cs │ ├── PhpScript.cs │ ├── PosixBinary.cs │ ├── PosixExecutable.cs │ ├── PosixScript.cs │ ├── PowerShellScript.cs │ ├── PythonScript.cs │ ├── RubyScript.cs │ ├── WindowsBatch.cs │ ├── WindowsExe.cs │ └── _Namespace.md ├── FeedBuilder.cs ├── FeedEditing.cs ├── FeedUtils.cs ├── ImplementationExtensions.cs ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx ├── Publish.csproj ├── RetrievalMethodExtensions.cs ├── SignedCatalog.cs ├── SignedFeed.cs ├── _Namespace.md ├── catalog.css ├── catalog.xsl ├── catalog.xsl.de ├── feed.css ├── feed.xsl └── feed.xsl.de ├── Resources.Designer.targets ├── Services ├── Executors │ ├── EnvironmentBuilder.Bindings.cs │ ├── EnvironmentBuilder.cs │ ├── Executor.cs │ ├── ExecutorException.cs │ ├── IEnvironmentBuilder.cs │ ├── IExecutor.cs │ ├── _Namespace.md │ ├── runenv.cs │ ├── runenv.exe.template │ └── runenv_build.cmd ├── Feeds │ ├── CatalogManager.cs │ ├── CatalogManagerExtensions.cs │ ├── FeedManager.cs │ ├── FeedManagerExtensions.cs │ ├── ICatalogManager.cs │ ├── IFeedManager.cs │ ├── ISelectionsManager.cs │ ├── ITrustManager.cs │ ├── OpenPgpKeyCallback.cs │ ├── ReplayAttackException.cs │ ├── SelectionsManager.cs │ ├── SelectionsManagerExtensions.cs │ ├── TrustManager.cs │ └── _Namespace.md ├── Fetchers │ ├── Fetcher.cs │ ├── IFetcher.cs │ ├── IImplementationDiscovery.cs │ ├── ImplementationDiscovery.cs │ ├── ImplementationDiscoveryExtensions.cs │ ├── ImplementationDiscoveryInstance.cs │ ├── RetrievalMethodRanker.cs │ └── _Namespace.md ├── Native │ ├── CompositePackageManager.cs │ ├── ExternalImplementation.cs │ ├── ExternalRetrievalMethod.cs │ ├── IPackageManager.cs │ ├── PackageManagerBase.cs │ ├── PackageManagers.cs │ ├── WindowsPackageManager.cs │ └── _Namespace.md ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx ├── Server │ ├── ImplementationServer.cs │ └── _Namespace.md ├── ServiceCollectionExtensions.cs ├── ServiceProvider.cs ├── Services.csproj ├── Solvers │ ├── BacktrackingSolver.cs │ ├── ExternalSolver.cs │ ├── ExternalSolverSession.cs │ ├── FallbackSolver.cs │ ├── ISelectionCandidateProvider.cs │ ├── ISolver.cs │ ├── SelectionCandidateComparer.cs │ ├── SelectionCandidateProvider.cs │ ├── SolverDemand.cs │ ├── SolverException.cs │ ├── SolverExtensions.cs │ ├── SolverRunBase.cs │ ├── SolverUtils.cs │ └── _Namespace.md ├── WebExceptionExtensions.cs └── _Namespace.md ├── Store ├── Configuration │ ├── Config.Access.cs │ ├── Config.Storage.cs │ ├── Config.cs │ ├── ConfigProperty.cs │ ├── ConfigTab.cs │ ├── NetworkLevel.cs │ └── _Namespace.md ├── Deployment │ ├── ClearDirectory.cs │ ├── DeployDirectory.cs │ ├── DirectoryOperation.cs │ └── _Namespace.md ├── Feeds │ ├── FeedCache.cs │ ├── FeedCaches.cs │ ├── FeedUtils.cs │ ├── IFeedCache.cs │ ├── SearchResult.cs │ ├── SearchResults.cs │ └── _Namespace.md ├── FileSystem │ ├── BuilderExtensions.cs │ ├── DirectoryBuilder.cs │ ├── IBuilder.cs │ ├── IForwardOnlyBuilder.cs │ ├── ImplFileUtils.cs │ ├── PrefixBuilder.cs │ ├── ReadDirectory.cs │ └── _Namespace.md ├── Icons │ ├── IIconStore.cs │ ├── IconStore.cs │ ├── IconStoreExtensions.cs │ └── _Namespace.md ├── Implementations │ ├── CompositeImplementationSink.cs │ ├── CompositeImplementationStore.cs │ ├── DigestMismatchException.cs │ ├── IImplementationSink.cs │ ├── IImplementationStore.cs │ ├── ImplementationAlreadyInStoreException.cs │ ├── ImplementationNotFoundException.cs │ ├── ImplementationSink.cs │ ├── ImplementationStore.OptimiseRun.cs │ ├── ImplementationStore.cs │ ├── ImplementationStoreKind.cs │ ├── ImplementationStoreUtils.cs │ ├── ImplementationStores.cs │ ├── ServiceImplementationStore.Connection.cs │ ├── ServiceImplementationStore.cs │ └── _Namespace.md ├── ManagerBase.cs ├── Manifests │ ├── Manifest.cs │ ├── ManifestBuilder.cs │ ├── ManifestElement.cs │ ├── ManifestFormat.cs │ └── _Namespace.md ├── Properties │ ├── Resources.Designer.cs │ ├── Resources.cs.resx │ ├── Resources.de.resx │ ├── Resources.el.resx │ ├── Resources.es.resx │ ├── Resources.fr.resx │ ├── Resources.id.resx │ ├── Resources.it.resx │ ├── Resources.ja.resx │ ├── Resources.ko.resx │ ├── Resources.nl.resx │ ├── Resources.pl.resx │ ├── Resources.pt-BR.resx │ ├── Resources.pt-PT.resx │ ├── Resources.resx │ ├── Resources.ro.resx │ ├── Resources.ru.resx │ ├── Resources.tr.resx │ └── Resources.zh.resx ├── Store.csproj ├── Trust │ ├── BouncyCastle.Storage.cs │ ├── BouncyCastle.cs │ ├── GnuPG.GpgLauncher.cs │ ├── GnuPG.cs │ ├── IFingerprintContainer.cs │ ├── IKeyIDContainer.cs │ ├── IOpenPgp.cs │ ├── OpenPgp.cs │ ├── OpenPgpExtensions.cs │ ├── OpenPgpFingerprint.cs │ ├── OpenPgpSecretKey.cs │ ├── OpenPgpSignature.cs │ ├── OpenPgpUtils.cs │ ├── SignatureException.cs │ ├── WrongPassphraseException.cs │ └── _Namespace.md ├── ViewModel │ ├── CacheNode.cs │ ├── CacheNodeBuilder.cs │ ├── FeedNode.cs │ ├── ImplementationNode.cs │ ├── OwnedImplementationNode.cs │ ├── SelectionsDiffNode.cs │ ├── SelectionsTreeNode.cs │ ├── TempDirectoryNode.cs │ ├── TrustNode.cs │ ├── TrustNodeExtensions.cs │ └── _Namespace.md └── _Namespace.md ├── UnitTests ├── Archives │ ├── Builders │ │ ├── BuilderTestBase.cs │ │ ├── TarBuilderTest.cs │ │ ├── TarBz2BuilderTest.cs │ │ ├── TarGzBuilderTest.cs │ │ ├── TarLzipBuilerTest.cs │ │ ├── TarZstandardBuilderTest.cs │ │ └── ZipBuilderTest.cs │ └── Extractors │ │ ├── ArchiveExtractorTest.cs │ │ ├── ArchiveExtractorTestBase.cs │ │ ├── CabExtractorTest.cs │ │ ├── DmgExtractorTest.cs │ │ ├── MsiExtractorTest.cs │ │ ├── NonSeekableStream.cs │ │ ├── RarExtractorTest.cs │ │ ├── RubyGemExtractorTest.cs │ │ ├── SevenZipExtractorTest.cs │ │ ├── TarBz2ExtractorTest.cs │ │ ├── TarExtractorTest.cs │ │ ├── TarGzExtractorTest.cs │ │ ├── TarLzipExtractorTest.cs │ │ ├── TarLzmaExtractorTest.cs │ │ ├── TarXzExtractorTest.cs │ │ ├── TarZstandardExtractorTest.cs │ │ ├── ZipExtractorTest.cs │ │ ├── testArchive.7z │ │ ├── testArchive.cab │ │ ├── testArchive.dmg │ │ ├── testArchive.gem │ │ ├── testArchive.msi │ │ ├── testArchive.rar │ │ ├── testArchive.tar │ │ ├── testArchive.tar.bz2 │ │ ├── testArchive.tar.gz │ │ ├── testArchive.tar.lz │ │ ├── testArchive.tar.lzma │ │ ├── testArchive.tar.xz │ │ ├── testArchive.tar.zst │ │ └── testArchive.zip ├── Client │ ├── ZeroInstallClientGuiTest.cs │ └── ZeroInstallClientTest.cs ├── Commands │ ├── Basic │ │ ├── DownloadTest.cs │ │ ├── Exporters │ │ │ └── ExporterTest.cs │ │ ├── ListTest.cs │ │ ├── RunTest.cs │ │ ├── SelectionTest.cs │ │ ├── SelectionTestBase.cs │ │ ├── StoreManTest.cs │ │ ├── TrustManTest.cs │ │ └── UpdateTest.cs │ ├── CliCommandTestBase.cs │ ├── Desktop │ │ ├── AddAppTest.cs │ │ └── ListAppsTest.cs │ └── MockCommandHandler.cs ├── DesktopIntegration │ ├── AccessPoints │ │ └── CapabilityRegistrationTest.cs │ ├── AppListTest.cs │ ├── ConflictDataUtilsTest.cs │ ├── IntegrationManagerTest.cs │ ├── SuggestTest.cs │ ├── SyncIntegrationManagerTest.cs │ └── Windows │ │ ├── RegistryClassesTest.cs │ │ ├── ShortcutTest.cs │ │ └── StubBuilderTest.cs ├── Fake.cs ├── FileSystem │ ├── TestDirectory.cs │ ├── TestElement.cs │ ├── TestFile.cs │ ├── TestRoot.cs │ └── TestSymlink.cs ├── MockExtensions.cs ├── Model │ ├── ArchitectureTest.cs │ ├── ArchiveTest.cs │ ├── Capabilities │ │ └── CapabilityListTest.cs │ ├── CatalogTest.cs │ ├── CommandTest.cs │ ├── DependencyTest.cs │ ├── EnvironmentBindingTest.cs │ ├── ExecutableInPathTest.cs │ ├── ExecutableInVarTest.cs │ ├── FeedElementTest.cs │ ├── FeedReferenceTest.cs │ ├── FeedTest.cs │ ├── FeedUriTest.cs │ ├── GenericBindingTest.cs │ ├── ImplementationTest.cs │ ├── ImplementationVersionTest.cs │ ├── ManifestDigestTest.cs │ ├── ModelUtilsTest.cs │ ├── OverlayBindingTest.cs │ ├── PackageImplementationTest.cs │ ├── Preferences │ │ ├── FeedPreferencesTest.cs │ │ └── InterfacePreferencesTest.cs │ ├── RequirementsTest.cs │ ├── RestrictionTest.cs │ ├── RunnerTest.cs │ ├── Selection │ │ ├── ImplementationSelectionTest.cs │ │ ├── SelectionCandidateTest.cs │ │ └── SelectionsTest.cs │ ├── SingleFileTest.cs │ ├── Trust │ │ └── TrustDBTest.cs │ ├── VersionRangeTest.cs │ └── XmlUnknownTest.cs ├── Publish │ ├── BuilderExtensionsTest.cs │ ├── Capture │ │ └── CommandMapperTest.cs │ ├── EntryPoints │ │ ├── CandidateTest.cs │ │ ├── DetectionTest.cs │ │ ├── DotNetDllTest.cs │ │ ├── DotNetExeTest.cs │ │ ├── DotNetFrameworkExeTest.cs │ │ ├── PosixBinaryTest.cs │ │ ├── PosixScriptTest.cs │ │ ├── PythonScriptTest.cs │ │ ├── WindowsExeTest.cs │ │ ├── batch.cmd │ │ ├── dotnet-aspnetcore.dll │ │ ├── dotnet-aspnetcore.exe │ │ ├── dotnet-aspnetcore.runtimeconfig.json │ │ ├── dotnet-windowsdesktop.dll │ │ ├── dotnet-windowsdesktop.exe │ │ ├── dotnet-windowsdesktop.runtimeconfig.json │ │ ├── dotnet.dll │ │ ├── dotnet.exe │ │ ├── dotnet.runtimeconfig.json │ │ ├── elf32 │ │ ├── elf64 │ │ ├── netfx.exe │ │ ├── netfx64.exe │ │ ├── netfx_terminal.exe │ │ ├── python │ │ ├── python.py │ │ ├── python.pyw │ │ ├── sh │ │ ├── windows32.exe │ │ ├── windows32_terminal.exe │ │ └── windows64.exe │ ├── FeedBuilderTest.cs │ ├── FeedUtilsTest.cs │ ├── ImplementationExtensionsTest.cs │ ├── RetrievalMethodExtensionsTest.cs │ └── testArchive.zip ├── Services │ ├── Executors │ │ └── EnvironmentBuilderTest.cs │ ├── Feeds │ │ ├── CatalogManagerTest.cs │ │ ├── FeedManagerTest.cs │ │ └── TrustManagerTest.cs │ ├── Fetchers │ │ ├── FetcherTest.cs │ │ ├── ImplementationDiscoveryTest.cs │ │ ├── RetrievalMethodRankerTest.cs │ │ └── testArchive.zip │ ├── MockTaskHandler.cs │ ├── Native │ │ └── WindowsPackageManagerTest.cs │ ├── SelectionsManagerTest.cs │ ├── Server │ │ └── ImplementationServerTest.cs │ ├── ServiceCollectionTest.cs │ ├── ServiceProviderTest.cs │ └── Solvers │ │ ├── BacktrackingSolverTest.cs │ │ ├── SelectionCandidateComparerTest.cs │ │ ├── SelectionCandidateProviderTest.cs │ │ ├── SolverTest.cs │ │ ├── SolverUtilsTest.cs │ │ └── test-cases.xml ├── Store │ ├── Configuration │ │ └── ConfigTest.cs │ ├── Deployment │ │ ├── ClearDirectoryTest.cs │ │ ├── DeployDirectoryTest.cs │ │ └── DirectoryOperationTestBase.cs │ ├── Feeds │ │ ├── FeedCacheTest.cs │ │ └── FeedUtilsTest.cs │ ├── FileSystem │ │ ├── DirectoryBuilderTest.cs │ │ ├── PrefixBuilderTest.cs │ │ └── ReadDirectoryTest.cs │ ├── Icons │ │ └── IconStoreTest.cs │ ├── Implementations │ │ ├── CompositeImplementationStoreTest.cs │ │ ├── ImplementationStoreExtensions.cs │ │ ├── ImplementationStoreTest.cs │ │ └── ImplementationStoreUtilsTest.cs │ ├── Manifests │ │ ├── ManifestBuilderTest.cs │ │ ├── ManifestFormatTest.cs │ │ └── ManifestTest.cs │ └── Trust │ │ ├── BouncyCastleTest.cs │ │ ├── OpenPgpTest.cs │ │ ├── OpenPgpUtilsTest.cs │ │ ├── pubkey.gpg │ │ ├── pubring.gpg │ │ ├── secring.gpg │ │ └── signature.dat ├── TestWithMocks.cs ├── TestWithMocksAndRedirect.cs ├── TestWithRedirect.cs └── UnitTests.csproj ├── XmlSerializer.Generator.targets ├── ZeroInstall.sln ├── ZeroInstall.sln.DotSettings ├── build.ps1 ├── build.sh ├── test.ps1 └── test.sh /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "docfx": { 6 | "version": "2.78.3", 7 | "commands": [ 8 | "docfx" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable linebreak normalization 2 | * -text 3 | 4 | # Language-aware diff 5 | *.cs diff=csharp 6 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # Trigger additional actions after a GitHub Release has been created 2 | name: Release 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Download documentation 12 | run: | 13 | curl -sSfLO https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/docs.zip 14 | unzip -q docs.zip -d docs 15 | 16 | - name: Publish documentation 17 | uses: peaceiris/actions-gh-pages@v4 18 | with: 19 | github_token: ${{github.token}} 20 | force_orphan: true 21 | publish_dir: docs 22 | cname: dotnet.0install.net 23 | 24 | - name: Publish feed 25 | env: 26 | GH_TOKEN: ${{secrets.PERSONAL_TOKEN}} 27 | run: > 28 | gh workflow run --repo=0install/apps Incoming 29 | -f feed_url=https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/0install-dotnet-${{github.ref_name}}.xml 30 | -f archive_url=https://github.com/${{github.repository}}/releases/download/${{github.ref_name}}/0install-dotnet-${{github.ref_name}}.tar.gz 31 | -------------------------------------------------------------------------------- /.github/workflows/translate-upload.yml: -------------------------------------------------------------------------------- 1 | name: Translate Upload 2 | on: 3 | workflow_dispatch: {} 4 | push: 5 | branches: [master] 6 | paths: ['**/*.resx', '!**/*.*.resx'] # non-localized resource files 7 | 8 | jobs: 9 | translate-upload: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | show-progress: false 16 | 17 | - name: Transifex Push 18 | run: ./0install.sh run https://apps.0install.net/devel/transifex-cli.xml --token ${{secrets.TRANSIFEX_API_KEY}} push --source 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.bak 3 | *.a.resx 4 | *.o.resx 5 | 6 | # Caches 7 | /src/.vs/ 8 | /src/.idea/ 9 | /src/_ReSharper.*/ 10 | /src/*/obj/ 11 | /src/*/bin/ 12 | /doc/obj/ 13 | /doc/api/ 14 | 15 | # Output 16 | /artifacts/ 17 | /0install-dotnet-*.xml 18 | /0install-dotnet-*.tar.gz 19 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | type = RESX 4 | source_lang = en 5 | lang_map = pt_PT: pt-PT, pt_BR: pt-BR 6 | 7 | [o:eicher:p:0install-win:r:model] 8 | source_file = src/Model/Properties/Resources.resx 9 | file_filter = src/Model/Properties/Resources..o.resx 10 | 11 | [o:eicher:p:0install-win:r:store] 12 | source_file = src/Store/Properties/Resources.resx 13 | file_filter = src/Store/Properties/Resources..o.resx 14 | 15 | [o:eicher:p:0install-win:r:archives] 16 | source_file = src/Archives/Properties/Resources.resx 17 | file_filter = src/Archives/Properties/Resources..o.resx 18 | 19 | [o:eicher:p:0install-win:r:services] 20 | source_file = src/Services/Properties/Resources.resx 21 | file_filter = src/Services/Properties/Resources..o.resx 22 | 23 | [o:eicher:p:0install-win:r:desktopintegration] 24 | source_file = src/DesktopIntegration/Properties/Resources.resx 25 | file_filter = src/DesktopIntegration/Properties/Resources..o.resx 26 | 27 | [o:eicher:p:0install-win:r:commands] 28 | source_file = src/Commands/Properties/Resources.resx 29 | file_filter = src/Commands/Properties/Resources..o.resx 30 | 31 | [o:eicher:p:0install-win:r:publish] 32 | source_file = src/Publish/Properties/Resources.resx 33 | file_filter = src/Publish/Properties/Resources..o.resx 34 | -------------------------------------------------------------------------------- /0install-dotnet.xml.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | Zero Install - .NET Core version 4 | .NET Core version of 0install, the decentralized installation system 5 | This is the .NET Core version of Zero Install. Zero Install is a cross-platform, decentralized installation system. Instead of having a central repository in which all software is placed under a naming scheme managed by some central authority, programs and libraries in Zero Install are identified by URIs. Anyone who can create a web-page can publish software. Anyone can install software (not just administrators). 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /0install.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | 3 | function Download-ZeroInstall { 4 | $dir = "$env:LOCALAPPDATA\0install.net\bootstrapper" 5 | $file = "$dir\0install.exe" 6 | if (!(Test-Path $file)) { 7 | mkdir -Force $dir | Out-Null 8 | [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls11,Tls12' 9 | Invoke-WebRequest "https://get.0install.net/0install.exe" -OutFile $file 10 | } 11 | return $file 12 | } 13 | 14 | function Run-ZeroInstall { 15 | if (Get-Command 0install -ErrorAction SilentlyContinue) { 16 | 0install @args 17 | } else { 18 | . $(Download-ZeroInstall) @args 19 | } 20 | } 21 | 22 | if ($args.Count -eq 0) { 23 | echo "This script runs 0install from your PATH or downloads it on-demand." 24 | echo "" 25 | echo "To run 0install commands without adding 0install to your PATH:" 26 | echo ".\0install.ps1 COMMAND [OPTIONS]" 27 | echo "" 28 | echo "To deploy 0install to your user profile:" 29 | echo ".\0install.ps1 self deploy" 30 | echo "" 31 | echo "To deploy 0install to your machine:" 32 | echo ".\0install.ps1 self deploy --machine" 33 | } else { 34 | Run-ZeroInstall @args 35 | } 36 | -------------------------------------------------------------------------------- /0install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | if [ "$#" -eq 0 ]; then 5 | echo "This script runs 0install from your PATH or downloads it on-demand." 6 | echo "" 7 | echo "To run 0install commands without adding 0install to your PATH:" 8 | echo "./0install.sh --help" 9 | echo "./0install.sh COMMAND [OPTIONS]" 10 | echo "" 11 | echo "To install to /usr/local:" 12 | echo "sudo ./0install.sh install local" 13 | echo "" 14 | echo "To install to your home directory:" 15 | echo "./0install.sh install home" 16 | exit 1 17 | fi 18 | 19 | download() { 20 | zeroinstall_release=0install-$(uname | tr '[:upper:]' '[:lower:]')-$(uname -m)-${ZEROINSTALL_VERSION:-latest} 21 | download_dir=~/.cache/0install.net/$zeroinstall_release 22 | 23 | if [ ! -f $download_dir/files/0install ]; then 24 | echo "Downloading 0install..." >&2 25 | rm -rf $download_dir 26 | mkdir -p $download_dir 27 | curl -sSL https://get.0install.net/$zeroinstall_release.tar.bz2 | tar xj --strip-components 1 --directory $download_dir 28 | fi 29 | } 30 | 31 | if [ "$1" = "install" ]; then 32 | download 33 | shift 1 34 | $download_dir/install.sh "$@" 35 | else 36 | if command -v 0install > /dev/null 2> /dev/null; then 37 | 0install "$@" 38 | else 39 | download 40 | $download_dir/files/0install "$@" 41 | fi 42 | fi 43 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | mode: ContinuousDeployment 2 | 3 | # Generate 0install-compatible version numbers 4 | branches: 5 | # Mainline branches 6 | main: 7 | tag: rc-pre 8 | develop: 9 | tag: pre 10 | increment: patch 11 | 12 | # Stabilization branches 13 | release: 14 | tag: rc 15 | hotfix: 16 | tag: rc 17 | 18 | # Topic branches 19 | feature: 20 | tag: pre-pre 21 | pull-request: 22 | tag: pre-pre 23 | fallback: 24 | source-branches: [main] 25 | regex: ^(?!main|master|develop|release|hotfix|feature|pull|pr) 26 | tag: pre-pre 27 | -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | Param ([String]$Version = "1.0.0-pre", [Switch]$SkipTest) 2 | $ErrorActionPreference = "Stop" 3 | pushd $PSScriptRoot 4 | 5 | src\build.ps1 $Version 6 | if (-Not $SkipTest) { src\test.ps1 } 7 | doc\build.ps1 8 | .\0install.ps1 run --batch https://apps.0install.net/0install/0template.xml 0install-dotnet.xml.template version=$Version ` 9 | 10 | popd 11 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | cd `dirname $0` 4 | VERSION=${1:-1.0.0-pre} 5 | 6 | src/build.sh $VERSION 7 | [ "$2" != "--skip-test" ] && src/test.sh 8 | doc/build.sh 9 | ./0install.sh run https://apps.0install.net/0install/0template.xml 0install-dotnet.xml.template version=$VERSION 10 | -------------------------------------------------------------------------------- /doc/build.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | pushd $PSScriptRoot 3 | 4 | function Run-DotNet { 5 | ..\0install.ps1 run --batch --version 9.0.. https://apps.0install.net/dotnet/sdk.xml @args 6 | if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"} 7 | } 8 | 9 | echo "Build docs" 10 | Run-DotNet tool restore 11 | Run-DotNet docfx --logLevel=warning --warningsAsErrors docfx.json 12 | 13 | popd 14 | -------------------------------------------------------------------------------- /doc/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | cd `dirname $0` 4 | 5 | # Find dotnet 6 | #if command -v dotnet > /dev/null 2> /dev/null; then 7 | # dotnet="dotnet" 8 | #else 9 | dotnet="../0install.sh run --version 9.0.. https://apps.0install.net/dotnet/sdk.xml" 10 | #fi 11 | 12 | echo "Build docs" 13 | $dotnet tool restore 14 | $dotnet docfx --logLevel=warning --warningsAsErrors docfx.json 15 | -------------------------------------------------------------------------------- /doc/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../src", 7 | "files": ["*/*.csproj"], 8 | "exclude": ["UnitTests/*"] 9 | } 10 | ], 11 | "properties": { 12 | "TargetFramework": "net8.0" 13 | }, 14 | "namespaceLayout": "nested", 15 | "dest": "api" 16 | } 17 | ], 18 | "build": { 19 | "globalMetadata": { 20 | "_baseUrl": "https://dotnet.0install.net/", 21 | "_appTitle": "Zero Install .NET API", 22 | "_appFooter": "Copyright Bastian Eicher et al" 23 | }, 24 | "content": [ 25 | { 26 | "files": [ 27 | "*.md", 28 | "toc.yml", 29 | "docs/toc.yml", 30 | "api/*.yml" 31 | ] 32 | } 33 | ], 34 | "resource": [ 35 | { 36 | "src": "..", 37 | "files": ["logo.svg"] 38 | } 39 | ], 40 | "overwrite": [ 41 | { 42 | "src": "../src/", 43 | "files": ["**/*.md"] 44 | } 45 | ], 46 | "xref": [ 47 | "https://common.nano-byte.net/xrefmap.yml" 48 | ], 49 | "xrefService": [ 50 | "https://xref.docs.microsoft.com/query?uid={uid}" 51 | ], 52 | "postProcessors": ["ExtractSearchIndex"], 53 | "template": [ 54 | "default", 55 | "modern", 56 | "template" 57 | ], 58 | "dest": "../artifacts/Documentation" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /doc/docs/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Overview 2 | href: ../index.md 3 | - name: Services 4 | href: ../services.md 5 | - name: Data model 6 | href: ../model.md 7 | - name: Publishing 8 | href: ../publish.md 9 | - name: File system 10 | href: ../file-system.md 11 | - name: Command-line interface 12 | href: ../cli.md 13 | - name: Client library 14 | href: ../client.md 15 | -------------------------------------------------------------------------------- /doc/publish.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: publishing 3 | --- 4 | 5 | # Publishing 6 | 7 | The namespace provides utilities for creating and modifying feed files. This provides the basis for the [Zero Install Publishing Tools](https://github.com/0install/0publish-win). You can also use it to create your own tools. 8 | 9 | ## Feed signing 10 | 11 | The class provides a wrapper around that adds [OpenPGP signatures](https://docs.0install.net/specifications/feed/#digital-signatures) to feed files when saving. 12 | 13 | ## Set missing values 14 | 15 | The [.SetMissing()](xref:ZeroInstall.Publish.ImplementationExtensions#ZeroInstall_Publish_ImplementationExtensions_SetMissing_ZeroInstall_Model_Implementation_NanoByte_Common_Undo_ICommandExecutor_NanoByte_Common_Tasks_ITaskHandler_) extension method for sets missing properties by downloading, extracting and hashing files as needed. 16 | 17 | ## Feed editing 18 | 19 | The class is a container for editing feeds with an . 20 | -------------------------------------------------------------------------------- /doc/toc.yml: -------------------------------------------------------------------------------- 1 | - name: Docs 2 | href: docs/ 3 | - name: API 4 | href: api/ 5 | -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/icon.ico -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/icon.png -------------------------------------------------------------------------------- /samples/MinimalZeroInstall.cs: -------------------------------------------------------------------------------- 1 | using NanoByte.Common.Tasks; 2 | using ZeroInstall.Model; 3 | using ZeroInstall.Services; 4 | using ZeroInstall.Services.Feeds; 5 | 6 | var requirements = new Requirements(new FeedUri(args[0])); 7 | var services = new ServiceProvider(new CliTaskHandler()); 8 | var selections = services.Solver.Solve(requirements); 9 | foreach (var implementation in services.SelectionsManager.GetUncachedImplementations(selections)) 10 | services.Fetcher.Fetch(implementation); 11 | services.Executor.Start(selections); 12 | -------------------------------------------------------------------------------- /samples/MinimalZeroInstall.fs: -------------------------------------------------------------------------------- 1 | open NanoByte.Common.Tasks 2 | open ZeroInstall.Model 3 | open ZeroInstall.Services 4 | open ZeroInstall.Services.Feeds 5 | 6 | let services = new ServiceProvider(new CliTaskHandler()) 7 | let solve = services.Solver.Solve 8 | let uncached = services.SelectionsManager.GetUncachedImplementations 9 | let fetch = services.Fetcher.Fetch 10 | let execute = services.Executor.Start 11 | 12 | let run requirements = 13 | let selections = solve requirements 14 | for implementation in (uncached selections) do 15 | fetch implementation 16 | execute selections 17 | 18 | [] 19 | let main args = 20 | ignore(run(new Requirements(new FeedUri(args.[0])))) 21 | 0 22 | -------------------------------------------------------------------------------- /samples/MinimalZeroInstall.py: -------------------------------------------------------------------------------- 1 | import clr 2 | clr.AddReferenceToFile("NanoByte.Common.dll", "ZeroInstall.Services.dll", "ZeroInstall.Store.dll") 3 | 4 | import sys 5 | from NanoByte.Common.Tasks import CliTaskHandler 6 | from ZeroInstall.Model import FeedUri, Requirements 7 | from ZeroInstall.Services import ServiceProvider 8 | from ZeroInstall.Services.Feeds import SelectionsManagerExtensions 9 | 10 | services = ServiceProvider(CliTaskHandler()) 11 | requirements = Requirements(FeedUri(sys.argv[1])) 12 | selections = services.Solver.Solve(requirements) 13 | for implementation in SelectionsManagerExtensions.GetUncachedImplementations(services.SelectionsManager, selections): 14 | services.Fetcher.Fetch(implementation) 15 | services.Executor.Start(selections) 16 | -------------------------------------------------------------------------------- /samples/MinimalZeroInstall.vb: -------------------------------------------------------------------------------- 1 | Imports NanoByte.Common.Tasks 2 | Imports ZeroInstall.Model 3 | Imports ZeroInstall.Services 4 | Imports ZeroInstall.Services.Feeds 5 | 6 | Module MinimalZeroInstall 7 | Sub Main(ByVal args As String()) 8 | Dim requirements = New Requirements(New FeedUri(args(0))) 9 | Dim services = New ServiceProvider(New CliTaskHandler()) 10 | With services 11 | Dim selections = .Solver.Solve(requirements) 12 | For Each implementation In .SelectionsManager.GetUncachedImplementations(selections) 13 | .Fetcher.Fetch(implementation) 14 | Next 15 | .Executor.Start(selections) 16 | End With 17 | End Sub 18 | End Module 19 | -------------------------------------------------------------------------------- /src/Archives/Builders/IArchiveBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.FileSystem; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Builds an implementation archive file. 10 | /// 11 | public interface IArchiveBuilder : IForwardOnlyBuilder, IDisposable; 12 | -------------------------------------------------------------------------------- /src/Archives/Builders/TarBz2Builder.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ICSharpCode.SharpZipLib.BZip2; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Builds a BZip2-compressed TAR archive (.tar.bz2). 10 | /// 11 | /// The stream to write the archive to. Will be disposed when the builder is disposed. 12 | /// The compression operation should complete as quickly as possible, even if the resulting file is not optimally compressed. 13 | [MustDisposeResource] 14 | public class TarBz2Builder(Stream stream, bool fast = false) : TarBuilder(new BZip2OutputStream(stream, blockSize: fast ? 1 : 9)); 15 | -------------------------------------------------------------------------------- /src/Archives/Builders/TarGzBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.IO.Compression; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Builds a GZip-compressed TAR archive (.tar.gz). 10 | /// 11 | /// The stream to write the archive to. Will be disposed when the builder is disposed. 12 | /// The compression operation should complete as quickly as possible, even if the resulting file is not optimally compressed. 13 | [MustDisposeResource] 14 | public class TarGzBuilder(Stream stream, bool fast = false) : TarBuilder(new GZipStream(stream, fast 15 | ? CompressionLevel.Fastest 16 | #if NET 17 | : CompressionLevel.SmallestSize 18 | #else 19 | : CompressionLevel.Optimal 20 | #endif 21 | )); 22 | -------------------------------------------------------------------------------- /src/Archives/Builders/TarLzipBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using SharpCompress.Compressors; 6 | using SharpCompress.Compressors.LZMA; 7 | 8 | namespace ZeroInstall.Archives.Builders; 9 | 10 | /// 11 | /// Builds a Lzip-compressed TAR archive (.tar.lz). 12 | /// 13 | /// The stream to write the archive to. Will be disposed when the builder is disposed. 14 | [MustDisposeResource] 15 | public class TarLzipBuilder(Stream stream) : TarBuilder(new LZipStream(stream, CompressionMode.Compress)); 16 | #endif 17 | -------------------------------------------------------------------------------- /src/Archives/Builders/TarZstandardBuilder.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using ZstdSharp; 6 | 7 | namespace ZeroInstall.Archives.Builders; 8 | 9 | /// 10 | /// Builds a Zstandard-compressed TAR archive (tar.zst). 11 | /// 12 | /// The stream to write the archive to. Will be disposed when the builder is disposed. 13 | /// The compression operation should complete as quickly as possible, even if the resulting file is not optimally compressed. 14 | [MustDisposeResource] 15 | public class TarZstandardBuilder(Stream stream, bool fast = false) : TarBuilder(new CompressionStream(stream, level: fast ? 3 : 19)) 16 | { 17 | public override void Dispose() 18 | { 19 | try 20 | { 21 | base.Dispose(); 22 | } 23 | finally 24 | { 25 | stream.Dispose(); 26 | } 27 | } 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /src/Archives/Builders/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Archives.Builders 3 | summary: *content 4 | --- 5 | Building archives (.zip, .tar, etc.). 6 | -------------------------------------------------------------------------------- /src/Archives/Extractors/IArchiveExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.FileSystem; 5 | 6 | namespace ZeroInstall.Archives.Extractors; 7 | 8 | /// 9 | /// Extracts implementation archives. 10 | /// 11 | /// Implementations of this interface are immutable and thread-safe. 12 | public interface IArchiveExtractor 13 | { 14 | /// 15 | /// Extracts an archive. 16 | /// 17 | /// The builder receiving the extracted files. 18 | /// The archive data to be extracted. 19 | /// The Unix-style path of the subdirectory in the archive to extract; null to extract entire archive. 20 | /// The operation was canceled. 21 | /// A problem occurred while extracting the archive. 22 | void Extract(IBuilder builder, Stream stream, string? subDir = null); 23 | 24 | /// 25 | /// A to set for see cref="ITask"/>s spawned by this extractor; can be null. 26 | /// 27 | object? Tag { get; set; } 28 | } 29 | -------------------------------------------------------------------------------- /src/Archives/Extractors/OldUnixExtraData.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ICSharpCode.SharpZipLib.Zip; 5 | 6 | namespace ZeroInstall.Archives.Extractors; 7 | 8 | /// 9 | /// Class representing the old Info-ZIP extra block for Unix. 10 | /// 11 | internal class OldUnixExtraData : ITaggedData 12 | { 13 | public ushort TagID => 0x5855; 14 | 15 | public UnixTime ModificationTime { get; set; } 16 | 17 | public UnixTime AccessTime { get; set; } 18 | 19 | public void SetData(byte[] data, int index, int count) 20 | { 21 | var stream = new MemoryStream(data, index, count); 22 | ModificationTime = ReadLEInt(stream); 23 | AccessTime = ReadLEInt(stream); 24 | } 25 | 26 | private static int ReadLEInt(Stream stream) 27 | => ReadLEShort(stream) | (ReadLEShort(stream) << 16); 28 | 29 | private static int ReadLEShort(Stream stream) 30 | { 31 | int byteValue1 = stream.ReadByte(); 32 | 33 | if (byteValue1 < 0) 34 | throw new EndOfStreamException(); 35 | 36 | int byteValue2 = stream.ReadByte(); 37 | if (byteValue2 < 0) 38 | throw new EndOfStreamException(); 39 | 40 | return byteValue1 | (byteValue2 << 8); 41 | } 42 | 43 | public byte[] GetData() => throw new NotImplementedException(); 44 | } 45 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarBz2Extractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ICSharpCode.SharpZipLib.BZip2; 5 | using ZeroInstall.Store.FileSystem; 6 | 7 | namespace ZeroInstall.Archives.Extractors; 8 | 9 | /// 10 | /// Extracts BZip2-compressed TAR archives (.tar.bz2). 11 | /// 12 | /// A callback object used when the user needs to be informed about IO tasks. 13 | /// This class is immutable and thread-safe. 14 | public class TarBz2Extractor(ITaskHandler handler) : TarExtractor(handler) 15 | { 16 | /// 17 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 18 | { 19 | try 20 | { 21 | base.Extract(builder, new BZip2InputStream(stream) {IsStreamOwner = false}, subDir); 22 | } 23 | #region Error handling 24 | catch (BZip2Exception ex) 25 | { 26 | // Wrap exception since only certain exception types are allowed 27 | throw new IOException(Resources.ArchiveInvalid, ex); 28 | } 29 | #endregion 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarGzExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.IO.Compression; 5 | using ZeroInstall.Store.FileSystem; 6 | 7 | namespace ZeroInstall.Archives.Extractors; 8 | 9 | /// 10 | /// Extracts GZip-compressed TAR archives (.tar.gz). 11 | /// 12 | /// A callback object used when the user needs to be informed about IO tasks. 13 | /// This class is immutable and thread-safe. 14 | public class TarGzExtractor(ITaskHandler handler) : TarExtractor(handler) 15 | { 16 | /// 17 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 18 | => base.Extract(builder, new GZipStream(stream, CompressionMode.Decompress), subDir); 19 | } 20 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarLzipExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using SharpCompress.Common; 6 | using SharpCompress.Compressors; 7 | using SharpCompress.Compressors.LZMA; 8 | using ZeroInstall.Store.FileSystem; 9 | 10 | namespace ZeroInstall.Archives.Extractors; 11 | 12 | /// 13 | /// Extracts Lzip-compressed TAR archives (.tar.lz). 14 | /// 15 | /// A callback object used when the user needs to be informed about IO tasks. 16 | /// This class is immutable and thread-safe. 17 | public class TarLzipExtractor(ITaskHandler handler) : TarExtractor(handler) 18 | { 19 | /// 20 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 21 | { 22 | try 23 | { 24 | base.Extract(builder, new LZipStream(stream, CompressionMode.Decompress), subDir); 25 | } 26 | #region Error handling 27 | catch (ExtractionException ex) 28 | { 29 | // Wrap exception since only certain exception types are allowed 30 | throw new IOException(Resources.ArchiveInvalid, ex); 31 | } 32 | #endregion 33 | } 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarLzmaExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using NanoByte.Common.Streams; 6 | using SharpCompress.Common; 7 | using SharpCompress.Compressors.LZMA; 8 | using ZeroInstall.Store.FileSystem; 9 | 10 | namespace ZeroInstall.Archives.Extractors; 11 | 12 | /// 13 | /// Extracts LZMA-compressed TAR archives (.tar.lzma). 14 | /// 15 | /// A callback object used when the user needs to be informed about IO tasks. 16 | /// This class is immutable and thread-safe. 17 | public class TarLzmaExtractor(ITaskHandler handler) : TarExtractor(handler) 18 | { 19 | /// 20 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 21 | { 22 | try 23 | { 24 | base.Extract(builder, new LzmaStream(stream.Read(13), stream), subDir); 25 | } 26 | #region Error handling 27 | catch (ExtractionException ex) 28 | { 29 | // Wrap exception since only certain exception types are allowed 30 | throw new IOException(Resources.ArchiveInvalid, ex); 31 | } 32 | #endregion 33 | } 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarXzExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using NanoByte.Common.Streams; 6 | using SharpCompress.Common; 7 | using SharpCompress.Compressors.Xz; 8 | using ZeroInstall.Store.FileSystem; 9 | 10 | namespace ZeroInstall.Archives.Extractors; 11 | 12 | /// 13 | /// Extracts XZ-compressed TAR archives (tar.xz). 14 | /// 15 | /// A callback object used when the user needs to be informed about IO tasks. 16 | /// This class is immutable and thread-safe. 17 | public class TarXzExtractor(ITaskHandler handler) : TarExtractor(handler) 18 | { 19 | /// 20 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 21 | { 22 | try 23 | { 24 | base.Extract(builder, new XZStream( 25 | stream.WithSeekBuffer(bufferSize: 0) // Allow skipping past padding 26 | ), subDir); 27 | } 28 | #region Error handling 29 | catch (ExtractionException ex) 30 | { 31 | // Wrap exception since only certain exception types are allowed 32 | throw new IOException(Resources.ArchiveInvalid, ex); 33 | } 34 | #endregion 35 | } 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /src/Archives/Extractors/TarZstandardExtractor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !MINIMAL 5 | using ZeroInstall.Store.FileSystem; 6 | using ZstdSharp; 7 | 8 | namespace ZeroInstall.Archives.Extractors; 9 | 10 | /// 11 | /// Extracts Zstandard-compressed TAR archives (tar.zst). 12 | /// 13 | /// A callback object used when the user needs to be informed about IO tasks. 14 | /// This class is immutable and thread-safe. 15 | public class TarZstandardExtractor(ITaskHandler handler) : TarExtractor(handler) 16 | { 17 | /// 18 | public override void Extract(IBuilder builder, Stream stream, string? subDir = null) 19 | { 20 | try 21 | { 22 | using var decompressionStream = new DecompressionStream(stream); 23 | base.Extract(builder, decompressionStream, subDir); 24 | } 25 | #region Error handling 26 | catch (Exception ex) when (ex is ZstdException or ArgumentException) 27 | { 28 | // Wrap exception since only certain exception types are allowed 29 | throw new IOException(Resources.ArchiveInvalid, ex); 30 | } 31 | #endregion 32 | } 33 | } 34 | #endif 35 | -------------------------------------------------------------------------------- /src/Archives/Extractors/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Archives.Extractors 3 | summary: *content 4 | --- 5 | Extracting archives (.zip, .tar, etc.). 6 | -------------------------------------------------------------------------------- /src/Archives/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Archives 3 | summary: *content 4 | --- 5 | Extracting and building archives (`.zip`, `.tar`, etc.). 6 | 7 | **NuGet package:** [ZeroInstall.Archives](https://www.nuget.org/packages/ZeroInstall.Archives/) 8 | -------------------------------------------------------------------------------- /src/Client/Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | ZeroInstall.Client 6 | ZeroInstall.Client 7 | Client for invoking Zero Install commands from within other applications 8 | https://dotnet.0install.net/md_client.html 9 | ..\..\artifacts\$(Configuration)\ 10 | net462;net472;net8.0;net9.0 11 | 12 | 13 | enable 14 | True 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Client/NoChangesException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Client; 5 | 6 | /// 7 | /// The operation was successful but resulted in no changes. 8 | /// 9 | internal class NoChangesException() 10 | : Exception("The operation was successful but resulted in no changes."); 11 | -------------------------------------------------------------------------------- /src/Client/TemporarilyUnavailableException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Client; 5 | 6 | /// 7 | /// Zero Install is temporarily unavailable. Try again in a few seconds. 8 | /// 9 | public class TemporarilyUnavailableException() 10 | : Exception("Zero Install is temporarily unavailable. Try again in a few seconds."); 11 | -------------------------------------------------------------------------------- /src/Client/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Client 3 | summary: *content 4 | --- 5 | for invoking Zero Install commands from within other applications. 6 | 7 | **NuGet package:** [ZeroInstall.Client](https://www.nuget.org/packages/ZeroInstall.Client/) 8 | -------------------------------------------------------------------------------- /src/Commands/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.List.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.Configuration; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | partial class CatalogMan 9 | { 10 | private class List(ICommandHandler handler) : CatalogSubCommand(handler) 11 | { 12 | public const string Name = "list"; 13 | public override string Description => Resources.DescriptionCatalogList; 14 | public override string Usage => ""; 15 | protected override int AdditionalArgsMax => 0; 16 | 17 | public override ExitCode Execute() 18 | { 19 | if (Handler.IsGui) ShowConfig(ConfigTab.Catalog); 20 | else Handler.Output(Resources.CatalogSources, CatalogManager.GetSources()); 21 | return ExitCode.OK; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.Refresh.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands.Basic; 5 | 6 | partial class CatalogMan 7 | { 8 | private class Refresh(ICommandHandler handler) : CatalogSubCommand(handler) 9 | { 10 | public const string Name = "refresh"; 11 | public override string Description => Resources.DescriptionCatalogRefresh; 12 | public override string Usage => ""; 13 | protected override int AdditionalArgsMax => 0; 14 | 15 | public override ExitCode Execute() 16 | { 17 | CatalogManager.GetOnline(); 18 | return ExitCode.OK; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.Remove.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands.Basic; 5 | 6 | partial class CatalogMan 7 | { 8 | private class Remove(ICommandHandler handler) : CatalogSubCommand(handler) 9 | { 10 | public const string Name = "remove"; 11 | public override string Description => Resources.DescriptionCatalogRemove; 12 | public override string Usage => "URI"; 13 | protected override int AdditionalArgsMin => 1; 14 | protected override int AdditionalArgsMax => 1; 15 | 16 | public override ExitCode Execute() 17 | { 18 | var uri = new FeedUri(AdditionalArgs[0]); 19 | 20 | if (CatalogManager.RemoveSource(uri)) 21 | return ExitCode.OK; 22 | else 23 | { 24 | Handler.OutputLow(Resources.CatalogSources, string.Format(Resources.CatalogNotRegistered, uri.ToStringRfc())); 25 | return ExitCode.NoChanges; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.Reset.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Services.Feeds; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | partial class CatalogMan 9 | { 10 | private class Reset(ICommandHandler handler) : CatalogSubCommand(handler) 11 | { 12 | public const string Name = "reset"; 13 | public override string Description => Resources.DescriptionCatalogReset; 14 | public override string Usage => ""; 15 | protected override int AdditionalArgsMax => 0; 16 | 17 | public override ExitCode Execute() 18 | { 19 | Services.Feeds.CatalogManager.SetSources([Services.Feeds.CatalogManager.DefaultSource]); 20 | CatalogManager.TryGetOnline(); 21 | return ExitCode.OK; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.Search.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Services.Feeds; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | partial class CatalogMan 9 | { 10 | private class Search(ICommandHandler handler) : CatalogSubCommand(handler) 11 | { 12 | public const string Name = "search"; 13 | public override string Description => Resources.DescriptionCatalogSearch; 14 | public override string Usage => "[QUERY]"; 15 | 16 | public override ExitCode Execute() 17 | { 18 | Handler.Output( 19 | Resources.AppList, 20 | CatalogManager.Get().Search(query: AdditionalArgs.JoinEscapeArguments())); 21 | return ExitCode.OK; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Commands/Basic/CatalogMan.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Services.Feeds; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// Manages the s provided by the . 10 | /// 11 | public sealed partial class CatalogMan(ICommandHandler handler) : CliMultiCommand(handler) 12 | { 13 | public const string Name = "catalog"; 14 | 15 | /// 16 | public override IEnumerable SubCommandNames => [Search.Name, Refresh.Name, Add.Name, Remove.Name, Reset.Name, List.Name]; 17 | 18 | /// 19 | public override CliCommand GetCommand(string commandName) 20 | => (commandName ?? throw new ArgumentNullException(nameof(commandName))) switch 21 | { 22 | Search.Name => new Search(Handler), 23 | Refresh.Name => new Refresh(Handler), 24 | Add.Name => new Add(Handler), 25 | Remove.Name => new Remove(Handler), 26 | Reset.Name => new Reset(Handler), 27 | List.Name => new List(Handler), 28 | _ => throw new OptionException(string.Format(Resources.UnknownCommand, commandName), commandName) 29 | }; 30 | 31 | private abstract class CatalogSubCommand(ICommandHandler handler) : CliCommand(handler), ICliSubCommand 32 | { 33 | public string ParentName => Name; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Commands/Basic/ExportHelp.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Commands.Basic.Exporters; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// Exports all help texts as HTML. 10 | /// 11 | public class ExportHelp(ICommandHandler handler) : CliCommand(handler) 12 | { 13 | public const string Name = "export-help"; 14 | public override string Description => "Exports all command help texts as HTML."; 15 | public override string Usage => ""; 16 | protected override int AdditionalArgsMax => 0; 17 | 18 | public override ExitCode Execute() 19 | { 20 | Handler.Output("Zero Install HTML Help Export", new HtmlHelpExporter().ToString()); 21 | return ExitCode.OK; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Commands/Basic/Exporters/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Commands.Basic.Exporters 3 | summary: *content 4 | --- 5 | Utilitiy classes for exporting data from Zero Install. 6 | -------------------------------------------------------------------------------- /src/Commands/Basic/Exporters/import.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | FOR %%A IN ("%~dp0content\*.xml") DO 0install import --batch "%%A" 4 | 5 | FOR %%A IN ("%~dp0content\*.tgz") DO 0install store add --batch %%~nA "%%A" 6 | 7 | mkdir %appdata%\0install.net\desktop-integration\icons 8 | copy /y *.ico %appdata%\0install.net\desktop-integration\icons\ 9 | copy /y *.png %appdata%\0install.net\desktop-integration\icons\ 10 | -------------------------------------------------------------------------------- /src/Commands/Basic/Exporters/import.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | shopt -s nullglob 4 | 5 | cd $(dirname $0)/content 6 | for f in *.xml; do 0install import "$f"; done 7 | for f in *.tgz; do 0install store add "$(basename "$f" .tgz)" "$f"; done 8 | -------------------------------------------------------------------------------- /src/Commands/Basic/Fetch.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands.Basic; 5 | 6 | /// 7 | /// Downloads a set of s piped in as XML via stdin (for programmatic use). Use format with no inner linebreaks and terminated by a single linebreak. 8 | /// 9 | public class Fetch : CliCommand 10 | { 11 | public const string Name = "fetch"; 12 | public override string Description => "Downloads a set of implementations piped in as XML via stdin (for programmatic use). Use Feed format with no inner linebreaks and terminated by a single linebreak."; 13 | public override string Usage => ""; 14 | protected override int AdditionalArgsMax => 0; 15 | 16 | /// 17 | public Fetch(ICommandHandler handler) 18 | : base(handler) 19 | { 20 | AddDiscoverOptions(); 21 | } 22 | 23 | /// 24 | public override ExitCode Execute() 25 | { 26 | if (Console.ReadLine() is not {Length: > 0} input) return ExitCode.InvalidData; 27 | Log.Debug($"Fetch input:\n{input}"); 28 | 29 | var feedFragment = XmlStorage.FromXmlString(input); 30 | feedFragment.Name = "dummy"; 31 | feedFragment.Normalize(); 32 | FetchAll(feedFragment.Implementations); 33 | 34 | return ExitCode.OK; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Commands/Basic/Import.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Services.Feeds; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// Import a feed from a local file, as if it had been downloaded from the network. 10 | /// 11 | /// This is useful when testing a feed file, to avoid uploading it to a remote server in order to download it again. The file must have a trusted digital signature, as when fetching from the network. 12 | public class Import(ICommandHandler handler) : CliCommand(handler) 13 | { 14 | public const string Name = "import"; 15 | public override string Description => Resources.DescriptionImport; 16 | public override string Usage => "FEED-FILE [...]"; 17 | protected override int AdditionalArgsMin => 1; 18 | 19 | /// 20 | public override ExitCode Execute() 21 | { 22 | foreach (var file in Paths.ResolveFiles(AdditionalArgs, "*.xml")) 23 | FeedManager.ImportFeed(file.FullName); 24 | 25 | return ExitCode.OK; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Commands/Basic/List.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.ViewModel; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// List all known interface (program) URIs. 10 | /// 11 | /// If a search term is given, only URIs containing that string are shown (case insensitive). 12 | public class List(ICommandHandler handler) : CliCommand(handler) 13 | { 14 | public const string Name = "list"; 15 | public override string Description => Resources.DescriptionList; 16 | public override string Usage => "[PATTERN]"; 17 | protected override int AdditionalArgsMax => 1; 18 | 19 | /// 20 | public override ExitCode Execute() 21 | { 22 | var feeds = new CacheNodeBuilder(Handler, FeedCache).Build().OfType(); 23 | if (AdditionalArgs is [var pattern]) 24 | feeds = feeds.Where(x => x.Uri.ToStringRfc().ContainsIgnoreCase(pattern) || x.Name.Contains(pattern)); 25 | 26 | Handler.Output(Resources.FeedsCached, feeds); 27 | return ExitCode.OK; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Commands/Basic/ListFeeds.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Preferences; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// List all known feed URIs for a specific interface. 10 | /// 11 | public class ListFeeds(ICommandHandler handler) : CliCommand(handler) 12 | { 13 | public const string Name = "list-feeds"; 14 | public override string Description => Resources.DescriptionListFeeds; 15 | public override string Usage => "[OPTIONS] URI"; 16 | protected override int AdditionalArgsMin => 1; 17 | protected override int AdditionalArgsMax => 1; 18 | 19 | /// 20 | public override ExitCode Execute() 21 | { 22 | var interfaceUri = GetCanonicalUri(AdditionalArgs[0]); 23 | var preferences = InterfacePreferences.LoadFor(interfaceUri); 24 | 25 | Handler.Output( 26 | string.Format(Resources.FeedsRegistered, interfaceUri), 27 | preferences.Feeds.Select(x => x.Source)); 28 | return ExitCode.OK; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Commands/Basic/Search.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.Feeds; 5 | 6 | namespace ZeroInstall.Commands.Basic; 7 | 8 | /// 9 | /// Searches for feeds indexed by the mirror server. 10 | /// 11 | public class Search(ICommandHandler handler) : CliCommand(handler) 12 | { 13 | public const string Name = "search"; 14 | public override string Description => Resources.DescriptionSearch; 15 | public override string Usage => "QUERY"; 16 | protected override int AdditionalArgsMin => (Handler is CliCommandHandler) ? 1 : 0; 17 | 18 | /// 19 | public override ExitCode Execute() 20 | { 21 | string keywords = string.Join(" ", AdditionalArgs); 22 | Handler.Output(keywords, SearchResults.Query(Config, keywords)); 23 | return ExitCode.OK; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Commands/Basic/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Commands.Basic 3 | summary: *content 4 | --- 5 | CLI commands for Zero Install's core features. 6 | -------------------------------------------------------------------------------- /src/Commands/Desktop/RepairApps.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.DesktopIntegration; 5 | using ZeroInstall.Services.Feeds; 6 | 7 | namespace ZeroInstall.Commands.Desktop; 8 | 9 | /// 10 | /// Reintegrate all applications in the into the desktop environment. 11 | /// 12 | public class RepairApps(ICommandHandler handler) : IntegrationCommand(handler) 13 | { 14 | public const string Name = "repair-all"; 15 | public const string AltName = "repair-apps"; 16 | public override string Description => Resources.DescriptionRepairApps; 17 | public override string Usage => "[OPTIONS]"; 18 | protected override int AdditionalArgsMax => 0; 19 | 20 | /// 21 | public override ExitCode Execute() 22 | { 23 | CheckInstallBase(); 24 | 25 | using var integrationManager = new IntegrationManager(Config, Handler, MachineWide); 26 | integrationManager.Repair(FeedManager.GetFresh); 27 | 28 | return ExitCode.OK; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Commands/Desktop/Self.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands.Desktop; 5 | 6 | /// 7 | /// Manages the integration of Zero Install itself in the operating system (deployment and removal). 8 | /// 9 | public sealed partial class Self(ICommandHandler handler) : CliMultiCommand(handler) 10 | { 11 | public const string Name = "self"; 12 | public const string AltName = "maintenance"; 13 | 14 | /// 15 | public override IEnumerable SubCommandNames => [Deploy.Name, Remove.Name, Update.Name]; 16 | 17 | /// 18 | public override CliCommand GetCommand(string commandName) 19 | => (commandName ?? throw new ArgumentNullException(nameof(commandName))) switch 20 | { 21 | Deploy.Name => new Deploy(Handler), 22 | Remove.Name => new Remove(Handler), 23 | RemoveHelper.Name => new RemoveHelper(Handler), 24 | Update.Name => new Update(Handler), 25 | _ => throw new OptionException(string.Format(Resources.UnknownCommand, commandName), commandName) 26 | }; 27 | 28 | public abstract class SelfSubCommand(ICommandHandler handler) : CliCommand(handler), ICliSubCommand 29 | { 30 | public string ParentName => Name; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Commands/Desktop/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Commands.Desktop 3 | summary: *content 4 | --- 5 | CLI commands for Zero Install's [desktop integration](xref:ZeroInstall.DesktopIntegration) features. 6 | -------------------------------------------------------------------------------- /src/Commands/ICliSubCommand.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands; 5 | 6 | /// 7 | /// Interface for s that are aggregated by a . 8 | /// 9 | public interface ICliSubCommand 10 | { 11 | /// 12 | /// The name of the this command is a sub-command of. 13 | /// 14 | [Localizable(false)] 15 | string ParentName { get; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Commands/NeedsGuiException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.Commands; 9 | 10 | /// 11 | /// Indicates that the requested operation requires a GUI but the current process does not have one. 12 | /// 13 | #if !NET 14 | [Serializable] 15 | #endif 16 | public class NeedsGuiException : NotSupportedException 17 | { 18 | /// 19 | public NeedsGuiException() 20 | : this(Resources.NeedsGui) 21 | {} 22 | 23 | /// 24 | public NeedsGuiException(string message, Exception inner) 25 | : base(message, inner) 26 | {} 27 | 28 | /// 29 | public NeedsGuiException(string message) 30 | : base(message) 31 | {} 32 | 33 | #if !NET 34 | /// 35 | protected NeedsGuiException(SerializationInfo info, StreamingContext context) 36 | : base(info, context) 37 | {} 38 | #endif 39 | } 40 | -------------------------------------------------------------------------------- /src/Commands/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Commands; 5 | 6 | ProgramUtils.Init(); 7 | 8 | using var handler = new CliCommandHandler(); 9 | return (int)ProgramUtils.Run("0install", args, handler); 10 | -------------------------------------------------------------------------------- /src/Commands/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Commands": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /src/Commands/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Commands 3 | summary: *content 4 | --- 5 | for Zero Install. Both an actual CLI and a library for building other clients. 6 | 7 | **NuGet package:** [ZeroInstall.Commands](https://www.nuget.org/packages/ZeroInstall.Commands/) 8 | -------------------------------------------------------------------------------- /src/Commands/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | true 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Commands/net472.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %(FileName)%(Extension) 8 | Always 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Commands/net8.0.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %(FileName)%(Extension) 8 | Always 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Commands/net9.0.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %(FileName)%(Extension) 8 | Always 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/DesktopIntegration/AccessPoints/DefaultAccessPoint.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.AccessPoints; 5 | 6 | /// 7 | /// Makes an application the default handler for something. 8 | /// 9 | /// 10 | [XmlType(TagName, Namespace = AppList.XmlNamespace)] 11 | [Equatable] 12 | public abstract partial class DefaultAccessPoint : AccessPoint 13 | { 14 | public const string TagName = "default-access-point", AltName = "default-app"; 15 | 16 | /// 17 | /// The ID of the to be made the default handler. 18 | /// 19 | [Description("The ID of the Capability to be made the default handler.")] 20 | [XmlAttribute("capability")] 21 | public required string Capability { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /src/DesktopIntegration/AccessPoints/IconAccessPoint.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.AccessPoints; 5 | 6 | /// 7 | /// Creates some form of icon in the desktop environment. 8 | /// 9 | [XmlType("icon-access-point", Namespace = AppList.XmlNamespace)] 10 | public abstract class IconAccessPoint : CommandAccessPoint; 11 | -------------------------------------------------------------------------------- /src/DesktopIntegration/AccessPoints/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.DesktopIntegration.AccessPoints 3 | summary: *content 4 | --- 5 | Structures for parsing and in-memory representation of access points applied to a system. 6 | -------------------------------------------------------------------------------- /src/DesktopIntegration/CapabilityExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | 5 | namespace ZeroInstall.DesktopIntegration; 6 | 7 | /// 8 | /// Contains extension methods for s. 9 | /// 10 | public static class CapabilityExtensions 11 | { 12 | /// 13 | /// Creates a referencing a specific . 14 | /// 15 | /// The to create a for. 16 | /// The newly created . 17 | public static AccessPoints.AccessPoint ToAccessPoint(this DefaultCapability capability) 18 | => (capability ?? throw new ArgumentNullException(nameof(capability))) switch 19 | { 20 | AutoPlay x => new AccessPoints.AutoPlay {Capability = x.ID}, 21 | ContextMenu x => new AccessPoints.ContextMenu {Capability = x.ID}, 22 | DefaultProgram x => new AccessPoints.DefaultProgram {Capability = x.ID}, 23 | FileType x => new AccessPoints.FileType {Capability = x.ID}, 24 | UrlProtocol x => new AccessPoints.UrlProtocol {Capability = x.ID}, 25 | _ => throw new NotSupportedException($"Unknown capability: {capability}") 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ConflictData.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.DesktopIntegration.AccessPoints; 5 | 6 | namespace ZeroInstall.DesktopIntegration; 7 | 8 | /// 9 | /// Stores information about an causing a conflict and the containing it. 10 | /// 11 | /// The causing the conflict. 12 | /// The application containing the . 13 | public sealed record ConflictData(AccessPoint AccessPoint, AppEntry AppEntry); -------------------------------------------------------------------------------- /src/DesktopIntegration/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click 8 | // "In Project Suppression File". 9 | // You do not need to add suppressions to this file manually. 10 | -------------------------------------------------------------------------------- /src/DesktopIntegration/SyncRaceException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.DesktopIntegration; 9 | 10 | /// 11 | /// Multiple computers are trying to sync with the same account at the same time. 12 | /// 13 | #if !NET 14 | [Serializable] 15 | #endif 16 | public class SyncRaceException : WebException 17 | { 18 | public SyncRaceException() 19 | : base("Multiple computers are trying to sync with the same account at the same time.") 20 | {} 21 | 22 | #if !NET 23 | protected SyncRaceException(SerializationInfo serializationInfo, StreamingContext streamingContext) 24 | : base(serializationInfo, streamingContext) 25 | {} 26 | #endif 27 | } 28 | -------------------------------------------------------------------------------- /src/DesktopIntegration/SyncResetMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration; 5 | 6 | /// 7 | /// Controls how synchronization data is reset by 8 | /// 9 | public enum SyncResetMode 10 | { 11 | /// Merge data from client and server normally. 12 | None, 13 | 14 | /// Replace all data on the client with data from the server. 15 | Client, 16 | 17 | /// Replace all data on the server with data from the client. 18 | Server 19 | } 20 | -------------------------------------------------------------------------------- /src/DesktopIntegration/Unix/FreeDesktop.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.DesktopIntegration.AccessPoints; 5 | 6 | namespace ZeroInstall.DesktopIntegration.Unix; 7 | 8 | /// 9 | /// Utility class for creating and modifying FreeDesktop.org Desktop Entries. 10 | /// 11 | public static class FreeDesktop 12 | { 13 | public static void Create(MenuEntry menuEntry, FeedTarget target, IIconStore iconStore, bool machineWide) => throw new NotImplementedException(); 14 | 15 | public static void Remove(MenuEntry menuEntry, bool machineWide) => throw new NotImplementedException(); 16 | 17 | public static void Create(DesktopIcon desktopIcon, FeedTarget target, IIconStore iconStore, bool machineWide) => throw new NotImplementedException(); 18 | 19 | public static void Remove(DesktopIcon desktopIcon, bool machineWide) => throw new NotImplementedException(); 20 | } 21 | -------------------------------------------------------------------------------- /src/DesktopIntegration/Unix/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.DesktopIntegration.Unix 3 | summary: *content 4 | --- 5 | Desktop integration code for Unix-like systems (e.g. Linux). 6 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/AutoPlayModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps a for data binding. 8 | /// 9 | public class AutoPlayModel : IconCapabilityModel 10 | { 11 | private readonly AutoPlay _autoPlay; 12 | 13 | /// 14 | /// All concatenated with ", ". 15 | /// 16 | public string Events => string.Join(", ", _autoPlay.Events.Select(x => x.Name)); 17 | 18 | /// 19 | public AutoPlayModel(AutoPlay capability, bool used) 20 | : base(capability, used) 21 | { 22 | _autoPlay = capability; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/CapabilityModelExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Contains extension methods for s. 8 | /// 9 | public static class CapabilityModelExtensions 10 | { 11 | /// 12 | /// Sets all values within a list/model to a specific value. 13 | /// 14 | /// The specific kind of to handle. 15 | /// A model representing the underlying s and their selection states. 16 | /// The value to set. 17 | public static void SetAllUse<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(this BindingList model, bool value) 18 | where T : CapabilityModel 19 | { 20 | #region Sanity checks 21 | if (model == null) throw new ArgumentNullException(nameof(model)); 22 | #endregion 23 | 24 | foreach (var element in model.Except(element => element.Capability.ExplicitOnly)) 25 | element.Use = value; 26 | model.ResetBindings(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/ContextMenuModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps a for data binding. 8 | /// 9 | public class ContextMenuModel : IconCapabilityModel 10 | { 11 | private readonly ContextMenu _contextMenu; 12 | 13 | /// 14 | /// The name of the first entry in . 15 | /// 16 | public string? Name 17 | { 18 | get 19 | { 20 | var verb = _contextMenu.Verbs.FirstOrDefault(); 21 | return verb?.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture) 22 | ?? verb?.Name; 23 | } 24 | } 25 | 26 | /// 27 | public ContextMenuModel(ContextMenu contextMenu, bool used) 28 | : base(contextMenu, used) 29 | { 30 | _contextMenu = contextMenu; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/DefaultProgramModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps a for data binding. 8 | /// 9 | public class DefaultProgramModel : IconCapabilityModel 10 | { 11 | private readonly DefaultProgram _defaultProgram; 12 | 13 | /// 14 | /// Returns . 15 | /// 16 | public string Service => _defaultProgram.Service; 17 | 18 | /// 19 | public DefaultProgramModel(DefaultProgram capability, bool used) 20 | : base(capability, used) 21 | { 22 | _defaultProgram = capability; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/FileTypeModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps a for data binding. 8 | /// 9 | public class FileTypeModel : IconCapabilityModel 10 | { 11 | private readonly FileType _fileType; 12 | 13 | /// 14 | /// All concatenated with ", ". 15 | /// 16 | public string Extensions => string.Join(", ", _fileType.Extensions.Select(extension => extension.Value)); 17 | 18 | /// 19 | public FileTypeModel(FileType fileType, bool used) 20 | : base(fileType, used) 21 | { 22 | _fileType = fileType; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/IconCapabilityModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps an for data binding. 8 | /// 9 | public class IconCapabilityModel : CapabilityModel 10 | { 11 | private readonly IconCapability _iconCapability; 12 | 13 | /// 14 | /// Returns the description of the dependant on . 15 | /// 16 | public string Description 17 | => _iconCapability.Descriptions.GetBestLanguage(CultureInfo.CurrentUICulture) 18 | ?? _iconCapability.ID; 19 | 20 | /// 21 | protected IconCapabilityModel(IconCapability capability, bool used) 22 | : base(capability, used) 23 | { 24 | _iconCapability = capability; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/UrlProtocolModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.ViewModel; 5 | 6 | /// 7 | /// Wraps a for data binding. 8 | /// 9 | public class UrlProtocolModel : IconCapabilityModel 10 | { 11 | private readonly UrlProtocol _urlProtocol; 12 | 13 | /// 14 | /// All concatenated with ", ". If no is available will be returned. 15 | /// 16 | public string KnownPrefixes 17 | => _urlProtocol.KnownPrefixes is [] 18 | ? Capability.ID 19 | : string.Join(", ", _urlProtocol.KnownPrefixes.Select(extension => extension.Value)); 20 | 21 | /// 22 | public UrlProtocolModel(UrlProtocol capability, bool used) 23 | : base(capability, used) 24 | { 25 | _urlProtocol = capability; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DesktopIntegration/ViewModel/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.DesktopIntegration.ViewModel 3 | summary: *content 4 | --- 5 | Classes that wrap desktop integration capabilities in a data binding-friendly manner. 6 | -------------------------------------------------------------------------------- /src/DesktopIntegration/Windows/Stub.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/DesktopIntegration/Windows/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.DesktopIntegration.Windows 3 | summary: *content 4 | --- 5 | Windows-specific desktop integration code. 6 | -------------------------------------------------------------------------------- /src/DesktopIntegration/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.DesktopIntegration 3 | summary: *content 4 | --- 5 | Integrating applications with [desktop environments](https://docs.0install.net/details/desktop-integration/) (creating menu entries, etc.). 6 | 7 | **NuGet package:** [ZeroInstall.DesktopIntegration](https://www.nuget.org/packages/ZeroInstall.DesktopIntegration/) 8 | -------------------------------------------------------------------------------- /src/Model/ArgBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Design; 5 | 6 | namespace ZeroInstall.Model; 7 | 8 | /// 9 | /// Common base class for and . 10 | /// 11 | [TypeConverter(typeof(ArgBaseConverter))] 12 | [XmlType("arg-base", Namespace = Feed.XmlNamespace)] 13 | public abstract class ArgBase : FeedElement, ICloneable 14 | { 15 | /// 16 | /// Converts legacy elements, sets default values, etc.. 17 | /// 18 | /// A required property is not set or invalid. 19 | public abstract void Normalize(); 20 | 21 | /// 22 | /// Creates a deep copy of this instance. 23 | /// 24 | /// The new copy of the . 25 | public abstract ArgBase Clone(); 26 | 27 | /// 28 | /// Convenience cast for turning strings into plain s. 29 | /// 30 | public static implicit operator ArgBase(string value) => new Arg {Value = value}; 31 | } 32 | -------------------------------------------------------------------------------- /src/Model/Binding.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Bindings specify how the chosen implementation is made known to the running program. 8 | /// 9 | /// 10 | /// Bindings can appear in s, in which case they tell a component how to find its dependency, 11 | /// or in , where they tell a component how to find itself. 12 | /// 13 | [XmlType("binding-base", Namespace = Feed.XmlNamespace)] 14 | public abstract class Binding : FeedElement, ICloneable 15 | { 16 | /// 17 | /// Creates a deep copy of this instance. 18 | /// 19 | /// The new copy of the . 20 | public abstract Binding Clone(); 21 | 22 | /// 23 | /// Converts legacy elements, sets default values, etc.. 24 | /// 25 | /// A required property is not set or invalid. 26 | public virtual void Normalize() 27 | {} 28 | } 29 | -------------------------------------------------------------------------------- /src/Model/Capabilities/CapabilityListExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Capabilities; 5 | 6 | /// 7 | /// Contains extension methods for s. 8 | /// 9 | public static class CapabilityListExtensions 10 | { 11 | /// 12 | /// Flattens a set of s into a single stream of s, filtering out es that do not match . 13 | /// 14 | [LinqTunnel] 15 | public static IEnumerable CompatibleCapabilities(this IEnumerable capabilityLists) 16 | => capabilityLists.Where(x => x.OS.RunsOn(Architecture.CurrentSystem.OS)) 17 | .SelectMany(x => x.Entries); 18 | } 19 | -------------------------------------------------------------------------------- /src/Model/Capabilities/ComServer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Capabilities; 5 | 6 | /// 7 | /// An application's ability to act as a COM server. 8 | /// 9 | [Description("An application's ability to act as a COM server.")] 10 | [Serializable, XmlRoot("com-server", Namespace = CapabilityList.XmlNamespace), XmlType("com-server", Namespace = CapabilityList.XmlNamespace)] 11 | [Equatable] 12 | public sealed partial class ComServer : Capability 13 | { 14 | /// 15 | [Browsable(false), XmlIgnore, IgnoreEquality] 16 | public override IEnumerable ConflictIDs => [$"classes:{ID}"]; 17 | 18 | #region Conversion 19 | /// 20 | /// Returns the capability in the form "-". Not safe for parsing! 21 | /// 22 | public override string ToString() => "-"; 23 | #endregion 24 | 25 | #region Clone 26 | /// 27 | public override Capability Clone() => new ComServer {UnknownAttributes = UnknownAttributes, UnknownElements = UnknownElements, ID = ID}; 28 | #endregion 29 | } 30 | -------------------------------------------------------------------------------- /src/Model/Capabilities/DefaultCapability.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Capabilities; 5 | 6 | /// 7 | /// Abstract base class for capabilities that can be applied as default handlers for something at the user's request. 8 | /// 9 | [XmlType("default-capability", Namespace = CapabilityList.XmlNamespace)] 10 | [Equatable] 11 | public abstract partial class DefaultCapability : Capability 12 | { 13 | /// 14 | /// When set to true this capability is not applied as a default handler without explicit confirmation from the user. 15 | /// 16 | /// Use this to exclude exotic capabilities from default integration categories. 17 | [Description("When set to true this capability is not applied as a default handler without explicit confirmation from the user. Use this to exclude exotic capabilities from default integration categories.")] 18 | [XmlAttribute("explicit-only"), DefaultValue(false)] 19 | public bool ExplicitOnly { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /src/Model/Capabilities/VerbCapability.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Capabilities; 5 | 6 | /// 7 | /// Abstract base class for capabilities that can have multiple s. 8 | /// 9 | [XmlType("verb-capability", Namespace = CapabilityList.XmlNamespace)] 10 | [Equatable] 11 | public abstract partial class VerbCapability : IconCapability 12 | { 13 | /// 14 | /// A list of all available operations for the element. 15 | /// 16 | [Browsable(false)] 17 | [XmlElement("verb")] 18 | [OrderedEquality] 19 | public List Verbs { get; } = []; 20 | 21 | #region Normalize 22 | /// 23 | public override void Normalize() 24 | { 25 | base.Normalize(); 26 | foreach (var verb in Verbs) verb.Normalize(); 27 | } 28 | #endregion 29 | } 30 | -------------------------------------------------------------------------------- /src/Model/Capabilities/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Model.Capabilities 3 | summary: *content 4 | --- 5 | Extends the feed format with structures for describing [application capabilities](https://docs.0install.net/specifications/capabilities/). This forms the basis for [desktop integration](xref:ZeroInstall.DesktopIntegration). 6 | -------------------------------------------------------------------------------- /src/Model/DependencyContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Provides extension methods for . 8 | /// 9 | public static class DependencyContainerExtensions 10 | { 11 | /// 12 | /// A combination of and . 13 | /// 14 | public static IEnumerable GetEffectiveRestrictions(this IDependencyContainer container) 15 | => [..container.Restrictions, ..container.Dependencies]; 16 | } 17 | -------------------------------------------------------------------------------- /src/Model/Design/ArchiveMimeTypeConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | internal class ArchiveMimeTypeConverter : StringConverter 7 | { 8 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 9 | 10 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 11 | 12 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(Archive.KnownMimeTypes.ToList()); 13 | } 14 | -------------------------------------------------------------------------------- /src/Model/Design/ArgBaseConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | /// 7 | /// Converts s to s and s/ to s. 8 | /// 9 | public class ArgBaseConverter : TypeConverter 10 | { 11 | /// 12 | public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) 13 | => (sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType); 14 | 15 | /// 16 | // ReSharper disable once NullnessAnnotationConflictWithJetBrainsAnnotations 17 | public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) 18 | => (value is string stringValue) 19 | ? new Arg {Value = stringValue} 20 | : base.ConvertFrom(context!, culture!, value); 21 | 22 | /// 23 | public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) 24 | { 25 | if (value != null && destinationType == typeof(string)) return value.ToString(); 26 | return base.ConvertTo(context, culture, value, destinationType); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Model/Design/CategoryNameConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | public class CategoryNameConverter : StringConverter 7 | { 8 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 9 | 10 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 11 | 12 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(Category.WellKnownNames); 13 | } 14 | -------------------------------------------------------------------------------- /src/Model/Design/CommandNameConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | /// 7 | /// Suggests canonical s. 8 | /// 9 | internal class CommandNameConverter : StringConverter 10 | { 11 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 12 | 13 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 14 | 15 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(new[] 16 | { 17 | Command.NameRun, 18 | Command.NameRunGui, 19 | Command.NameTest, 20 | Command.NameCompile 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /src/Model/Design/DistributionNameConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | internal class DistributionNameConverter : StringConverter 7 | { 8 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 9 | 10 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 11 | 12 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(PackageImplementation.DistributionNames); 13 | } 14 | -------------------------------------------------------------------------------- /src/Model/Design/IconMimeTypeConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Design; 5 | 6 | internal class IconMimeTypeConverter : StringConverter 7 | { 8 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 9 | 10 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 11 | 12 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(Icon.KnownMimeTypes); 13 | } 14 | -------------------------------------------------------------------------------- /src/Model/Design/VerbNameConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Capabilities; 5 | 6 | namespace ZeroInstall.Model.Design; 7 | 8 | /// 9 | /// Suggests canonical s. 10 | /// 11 | internal class VerbNameConverter : StringConverter 12 | { 13 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 14 | 15 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 16 | 17 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(new[] {Verb.NameOpen, Verb.NameOpenNew, Verb.NameOpenAs, Verb.NameEdit, Verb.NamePlay, Verb.NamePrint, Verb.NamePreview}); 18 | } 19 | -------------------------------------------------------------------------------- /src/Model/Design/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Model.Design 3 | summary: *content 4 | --- 5 | s used for serialization and to provide a better runtime experience when using PropertyGrids. 6 | -------------------------------------------------------------------------------- /src/Model/ElementCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Provides extension methods for collections. 8 | /// 9 | public static class ElementCollectionExtensions 10 | { 11 | /// 12 | /// Returns a flat list of all s. 13 | /// 14 | public static IEnumerable GetImplementations(this IReadOnlyCollection elements) 15 | => elements.OfType() 16 | .Concat(elements.OfType().SelectMany(x => x.Elements.GetImplementations())); 17 | 18 | /// 19 | /// Removes an identified by its ID. 20 | /// 21 | /// true if the implementation was removed; false if the implementation could not be found. 22 | public static bool RemoveImplementation(this ICollection elements, string id) 23 | => elements.RemoveAll(x => x is Implementation implementation && implementation.ID == id) 24 | || elements.OfType().Any(group => @group.Elements.RemoveImplementation(id)); 25 | } 26 | -------------------------------------------------------------------------------- /src/Model/ExecutableInBinding.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Design; 5 | 6 | namespace ZeroInstall.Model; 7 | 8 | /// 9 | /// Make a chosen available as an executable at runtime. 10 | /// 11 | [XmlType("executable-in-binding", Namespace = Feed.XmlNamespace)] 12 | [Equatable] 13 | public abstract partial class ExecutableInBinding : Binding 14 | { 15 | /// 16 | /// The name of the in the to launch; leave null for . 17 | /// 18 | [Description("The name of the command in the implementation to launch; leave empty for 'run'.")] 19 | [TypeConverter(typeof(CommandNameConverter))] 20 | [XmlAttribute("command"), DefaultValue("")] 21 | public string? Command { get; set; } 22 | } 23 | -------------------------------------------------------------------------------- /src/Model/FeedTarget.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Associates a with the data acquired from there. 8 | /// 9 | /// The URI or local path (must be absolute) to the feed. 10 | /// The data acquired from . has already been called. 11 | public readonly record struct FeedTarget(FeedUri Uri, Feed Feed) 12 | { 13 | public override string ToString() => Uri.ToStringRfc(); 14 | } 15 | -------------------------------------------------------------------------------- /src/Model/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | // 6 | // To add a suppression to this file, right-click the message in the 7 | // Error List, point to "Suppress Message(s)", and click 8 | // "In Project Suppression File". 9 | // You do not need to add suppressions to this file manually. 10 | 11 | using System.Diagnostics.CodeAnalysis; 12 | 13 | [assembly: SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance", Scope = "type", Target = "ZeroInstall.Model.Capabilities.DefaultProgram")] 14 | [assembly: SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance", Scope = "type", Target = "ZeroInstall.Model.Capabilities.FileType")] 15 | [assembly: SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance", Scope = "type", Target = "ZeroInstall.Model.Capabilities.UrlProtocol")] 16 | -------------------------------------------------------------------------------- /src/Model/IArgBaseContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains s. 8 | /// 9 | public interface IArgBaseContainer 10 | { 11 | /// 12 | /// A list of command-line arguments to be passed to an executable. 13 | /// 14 | [XmlElement(typeof(Arg)), XmlElement(typeof(ForEachArgs))] 15 | List Arguments { get; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Model/IBindingContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains s. 8 | /// 9 | public interface IBindingContainer 10 | { 11 | /// 12 | /// A list of s for s to locate s. 13 | /// 14 | [XmlElement(typeof(GenericBinding)), XmlElement(typeof(EnvironmentBinding)), XmlElement(typeof(OverlayBinding)), XmlElement(typeof(ExecutableInVar)), XmlElement(typeof(ExecutableInPath))] 15 | List Bindings { get; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Model/IDependencyContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains s and s. 8 | /// 9 | public interface IDependencyContainer 10 | { 11 | /// 12 | /// A list of interfaces this implementation depends upon. 13 | /// 14 | [XmlElement("requires")] 15 | List Dependencies { get; } 16 | 17 | /// 18 | /// A list of interfaces that are restricted to specific versions when used. 19 | /// 20 | [XmlElement("restricts")] 21 | List Restrictions { get; } 22 | } 23 | -------------------------------------------------------------------------------- /src/Model/IDescriptionContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that has localizable descriptions. 8 | /// 9 | public interface IDescriptionContainer 10 | { 11 | /// 12 | /// Full descriptions for different languages, which can be several paragraphs long. 13 | /// 14 | [Browsable(false)] 15 | [XmlElement("description")] 16 | LocalizableStringCollection Descriptions { get; } 17 | } 18 | -------------------------------------------------------------------------------- /src/Model/IElementContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains s and s. Supports a composite pattern. 8 | /// 9 | public interface IElementContainer 10 | { 11 | /// 12 | /// A list of s and s contained within this element. 13 | /// 14 | [XmlElement(typeof(Implementation)), XmlElement(typeof(PackageImplementation)), XmlElement(typeof(Group))] 15 | List Elements { get; } 16 | } 17 | -------------------------------------------------------------------------------- /src/Model/IIconContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains s. 8 | /// 9 | public interface IIconContainer 10 | { 11 | /// 12 | /// Zero or more icons. 13 | /// 14 | [Browsable(false)] 15 | [XmlElement("icon")] 16 | List Icons { get; } 17 | } 18 | -------------------------------------------------------------------------------- /src/Model/IInterfaceUri.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains an interface URI. 8 | /// 9 | public interface IInterfaceUri 10 | { 11 | /// 12 | /// An interface URI (URL or file path). 13 | /// 14 | FeedUri InterfaceUri { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /src/Model/IInterfaceUriBindingContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that contains an interface URI string. 8 | /// 9 | public interface IInterfaceUriBindingContainer : IInterfaceUri, IBindingContainer; 10 | -------------------------------------------------------------------------------- /src/Model/IRecipeStep.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// A retrieval step is a part of a . 8 | /// 9 | public interface IRecipeStep : ICloneable 10 | { 11 | /// 12 | /// Converts legacy elements, sets default values, etc.. 13 | /// 14 | /// The feed the data was originally loaded from. 15 | /// is relative and is a remote URI. 16 | void Normalize(FeedUri? feedUri = null); 17 | } 18 | -------------------------------------------------------------------------------- /src/Model/ISummaryContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An object that has localizable summaries and descriptions. 8 | /// 9 | public interface ISummaryContainer : IDescriptionContainer 10 | { 11 | /// 12 | /// Short one-line descriptions for different languages; the first word should not be upper-case unless it is a proper noun (e.g. "cures all ills"). 13 | /// 14 | [Browsable(false)] 15 | [XmlElement("summary")] 16 | LocalizableStringCollection Summaries { get; } 17 | } 18 | -------------------------------------------------------------------------------- /src/Model/Preferences/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Model.Preferences 3 | summary: *content 4 | --- 5 | Structures for user-specified preferences and overrides for interfaces, feeds and implementations. 6 | -------------------------------------------------------------------------------- /src/Model/RetrievalMethod.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// A retrieval method is a way of getting a copy of an . 8 | /// 9 | [XmlType("retrieval-method", Namespace = Feed.XmlNamespace)] 10 | public abstract class RetrievalMethod : FeedElement, ICloneable 11 | { 12 | /// 13 | /// Sets missing default values and handles legacy elements. 14 | /// 15 | /// The feed the data was originally loaded from. 16 | /// is relative and is a remote URI. 17 | /// A required property is not set or invalid. 18 | public virtual void Normalize(FeedUri? feedUri = null) {} 19 | 20 | /// 21 | /// Creates a deep copy of this instance. 22 | /// 23 | /// The new copy of the . 24 | public abstract RetrievalMethod Clone(); 25 | } 26 | -------------------------------------------------------------------------------- /src/Model/Selection/SelectionCandidateExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Selection; 5 | 6 | /// 7 | /// Provides extension methods for . 8 | /// 9 | public static class SelectionCandidateExtensions 10 | { 11 | /// 12 | /// Returns a deduplicated list of suitable version numbers, sorted from newest to oldest. 13 | /// 14 | public static IEnumerable GetSuitableVersions(this IEnumerable candidates) 15 | => candidates.Where(x => x.IsSuitable) 16 | .Select(x => x.Version) 17 | .WhereNotNull() 18 | .Distinct() 19 | .OrderByDescending(x => x); 20 | } 21 | -------------------------------------------------------------------------------- /src/Model/Selection/TestCaseSet.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Selection; 5 | 6 | /// 7 | /// A set of test case describing and the they are expected to lead to. Used for automated testing of Solvers. 8 | /// 9 | [XmlRoot("test-cases", Namespace = Feed.XmlNamespace), XmlType("test-cases", Namespace = Feed.XmlNamespace)] 10 | [XmlNamespace("xsi", XmlStorage.XsiNamespace)] 11 | public class TestCaseSet 12 | { 13 | /// 14 | /// A list of input s for the solver. 15 | /// 16 | [XmlElement("test", typeof(TestCase), Namespace = Feed.XmlNamespace)] 17 | public List TestCases { get; } = []; 18 | } 19 | -------------------------------------------------------------------------------- /src/Model/Selection/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Model.Selection 3 | summary: *content 4 | --- 5 | Structures for representing [Solver results](https://docs.0install.net/specifications/selections/). 6 | -------------------------------------------------------------------------------- /src/Model/Trust/Domain.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Trust; 5 | 6 | /// 7 | /// A specific domain with feeds a is trusted to sign. 8 | /// 9 | /// A valid domain name (not a full !). 10 | [XmlType("domain", Namespace = TrustDB.XmlNamespace)] 11 | public record struct Domain([property: XmlAttribute("value")] string? Value = null) 12 | { 13 | /// 14 | public override string? ToString() => Value; 15 | } 16 | -------------------------------------------------------------------------------- /src/Model/Trust/DomainSet.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.Model.Trust; 9 | 10 | /// 11 | /// A set of alphabetically sorted s. 12 | /// 13 | [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "A Set is a specific type of Collection.")] 14 | 15 | #if !NET 16 | [Serializable] 17 | #endif 18 | public class DomainSet : SortedSet 19 | { 20 | public DomainSet() 21 | : base(new DomainComparer()) 22 | {} 23 | 24 | public Domain this[int index] => this.Skip(index).First(); 25 | 26 | #if !NET 27 | protected DomainSet(SerializationInfo info, StreamingContext context) 28 | : base(info, context) 29 | {} 30 | #endif 31 | private class DomainComparer : IComparer 32 | { 33 | public int Compare(Domain x, Domain y) => string.Compare(x.Value, y.Value, StringComparison.OrdinalIgnoreCase); 34 | } 35 | 36 | #region Conversion 37 | /// 38 | /// Returns the list of domains in the form "Domain1, Domain2, ...". Safe for parsing! 39 | /// 40 | public override string ToString() => string.Join(", ", this.Select(x => x.ToString()!)); 41 | #endregion 42 | } 43 | -------------------------------------------------------------------------------- /src/Model/Trust/Key.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model.Trust; 5 | 6 | /// 7 | /// A known OpenPGP key, trusted to sign feeds from a certain set of domains. 8 | /// 9 | [XmlType("key", Namespace = TrustDB.XmlNamespace)] 10 | [Equatable] 11 | public sealed partial class Key : ICloneable 12 | { 13 | /// 14 | /// The cryptographic fingerprint of this key. 15 | /// 16 | [XmlAttribute("fingerprint")] 17 | public string? Fingerprint { get; set; } 18 | 19 | /// 20 | /// A list of s this key is valid for. 21 | /// 22 | [XmlElement("domain")] 23 | [SetEquality] 24 | public DomainSet Domains { get; } = []; 25 | 26 | #region Conversion 27 | /// 28 | /// Returns the key in the form "Fingerprint: Domain1, Domain2, ...". Safe for parsing! 29 | /// 30 | public override string ToString() 31 | => $"{Fingerprint}: {Domains}"; 32 | #endregion 33 | 34 | #region Clone 35 | /// 36 | /// Creates a deep copy of this instance. 37 | /// 38 | /// The new copy of the . 39 | public Key Clone() => new() 40 | { 41 | Fingerprint = Fingerprint, 42 | Domains = {Domains} 43 | }; 44 | #endregion 45 | } 46 | -------------------------------------------------------------------------------- /src/Model/VersionModifier.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | public enum VersionModifier 8 | { 9 | /// No modifier; empty string 10 | None = 0, 11 | 12 | /// Pre-release 13 | Pre = -2, 14 | 15 | /// Release candidate 16 | RC = -1, 17 | 18 | /// Post-release 19 | Post = 1 20 | } 21 | -------------------------------------------------------------------------------- /src/Model/VersionRangePartExact.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// An exact version number like 2.0 as a part of a . 8 | /// 9 | /// The exact version to match. 10 | public sealed record VersionRangePartExact(ImplementationVersion Version) : VersionRangePart 11 | { 12 | /// 13 | public override IEnumerable Intersect(VersionRange versions) 14 | { 15 | #region Sanity checks 16 | if (versions == null) throw new ArgumentNullException(nameof(versions)); 17 | #endregion 18 | 19 | if (versions.Match(Version)) yield return this; 20 | } 21 | 22 | /// 23 | public override bool Match(ImplementationVersion version) => Version.Equals(version ?? throw new ArgumentNullException(nameof(version))); 24 | 25 | /// 26 | public override string ToString() => Version.ToString(); 27 | } 28 | -------------------------------------------------------------------------------- /src/Model/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Model 3 | summary: *content 4 | --- 5 | for the Zero Install [feed format](https://docs.0install.net/specifications/feed/). 6 | 7 | **NuGet package:** [ZeroInstall.Model](https://www.nuget.org/packages/ZeroInstall.Model/) 8 | -------------------------------------------------------------------------------- /src/Publish/Capture/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Publish.Capture 3 | summary: *content 4 | --- 5 | Builds feeds by creating and comparing snapshots of the system before and after an application was installed. 6 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/BashScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A script written in Perl. 8 | /// 9 | public sealed class BashScript : InterpretedScript 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | return 16 | StringUtils.EqualsIgnoreCase(file.Extension, @".sh") || 17 | HasShebang(file, "sh") || HasShebang(file, "bash"); 18 | } 19 | 20 | /// 21 | protected override FeedUri InterpreterInterface => new("https://apps.0install.net/utils/bash.xml"); 22 | } 23 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/Design/DotNetVersionConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Values.Design; 5 | 6 | namespace ZeroInstall.Publish.EntryPoints.Design; 7 | 8 | internal class DotNetVersionConverter : StringConstructorConverter 9 | { 10 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 11 | 12 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 13 | 14 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) 15 | => new(new[] {"", @"2.0", @"3.0", @"3.5", @"4.0", @"4.5", @"4.5.1", @"4.5.2", @"4.6", @"4.6.1", @"4.6.2", @"4.7", @"4.7.1", @"4.7.2", @"4.8"}); 16 | } 17 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/Design/JavaVersionConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Values.Design; 5 | 6 | namespace ZeroInstall.Publish.EntryPoints.Design; 7 | 8 | internal class JavaVersionConverter : StringConstructorConverter 9 | { 10 | public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true; 11 | 12 | public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false; 13 | 14 | public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(new[] {"", @"6.0", @"7.0", @"8.0"}); 15 | } 16 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/Design/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Publish.EntryPoints.Design 3 | summary: *content 4 | --- 5 | s used for serialization and to provide a better runtime experience when using s. 6 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/DotNetDll.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | [Equatable] 7 | public sealed partial class DotNetDll : DotNetExe 8 | { 9 | /// 10 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 11 | { 12 | if (!base.Analyze(baseDirectory, file)) return false; 13 | 14 | // Prefer extraction information from .exe instead of .dll, because it provides more details. 15 | if (File.Exists($"{file.FullName[..^4]}.exe")) return false; 16 | 17 | // GUI applications can only be started via .exe 18 | NeedsTerminal = true; 19 | 20 | return true; 21 | } 22 | 23 | protected override string ExecutableExtension => @".dll"; 24 | } 25 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/IIconContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Runtime.Versioning; 5 | 6 | namespace ZeroInstall.Publish.EntryPoints; 7 | 8 | /// 9 | /// An executable with embedded icons. 10 | /// 11 | public interface IIconContainer 12 | { 13 | /// 14 | /// Extracts the primary icon of the executable. 15 | /// 16 | [SupportedOSPlatform("windows")] 17 | System.Drawing.Icon ExtractIcon(); 18 | } 19 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/JavaClass.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A compiled Java class file. 8 | /// 9 | public sealed class JavaClass : Java 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | if (!StringUtils.EqualsIgnoreCase(file.Extension, @".class")) return false; 16 | 17 | Name = file.Name[..^file.Extension.Length]; 18 | GuiOnly = false; 19 | return true; 20 | } 21 | 22 | /// 23 | public override Command CreateCommand() => new() 24 | { 25 | Name = CommandName, 26 | Path = RelativePath, 27 | Runner = new() 28 | { 29 | InterfaceUri = new("https://apps.0install.net/java/jre.xml"), 30 | Command = NeedsTerminal ? Command.NameRun : Command.NameRunGui, 31 | Versions = ToVersionRange(MinimumRuntimeVersion) 32 | } 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/MacOSApp.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Diagnostics; 5 | 6 | namespace ZeroInstall.Publish.EntryPoints; 7 | 8 | /// 9 | /// A binary inside a MacOS X application bundle. 10 | /// 11 | public sealed class MacOSApp : PosixExecutable 12 | { 13 | /// 14 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 15 | { 16 | if (!base.Analyze(baseDirectory, file)) return false; 17 | Debug.Assert(RelativePath != null); 18 | 19 | if (!RelativePath.GetLeftPartAtLastOccurrence('/').EndsWith(@".app/Contents/MacOS")) return false; 20 | 21 | // TODO: Parse MacOS plist 22 | Name = file.Name[..^file.Extension.Length]; 23 | Architecture = new(OS.MacOSX); 24 | return true; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/NativeExecutable.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A file that can be executed directly by the operating system without an additional runtime environment. 8 | /// 9 | public abstract class NativeExecutable : Candidate 10 | { 11 | /// 12 | public override Command CreateCommand() => new() 13 | { 14 | Name = CommandName, 15 | Path = RelativePath 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/PerlScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A script written in Perl. 8 | /// 9 | public sealed class PerlScript : InterpretedScript 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | return 16 | StringUtils.EqualsIgnoreCase(file.Extension, @".pl") || 17 | HasShebang(file, "perl"); 18 | } 19 | 20 | /// 21 | protected override FeedUri InterpreterInterface => new("https://apps.0install.net/perl/perl.xml"); 22 | } 23 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/PhpScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A script written in PHP. 8 | /// 9 | public sealed class PhpScript : InterpretedScript 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | return 16 | file.Extension.StartsWith(@".php", StringComparison.OrdinalIgnoreCase) || 17 | HasShebang(file, "php"); 18 | } 19 | 20 | /// 21 | protected override FeedUri InterpreterInterface => new("https://apps.0install.net/php/php.xml"); 22 | } 23 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/PosixExecutable.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// Any file with the POSIX executable bit (xbit) set. 8 | /// 9 | public abstract class PosixExecutable : NativeExecutable 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | return IsExecutable(file.FullName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/PosixScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Text; 5 | 6 | namespace ZeroInstall.Publish.EntryPoints; 7 | 8 | /// 9 | /// A shebang (#!) script for execution on a POSIX-style operating system. 10 | /// 11 | public sealed class PosixScript : PosixExecutable 12 | { 13 | /// 14 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 15 | { 16 | if (base.Analyze(baseDirectory, file) 17 | && file.ReadFirstLine(Encoding.ASCII) is {} firstLine 18 | && firstLine.StartsWith(@"#!")) 19 | { 20 | Architecture = new(OS.Posix); 21 | Name = file.Name; 22 | NeedsTerminal = true; 23 | return true; 24 | } 25 | 26 | return false; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/RubyScript.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A script written in Ruby. 8 | /// 9 | public sealed class RubyScript : InterpretedScript 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | return 16 | StringUtils.EqualsIgnoreCase(file.Extension, @".rb") || 17 | HasShebang(file, "ruby"); 18 | } 19 | 20 | /// 21 | protected override FeedUri InterpreterInterface => new("https://apps.0install.net/ruby/ruby.xml"); 22 | } 23 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/WindowsBatch.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// A Windows batch file/script. 8 | /// 9 | public sealed class WindowsBatch : NativeExecutable 10 | { 11 | /// 12 | internal override bool Analyze(DirectoryInfo baseDirectory, FileInfo file) 13 | { 14 | if (!base.Analyze(baseDirectory, file)) return false; 15 | if (!StringUtils.EqualsIgnoreCase(file.Extension, @".bat") && !StringUtils.EqualsIgnoreCase(file.Extension, @".cmd")) return false; 16 | 17 | Architecture = new(OS.Windows); 18 | Name = file.Name[..^file.Extension.Length]; 19 | NeedsTerminal = true; 20 | return true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Publish/EntryPoints/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Publish.EntryPoints 3 | summary: *content 4 | --- 5 | Automatic detection of application entry points. 6 | 7 | Helps publishers set up the appropriate s and s. 8 | -------------------------------------------------------------------------------- /src/Publish/Publish.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | ZeroInstall.Publish 6 | ZeroInstall.Publish 7 | Utilities for creating and modifying Zero Install feed files 8 | https://dotnet.0install.net/md_publish.html 9 | ..\..\artifacts\$(Configuration)\ 10 | 11 | 12 | enable 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Publish/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Publish 3 | summary: *content 4 | --- 5 | Utilities for [creating and modifying feed files](xref:publishing). 6 | 7 | **NuGet package:** [ZeroInstall.Publish](https://www.nuget.org/packages/ZeroInstall.Publish/) 8 | -------------------------------------------------------------------------------- /src/Publish/catalog.css: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: scroll; 3 | } 4 | 5 | 6 | body { 7 | font-family: sans-serif; 8 | } 9 | 10 | 11 | a { 12 | color: black; 13 | text-decoration: none; 14 | } 15 | 16 | 17 | input { 18 | width: 100%; 19 | } 20 | 21 | 22 | #main { 23 | margin-top: -0.5rem; 24 | margin-left: auto; 25 | margin-right: auto; 26 | max-width: 1100px; 27 | } 28 | 29 | 30 | .searchBar { 31 | position: sticky; 32 | top: 0; 33 | padding-top: 0.5rem; 34 | padding-bottom: 0.5rem; 35 | padding-right: 1rem; 36 | background-color: white; 37 | } 38 | 39 | 40 | .app { 41 | display: flex; 42 | min-height: 64px; 43 | align-items: center; 44 | } 45 | 46 | 47 | .app:nth-child(even) { 48 | background-color: #EEE; 49 | } 50 | 51 | 52 | .icon { 53 | width: 42px; 54 | flex: 0 0 auto; 55 | padding: 0.5rem 0 0.5rem 0.5rem; 56 | } 57 | 58 | 59 | .info { 60 | flex: 1 1 auto; 61 | padding: 0.5rem 0 0.5rem 0.5rem; 62 | } 63 | 64 | 65 | .name { 66 | font-size: 1.1rem; 67 | margin: 0; 68 | } 69 | 70 | 71 | .summary { 72 | vertical-align: top; 73 | float: left; 74 | margin: 0; 75 | } 76 | 77 | 78 | .actions { 79 | flex: 0 0 auto; 80 | padding: 1rem; 81 | } 82 | 83 | -------------------------------------------------------------------------------- /src/Resources.Designer.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Services/Executors/Executor.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Diagnostics; 5 | using ZeroInstall.Model.Selection; 6 | using ZeroInstall.Store.Implementations; 7 | 8 | namespace ZeroInstall.Services.Executors; 9 | 10 | /// 11 | /// Executes a document as a program using dependency injection. 12 | /// 13 | /// This class is immutable and thread-safe. 14 | public class Executor(IImplementationStore implementationStore) : IExecutor 15 | { 16 | /// 17 | public Process? Start(Selections selections) 18 | => new EnvironmentBuilder(implementationStore) 19 | .Inject(selections) 20 | .Start(); 21 | 22 | /// 23 | public IEnvironmentBuilder Inject(Selections selections, string? overrideMain = null) 24 | => new EnvironmentBuilder(implementationStore) 25 | .Inject(selections, overrideMain); 26 | } 27 | -------------------------------------------------------------------------------- /src/Services/Executors/ExecutorException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.Services.Executors; 9 | 10 | /// 11 | /// Indicates that the was unable to launch the desired application. 12 | /// 13 | #if !NET 14 | [Serializable] 15 | #endif 16 | public sealed class ExecutorException : Exception 17 | { 18 | /// 19 | /// Creates a new missing main exception. 20 | /// 21 | public ExecutorException() {} 22 | 23 | /// 24 | /// Creates a new missing main exception. 25 | /// 26 | public ExecutorException(string message) 27 | : base(message) 28 | {} 29 | 30 | /// 31 | /// Creates a new missing main exception. 32 | /// 33 | public ExecutorException(string message, Exception innerException) 34 | : base(message, innerException) 35 | {} 36 | 37 | #region Serialization 38 | #if !NET 39 | /// 40 | /// Deserializes an exception. 41 | /// 42 | private ExecutorException(SerializationInfo info, StreamingContext context) 43 | : base(info, context) 44 | {} 45 | #endif 46 | #endregion 47 | } 48 | -------------------------------------------------------------------------------- /src/Services/Executors/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Executors 3 | summary: *content 4 | --- 5 | Launches implementations and injects the selected dependencies. 6 | -------------------------------------------------------------------------------- /src/Services/Executors/runenv.exe.template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/Services/Executors/runenv.exe.template -------------------------------------------------------------------------------- /src/Services/Executors/runenv_build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | "%windir%\Microsoft.NET\Framework\v4.0.30319\csc.exe" /nologo /win32manifest:"%~dp0..\..\Commands\app.manifest" /out:"%~dp0runenv.exe.template" "%~dp0runenv.cs" 3 | -------------------------------------------------------------------------------- /src/Services/Feeds/OpenPgpKeyCallback.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services.Feeds; 5 | 6 | /// 7 | /// Callback for reading a specific OpenPGP public key file. 8 | /// 9 | /// The key ID as a canonical string.. 10 | /// The public key in binary or ASCII Armored format. 11 | public delegate ArraySegment? OpenPgpKeyCallback(string id); 12 | -------------------------------------------------------------------------------- /src/Services/Feeds/SelectionsManagerExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Selection; 5 | 6 | namespace ZeroInstall.Services.Feeds; 7 | 8 | /// 9 | /// Provides extension methods for . 10 | /// 11 | public static class SelectionsManagerExtensions 12 | { 13 | /// 14 | /// Combines and . 15 | /// 16 | /// The . 17 | /// The selections to search for s that are missing. 18 | public static List GetUncachedImplementations(this ISelectionsManager selectionsManager, Selections selections) 19 | { 20 | #region Sanity checks 21 | if (selectionsManager == null) throw new ArgumentNullException(nameof(selectionsManager)); 22 | if (selections == null) throw new ArgumentNullException(nameof(selections)); 23 | #endregion 24 | 25 | return selectionsManager.GetImplementations(selectionsManager.GetUncached(selections.Implementations)).ToList(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Services/Feeds/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Feeds 3 | summary: *content 4 | --- 5 | Picking, downloading and verifying feeds. 6 | -------------------------------------------------------------------------------- /src/Services/Fetchers/IImplementationDiscovery.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services.Fetchers; 5 | 6 | /// 7 | /// Discovers implementations in implementation stores on other machines in the local network. 8 | /// 9 | public interface IImplementationDiscovery 10 | { 11 | /// 12 | /// Finds a specific implementation in an implementation store on another machine. 13 | /// Blocks until the implementation is found or the operation is cancelled. 14 | /// 15 | /// The digest the implementation to find. 16 | /// Used to stop looking for the implementation. 17 | /// An archive URI from which the implementation can be downloaded. 18 | /// The was cancelled. 19 | Uri GetImplementation(ManifestDigest manifestDigest, CancellationToken cancellationToken); 20 | } 21 | -------------------------------------------------------------------------------- /src/Services/Fetchers/RetrievalMethodRanker.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services.Fetchers; 5 | 6 | /// 7 | /// Compares s and sorts them from most to least preferred by s. 8 | /// 9 | public sealed class RetrievalMethodRanker : IComparer 10 | { 11 | #region Singleton 12 | /// 13 | /// Singleton pattern. 14 | /// 15 | public static readonly RetrievalMethodRanker Instance = new(); 16 | 17 | private RetrievalMethodRanker() {} 18 | #endregion 19 | 20 | /// 21 | public int Compare(RetrievalMethod? x, RetrievalMethod? y) 22 | => x switch 23 | { 24 | _ when ReferenceEquals(x, y) => 0, 25 | DownloadRetrievalMethod _ when y is Recipe => -1, 26 | Recipe _ when y is DownloadRetrievalMethod => 1, 27 | DownloadRetrievalMethod downloadX when y is DownloadRetrievalMethod downloadY => downloadX.Size.CompareTo(downloadY.Size), 28 | Recipe recipeX when y is Recipe recipeY => recipeX.Steps.Count.CompareTo(recipeY.Steps.Count), 29 | _ => 0 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/Services/Fetchers/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Fetchers 3 | summary: *content 4 | --- 5 | Downloads and extracts implementations. 6 | -------------------------------------------------------------------------------- /src/Services/Native/CompositePackageManager.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Selection; 5 | 6 | namespace ZeroInstall.Services.Native; 7 | 8 | /// 9 | /// Combines multiple s as a composite. 10 | /// 11 | /// A priority-sorted list of s. Queried first-to-last. 12 | /// This class is immutable and thread-safe. 13 | public class CompositePackageManager(IEnumerable packageManagers) : IPackageManager 14 | { 15 | private readonly List _packageManagers = packageManagers.ToList(); 16 | 17 | /// 18 | public IEnumerable Query(PackageImplementation package, params string[] distributions) 19 | => _packageManagers 20 | .SelectMany(x => x.Query(package, distributions)); 21 | 22 | /// 23 | public ExternalImplementation? Lookup(ImplementationSelection selection) 24 | => _packageManagers 25 | .Select(x => x.Lookup(selection)) 26 | .WhereNotNull() 27 | .FirstOrDefault(); 28 | } 29 | -------------------------------------------------------------------------------- /src/Services/Native/PackageManagers.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Native; 5 | 6 | namespace ZeroInstall.Services.Native; 7 | 8 | /// 9 | /// Provides instances. 10 | /// 11 | public static class PackageManagers 12 | { 13 | /// 14 | /// Creates the default for the current platform. 15 | /// 16 | public static IPackageManager Default() 17 | { 18 | var packageManagers = new List(); 19 | 20 | if (WindowsUtils.IsWindows) packageManagers.Add(new WindowsPackageManager()); 21 | //if (UnixUtils.IsUnix) packageManagers.Add(new PackageKitPackageManager()); 22 | 23 | return new CompositePackageManager(packageManagers); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Services/Native/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Native 3 | summary: *content 4 | --- 5 | Operating system specific services such as native package managers. 6 | -------------------------------------------------------------------------------- /src/Services/Server/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Server 3 | summary: *content 4 | --- 5 | Provides resources to other Zero Install instances via the network. 6 | -------------------------------------------------------------------------------- /src/Services/Solvers/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services.Solvers 3 | summary: *content 4 | --- 5 | Solves requirements by selecting a specific combination of implementations from feeds. 6 | -------------------------------------------------------------------------------- /src/Services/WebExceptionExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services; 5 | 6 | /// 7 | /// Provides extension methods for s. 8 | /// 9 | public static class WebExceptionExtensions 10 | { 11 | /// 12 | /// Determines a download from a specific that failed with an is should be retried using a mirror location. 13 | /// 14 | public static bool ShouldTryMirror(this WebException exception, Uri uri) 15 | => uri is {Scheme: "http" or "https", HostNameType: UriHostNameType.Dns, IsLoopback: false} 16 | && exception is not { 17 | #if NET 18 | InnerException: HttpRequestException 19 | #else 20 | Response: HttpWebResponse 21 | #endif 22 | {StatusCode: HttpStatusCode.Unauthorized or HttpStatusCode.Forbidden} 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/Services/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Services 3 | summary: *content 4 | --- 5 | for solving dependencies, downloading implementations, executing apps, etc.. 6 | 7 | **NuGet package:** [ZeroInstall.Services](https://www.nuget.org/packages/ZeroInstall.Services) 8 | -------------------------------------------------------------------------------- /src/Store/Configuration/ConfigTab.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Configuration; 5 | 6 | /// 7 | /// Available tabs in a GUI. 8 | /// 9 | public enum ConfigTab 10 | { 11 | Default, 12 | Updates, 13 | Storage, 14 | Catalog, 15 | Trust, 16 | Sync, 17 | Language, 18 | Advanced 19 | } 20 | -------------------------------------------------------------------------------- /src/Store/Configuration/NetworkLevel.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Configuration; 5 | 6 | /// 7 | /// Controls how liberally network access is attempted. 8 | /// 9 | /// 10 | public enum NetworkLevel 11 | { 12 | /// Do not access network at all. 13 | Offline, 14 | 15 | /// Only access network when there are no safe implementations available. 16 | Minimal, 17 | 18 | /// Always use network to get the newest available versions. 19 | Full 20 | } 21 | -------------------------------------------------------------------------------- /src/Store/Configuration/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Configuration 3 | summary: *content 4 | --- 5 | User settings controlling network behaviour, solving, etc.. 6 | -------------------------------------------------------------------------------- /src/Store/Deployment/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Deployment 3 | summary: *content 4 | --- 5 | Deploying implementations to locations outside an implementation cache; mainly used to deploy Zero Install itself. 6 | -------------------------------------------------------------------------------- /src/Store/Feeds/FeedCaches.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.Trust; 5 | 6 | namespace ZeroInstall.Store.Feeds; 7 | 8 | /// 9 | /// Provides instances. 10 | /// 11 | public static class FeedCaches 12 | { 13 | /// 14 | /// Creates an instance that uses the default cache location in the user profile. 15 | /// 16 | /// Provides access to an encryption/signature system compatible with the OpenPGP standard. 17 | public static IFeedCache Default(IOpenPgp openPgp) 18 | => new FeedCache(DefaultPath, openPgp); 19 | 20 | /// 21 | /// The default feed cache location in the user profile. 22 | /// 23 | public static string DefaultPath 24 | => Locations.GetCacheDirPath("0install.net", machineWide: false, resource: "interfaces"); 25 | } 26 | -------------------------------------------------------------------------------- /src/Store/Feeds/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Feeds 3 | summary: *content 4 | --- 5 | Caches for feeds. 6 | -------------------------------------------------------------------------------- /src/Store/FileSystem/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.FileSystem 3 | summary: *content 4 | --- 5 | Interfaces and methods for building and reading structures. 6 | -------------------------------------------------------------------------------- /src/Store/Icons/IconStoreExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Icons; 5 | 6 | /// 7 | /// Provides extension methods for . 8 | /// 9 | public static class IconStoreExtensions 10 | { 11 | /// 12 | /// Tries to get an icon that is already cached. 13 | /// 14 | /// The icon store. 15 | /// The icon to get. 16 | /// The file path of the icon in the cache; null if the icon is not cached yet. 17 | public static string? TryGetCached(this IIconStore iconStore, Icon icon) 18 | => iconStore.TryGetCached(icon, out _); 19 | } 20 | -------------------------------------------------------------------------------- /src/Store/Icons/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Icons 3 | summary: *content 4 | --- 5 | Stores icon files downloaded from the web as local files. 6 | -------------------------------------------------------------------------------- /src/Store/Implementations/ImplementationStoreKind.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Implementations; 5 | 6 | /// 7 | public enum ImplementationStoreKind 8 | { 9 | /// 10 | /// This store can be written to directly. 11 | /// 12 | ReadWrite, 13 | 14 | /// 15 | /// This store cannot be modified. 16 | /// 17 | ReadOnly, 18 | 19 | /// 20 | /// This store is managed by a background service. 21 | /// 22 | Service 23 | } 24 | -------------------------------------------------------------------------------- /src/Store/Implementations/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Implementations 3 | summary: *content 4 | --- 5 | On-disk storage for implementations, i.e. [implementation caches](https://docs.0install.net/details/cache/). 6 | -------------------------------------------------------------------------------- /src/Store/Manifests/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Manifests 3 | summary: *content 4 | --- 5 | [Manifests](https://docs.0install.net/specifications/manifest/) list every file, directory and symlink in the tree to allow for digest/hash calculation. 6 | -------------------------------------------------------------------------------- /src/Store/Trust/IFingerprintContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Trust; 5 | 6 | /// 7 | /// An object containing a fingerprint for an public or private key. 8 | /// 9 | public interface IFingerprintContainer : IKeyIDContainer 10 | { 11 | /// 12 | /// An OpenPGP key fingerprint. Superset of . 13 | /// 14 | OpenPgpFingerprint Fingerprint { get; } 15 | } 16 | -------------------------------------------------------------------------------- /src/Store/Trust/IKeyIDContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Trust; 5 | 6 | /// 7 | /// An object containing a key ID for an public or private key. 8 | /// 9 | public interface IKeyIDContainer 10 | { 11 | /// 12 | /// An OpenPGP key ID. A short identifier for a key. The lower 64 bits of . 13 | /// 14 | long KeyID { get; } 15 | } 16 | -------------------------------------------------------------------------------- /src/Store/Trust/OpenPgpFingerprint.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Trust; 5 | 6 | /// 7 | /// An OpenPGP key fingerprint. 8 | /// 9 | /// A long identifier for an OpenPGP key. 10 | [Equatable] 11 | public partial record OpenPgpFingerprint([property: OrderedEquality] byte[] Identifier) 12 | { 13 | public static implicit operator byte[](OpenPgpFingerprint fingerprint) => fingerprint.Identifier; 14 | } 15 | -------------------------------------------------------------------------------- /src/Store/Trust/OpenPgpSecretKey.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Trust; 5 | 6 | /// 7 | /// Represents a secret key stored in a local profile. 8 | /// 9 | /// The key ID of the key. 10 | /// The fingerprint of the key. 11 | /// The user's name, e-mail address, etc. of the key owner. 12 | public sealed record OpenPgpSecretKey(long KeyID, OpenPgpFingerprint Fingerprint, string UserID) : IFingerprintContainer 13 | { 14 | /// 15 | /// Returns the secret key in the form "UserID". Not safe for parsing! 16 | /// 17 | public override string ToString() => UserID; 18 | } 19 | -------------------------------------------------------------------------------- /src/Store/Trust/SignatureException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.Store.Trust; 9 | 10 | /// 11 | /// Indicates the implementation detected a problem with a digital signature. 12 | /// 13 | #if !NET 14 | [Serializable] 15 | #endif 16 | public sealed class SignatureException : Exception 17 | { 18 | /// 19 | public SignatureException() 20 | : base(Resources.InvalidSignature) 21 | {} 22 | 23 | /// 24 | public SignatureException(string message) 25 | : base(message) 26 | {} 27 | 28 | /// 29 | public SignatureException(string message, Exception innerException) 30 | : base(message, innerException) 31 | {} 32 | 33 | #region Serialization 34 | #if !NET 35 | /// 36 | /// Deserializes an exception. 37 | /// 38 | private SignatureException(SerializationInfo info, StreamingContext context) 39 | : base(info, context) 40 | {} 41 | #endif 42 | #endregion 43 | } 44 | -------------------------------------------------------------------------------- /src/Store/Trust/WrongPassphraseException.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | #if !NET 5 | using System.Runtime.Serialization; 6 | #endif 7 | 8 | namespace ZeroInstall.Store.Trust; 9 | 10 | /// 11 | /// Indicates that an incorrect passphrase was passed to . 12 | /// 13 | #if !NET 14 | [Serializable] 15 | #endif 16 | public sealed class WrongPassphraseException : Exception 17 | { 18 | /// 19 | /// Indicates that an incorrect passphrase was passed to . 20 | /// 21 | public WrongPassphraseException() 22 | : base(Resources.WrongPassphrase) 23 | {} 24 | 25 | /// 26 | public WrongPassphraseException(string message) 27 | : base(message) 28 | {} 29 | 30 | /// 31 | public WrongPassphraseException(string message, Exception innerException) 32 | : base(message, innerException) 33 | {} 34 | 35 | #region Serialization 36 | #if !NET 37 | /// 38 | /// Deserializes an exception. 39 | /// 40 | private WrongPassphraseException(SerializationInfo info, StreamingContext context) 41 | : base(info, context) 42 | {} 43 | #endif 44 | #endregion 45 | } 46 | -------------------------------------------------------------------------------- /src/Store/Trust/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.Trust 3 | summary: *content 4 | --- 5 | Structures and logic for [OpenPGP signatures](https://docs.0install.net/specifications/feed/#digital-signatures) and trust (which domains the user associates with which signatures). 6 | -------------------------------------------------------------------------------- /src/Store/ViewModel/TrustNode.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Model.Trust; 5 | 6 | namespace ZeroInstall.Store.ViewModel; 7 | 8 | /// 9 | /// Represents a - pair in a for display in a UI. 10 | /// 11 | /// The . 12 | /// The domain the fingerprint is valid for. 13 | public sealed record TrustNode(string Fingerprint, Domain Domain) : INamed 14 | { 15 | /// 16 | /// The full name of the node used for tree hierarchies. 17 | /// 18 | [Browsable(false)] 19 | public string Name 20 | { 21 | get => Fingerprint + Named.TreeSeparator + Domain.Value; 22 | set => throw new NotSupportedException(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Store/ViewModel/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store.ViewModel 3 | summary: *content 4 | --- 5 | Models information about configuration and cache elements for display in a UI. 6 | -------------------------------------------------------------------------------- /src/Store/_Namespace.md: -------------------------------------------------------------------------------- 1 | --- 2 | uid: ZeroInstall.Store 3 | summary: *content 4 | --- 5 | Management of [implementation caches](https://docs.0install.net/details/cache/), digital signatures, etc.. 6 | 7 | **NuGet package:** [ZeroInstall.Store](https://www.nuget.org/packages/ZeroInstall.Store/) 8 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Builders/BuilderTestBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Streams; 5 | using ZeroInstall.Store.FileSystem; 6 | 7 | namespace ZeroInstall.Archives.Builders; 8 | 9 | /// 10 | /// Common test cases for implementations. 11 | /// 12 | public abstract class ArchiveBuilderTestBase 13 | { 14 | protected virtual Stream GetArchiveStream() 15 | { 16 | var stream = new MemoryStream(); 17 | using (var builder = NewBuilder(stream)) 18 | AddElements(builder); 19 | return new MemoryStream(stream.AsArray()); 20 | } 21 | 22 | [MustDisposeResource] 23 | protected abstract IArchiveBuilder NewBuilder(Stream stream); 24 | 25 | protected abstract void AddElements(IForwardOnlyBuilder builder); 26 | } 27 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Builders/TarBz2BuilderTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ICSharpCode.SharpZipLib.BZip2; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Contains test methods for . 10 | /// 11 | public class TarBz2BuilderTest : TarBuilderTest 12 | { 13 | protected override IArchiveBuilder NewBuilder(Stream stream) => new TarBz2Builder(stream); 14 | 15 | protected override Stream GetArchiveStream() => new BZip2InputStream(base.GetArchiveStream()); 16 | } 17 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Builders/TarGzBuilderTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ICSharpCode.SharpZipLib.GZip; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Contains test methods for . 10 | /// 11 | public class TarGzBuilderTest : TarBuilderTest 12 | { 13 | protected override IArchiveBuilder NewBuilder(Stream stream) => new TarGzBuilder(stream); 14 | 15 | protected override Stream GetArchiveStream() => new GZipInputStream(base.GetArchiveStream()); 16 | } 17 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Builders/TarLzipBuilerTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using SharpCompress.Compressors; 5 | using SharpCompress.Compressors.LZMA; 6 | 7 | namespace ZeroInstall.Archives.Builders; 8 | 9 | /// 10 | /// Contains test methods for . 11 | /// 12 | public class TarLzipBuilderTest : TarBuilderTest 13 | { 14 | protected override IArchiveBuilder NewBuilder(Stream stream) => new TarLzipBuilder(stream); 15 | 16 | protected override Stream GetArchiveStream() => new LZipStream(base.GetArchiveStream(), CompressionMode.Decompress); 17 | } 18 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Builders/TarZstandardBuilderTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZstdSharp; 5 | 6 | namespace ZeroInstall.Archives.Builders; 7 | 8 | /// 9 | /// Contains test methods for . 10 | /// 11 | public class TarZstandardBuilderTest : TarBuilderTest 12 | { 13 | protected override IArchiveBuilder NewBuilder(Stream stream) => new TarZstandardBuilder(stream); 14 | 15 | protected override Stream GetArchiveStream() => new DecompressionStream(base.GetArchiveStream()); 16 | } 17 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/ArchiveExtractorTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Archives.Extractors; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class ArchiveExtractorTest 10 | { 11 | [Fact] 12 | public void TestForZip() 13 | { 14 | ArchiveExtractor.For(Archive.MimeTypeZip, new SilentTaskHandler()) 15 | .Should().BeOfType(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/MsiExtractorTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Native; 5 | using ZeroInstall.Store.Manifests; 6 | 7 | namespace ZeroInstall.Archives.Extractors; 8 | 9 | public class MsiExtractorTest: ArchiveExtractorTestBase 10 | { 11 | protected override string MimeType => Archive.MimeTypeMsi; 12 | 13 | public MsiExtractorTest() 14 | { 15 | Skip.IfNot(WindowsUtils.IsWindows, "MSI extraction relies on a Win32 API and therefore will not work on non-Windows platforms"); 16 | } 17 | 18 | [SkippableFact] 19 | public void Extract() 20 | { 21 | Test( 22 | "testArchive.msi", 23 | new Manifest(ManifestFormat.Sha1New) 24 | { 25 | [""] = 26 | { 27 | ["file"] = Normal("abc") 28 | }, 29 | ["folder1"] = 30 | { 31 | ["file"] = Normal("def") 32 | } 33 | }, 34 | subDir: "SourceDir"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/NonSeekableStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Streams; 5 | 6 | namespace ZeroInstall.Archives.Extractors; 7 | 8 | public class NonSeekableStream(Stream underlyingStream) : DelegatingStream(underlyingStream) 9 | { 10 | public override bool CanSeek => false; 11 | 12 | public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); 13 | 14 | public override long Position { get => base.Position; set => throw new NotSupportedException(); } 15 | } 16 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/RarExtractorTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.Manifests; 5 | 6 | namespace ZeroInstall.Archives.Extractors; 7 | 8 | public class RarExtractorTest : ArchiveExtractorTestBase 9 | { 10 | protected override string MimeType => Archive.MimeTypeRar; 11 | 12 | [Fact] 13 | public void Extract() 14 | { 15 | Test( 16 | "testArchive.rar", 17 | new Manifest(ManifestFormat.Sha1New) 18 | { 19 | [""] = {["file"] = Normal("abc")}, 20 | ["folder1"] = {["file"] = Normal("def")} 21 | }); 22 | } 23 | 24 | [Fact] 25 | public void ExtractSubDir() 26 | { 27 | Test( 28 | "testArchive.rar", 29 | new Manifest(ManifestFormat.Sha1New) 30 | { 31 | [""] = {["file"] = Normal("def")} 32 | }, 33 | subDir: "folder1"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/RubyGemExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class RubyGemExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeRubyGem; 6 | 7 | protected override string FileName => "testArchive.gem"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/SevenZipExtractorTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.Manifests; 5 | 6 | namespace ZeroInstall.Archives.Extractors; 7 | 8 | public class SevenZipExtractorTest : ArchiveExtractorTestBase 9 | { 10 | protected override string MimeType => Archive.MimeType7Z; 11 | 12 | [Fact] 13 | public void Extract() 14 | { 15 | Test( 16 | "testArchive.7z", 17 | new Manifest(ManifestFormat.Sha1New) 18 | { 19 | [""] = {["file"] = Normal("abc")}, 20 | ["folder1"] = {["file"] = Normal("def")} 21 | }); 22 | } 23 | 24 | [Fact] 25 | public void ExtractSubDir() 26 | { 27 | Test( 28 | "testArchive.7z", 29 | new Manifest(ManifestFormat.Sha1New) 30 | { 31 | [""] = {["file"] = Normal("def")} 32 | }, 33 | subDir: "folder1"); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarBz2ExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarBz2ExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarBzip; 6 | 7 | protected override string FileName => "testArchive.tar.bz2"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarGzExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarGzExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarGzip; 6 | 7 | protected override string FileName => "testArchive.tar.gz"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarLzipExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarLzipExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarLzip; 6 | 7 | protected override string FileName => "testArchive.tar.lz"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarLzmaExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarLzmaExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarLzma; 6 | 7 | protected override string FileName => "testArchive.tar.lzma"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarXzExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarXzExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarXz; 6 | 7 | protected override string FileName => "testArchive.tar.xz"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/TarZstandardExtractorTest.cs: -------------------------------------------------------------------------------- 1 | namespace ZeroInstall.Archives.Extractors; 2 | 3 | public class TarZstandardExtractorTest : TarExtractorTest 4 | { 5 | protected override string MimeType => Archive.MimeTypeTarZstandard; 6 | 7 | protected override string FileName => "testArchive.tar.zst"; 8 | } 9 | -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.7z -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.cab: -------------------------------------------------------------------------------- 1 | MSCF|,I^!(h file!(h folder1\file7d0`abcdef -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.dmg -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.gem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.gem -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.msi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.msi -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.rar -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.bz2 -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.gz -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.lz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.lz -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.lzma: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.lzma -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.xz -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.tar.zst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.tar.zst -------------------------------------------------------------------------------- /src/UnitTests/Archives/Extractors/testArchive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Archives/Extractors/testArchive.zip -------------------------------------------------------------------------------- /src/UnitTests/Commands/Basic/SelectionTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Commands.Basic; 5 | 6 | /// 7 | /// Contains integration tests for . 8 | /// 9 | public class SelectionTest : SelectionTestBase 10 | { 11 | [Fact] // Ensures all options are parsed and handled correctly. 12 | public virtual void TestNormal() 13 | { 14 | var selections = ExpectSolve(); 15 | 16 | RunAndAssert(selections.ToXmlString(), 0, selections, 17 | "--xml", "http://example.com/test1.xml", "--command=command", "--os=Windows", "--cpu=i586", "--not-before=1.0", "--before=2.0", "--version-for=http://example.com/test2.xml", "2.0..!3.0"); 18 | } 19 | 20 | [Fact] // Ensures local Selections XMLs are correctly detected and parsed. 21 | public virtual void TestImportSelections() 22 | { 23 | var selections = Fake.Selections; 24 | using var tempFile = new TemporaryFile("0install-test-selections"); 25 | selections.SaveXml(tempFile); 26 | 27 | selections.Normalize(); 28 | RunAndAssert(selections.ToXmlString(), 0, selections, 29 | "--xml", tempFile); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/UnitTests/DesktopIntegration/AccessPoints/CapabilityRegistrationTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.DesktopIntegration.AccessPoints; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class CapabilityRegistrationTest 10 | { 11 | [Fact] 12 | public void GetConflictIDs() 13 | { 14 | var capabilityRegistration = new CapabilityRegistration(); 15 | var appEntry = new AppEntry 16 | { 17 | InterfaceUri = FeedTest.Test1Uri, 18 | Name = "Test", 19 | CapabilityLists = 20 | { 21 | new() {Entries = {new Model.Capabilities.FileType {ID = "test1"}}}, 22 | new() {Entries = {new Model.Capabilities.FileType {ID = "test2"}}} 23 | } 24 | }; 25 | 26 | capabilityRegistration.GetConflictIDs(appEntry) 27 | .Should().Equal("progid:test1", "progid:test2"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/UnitTests/DesktopIntegration/Windows/ShortcutTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Runtime.Versioning; 5 | using NanoByte.Common.Native; 6 | 7 | namespace ZeroInstall.DesktopIntegration.Windows; 8 | 9 | /// 10 | /// Contains test methods for . 11 | /// 12 | [SupportedOSPlatform("windows")] 13 | public class ShortcutTest 14 | { 15 | public ShortcutTest() 16 | { 17 | Skip.IfNot(WindowsUtils.IsWindows); 18 | } 19 | 20 | [SkippableFact] 21 | public void TestCreate() 22 | { 23 | using var tempDir = new TemporaryDirectory("0install-unit-test"); 24 | string path = Path.Combine(tempDir, "shortcut.lnk"); 25 | Shortcut.Create(path, targetPath: "abc", arguments: "xyz"); 26 | 27 | var shortcut = ShellLink.Shortcut.ReadFromFile(path); 28 | shortcut.ExtraData.EnvironmentVariableDataBlock.TargetUnicode.Should().Be("abc"); 29 | shortcut.StringData.CommandLineArguments.Should().Be("xyz"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/UnitTests/FileSystem/TestElement.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.FileSystem; 5 | 6 | /// 7 | /// Represents a file system element used for testing file system operations. 8 | /// It can either be realized on-disk or compared against an existing on-disk element. 9 | /// 10 | /// 11 | public abstract class TestElement(string name) 12 | { 13 | /// 14 | /// The name of the file system element. 15 | /// 16 | public string Name { get; } = name; 17 | 18 | /// 19 | /// Realizes the element as an on-disk element. 20 | /// 21 | /// The full path of the existing directory to realize the element in. 22 | public abstract void Build(string parentPath); 23 | 24 | /// 25 | /// Compares the element against an existing on-disk element using assertions. 26 | /// 27 | /// The full path of the directory containing the element. 28 | public abstract void Verify(string parentPath); 29 | } 30 | -------------------------------------------------------------------------------- /src/UnitTests/FileSystem/TestRoot.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.FileSystem; 5 | 6 | /// 7 | /// Represents a directory structure used for testing file system operations. 8 | /// It can either be realized on-disk or compared against an existing on-disk directory. 9 | /// 10 | /// 11 | /// 12 | /// 13 | public class TestRoot : List 14 | { 15 | /// 16 | /// Realizes the directory structure as an on-disk directory. 17 | /// 18 | /// The full path of the directory to realize the structure in. 19 | public void Build(string path) 20 | { 21 | if (!Directory.Exists(path)) 22 | Directory.CreateDirectory(path); 23 | 24 | foreach (var element in this) 25 | element.Build(path); 26 | } 27 | 28 | /// 29 | /// Compares the structure against an existing on-disk directory using assertions. 30 | /// 31 | /// The full path of the directory to compare the structure against. 32 | public void Verify(string path) 33 | { 34 | foreach (var element in this) 35 | element.Verify(path); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/UnitTests/MockExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using System.Linq.Expressions; 5 | 6 | namespace ZeroInstall; 7 | 8 | public static class MockExtensions 9 | { 10 | public static Mock SetupFluent(this Mock mock, Expression> expression) where T : class 11 | { 12 | mock.Setup(expression).Returns(mock.Object); 13 | return mock; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/UnitTests/Model/EnvironmentBindingTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class EnvironmentBindingTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static EnvironmentBinding CreateTestBinding() => new() 15 | { 16 | Name = "name", 17 | Value = "value", 18 | Default = "default", 19 | Mode = EnvironmentMode.Replace, 20 | Separator = "," 21 | }; 22 | 23 | /// 24 | /// Ensures that the class can be correctly cloned. 25 | /// 26 | [Fact] 27 | public void Clone() 28 | { 29 | var binding1 = CreateTestBinding(); 30 | var binding2 = binding1.Clone(); 31 | 32 | // Ensure data stayed the same 33 | binding2.Should().Be(binding1, because: "Cloned objects should be equal."); 34 | binding2.GetHashCode().Should().Be(binding1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 35 | binding2.Should().NotBeSameAs(binding1, because: "Cloning should not return the same reference."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/UnitTests/Model/ExecutableInPathTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class ExecutableInPathTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static ExecutableInPath CreateTestBinding() => new() {Name = "name", Command = "command"}; 15 | 16 | /// 17 | /// Ensures that the class can be correctly cloned. 18 | /// 19 | [Fact] 20 | public void Clone() 21 | { 22 | var binding1 = CreateTestBinding(); 23 | var binding2 = binding1.Clone(); 24 | 25 | // Ensure data stayed the same 26 | binding2.Should().Be(binding1, because: "Cloned objects should be equal."); 27 | binding2.GetHashCode().Should().Be(binding1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 28 | binding2.Should().NotBeSameAs(binding1, because: "Cloning should not return the same reference."); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/UnitTests/Model/ExecutableInVarTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class ExecutableInVarTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static ExecutableInVar CreateTestBinding() => new() {Name = "name", Command = "command"}; 15 | 16 | /// 17 | /// Ensures that the class can be correctly cloned. 18 | /// 19 | [Fact] 20 | public void Clone() 21 | { 22 | var binding1 = CreateTestBinding(); 23 | var binding2 = binding1.Clone(); 24 | 25 | // Ensure data stayed the same 26 | binding2.Should().Be(binding1, because: "Cloned objects should be equal."); 27 | binding2.GetHashCode().Should().Be(binding1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 28 | binding2.Should().NotBeSameAs(binding1, because: "Cloning should not return the same reference."); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/UnitTests/Model/FeedElementTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class FeedElementTest 10 | { 11 | [Fact] 12 | public void FilterMismatch() 13 | { 14 | FeedElement.FilterMismatch(new EntryPoint {Command = Command.NameRun}).Should().BeFalse(); 15 | FeedElement.FilterMismatch(new EntryPoint {Command = Command.NameRun, IfZeroInstallVersion = new VersionRange("0..")}).Should().BeFalse(); 16 | FeedElement.FilterMismatch(new EntryPoint {Command = Command.NameRun, IfZeroInstallVersion = new VersionRange("..!0")}).Should().BeTrue(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/UnitTests/Model/GenericBindingTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class GenericBindingTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static GenericBinding CreateTestBinding() => new() {Path = "path", Command = "command"}; 15 | 16 | /// 17 | /// Ensures that the class can be correctly cloned. 18 | /// 19 | [Fact] 20 | public void Clone() 21 | { 22 | var binding1 = CreateTestBinding(); 23 | var binding2 = binding1.Clone(); 24 | 25 | // Ensure data stayed the same 26 | binding2.Should().Be(binding1, because: "Cloned objects should be equal."); 27 | binding2.GetHashCode().Should().Be(binding1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 28 | binding2.Should().NotBeSameAs(binding1, because: "Cloning should not return the same reference."); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/UnitTests/Model/OverlayBindingTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class OverlayBindingTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static OverlayBinding CreateTestBinding() => new() 15 | { 16 | Source = @"somedir", 17 | MountPoint = @"/usr/share/somedir" 18 | }; 19 | 20 | /// 21 | /// Ensures that the class can be correctly cloned. 22 | /// 23 | [Fact] 24 | public void Clone() 25 | { 26 | var binding1 = CreateTestBinding(); 27 | var binding2 = binding1.Clone(); 28 | 29 | // Ensure data stayed the same 30 | binding2.Should().Be(binding1, because: "Cloned objects should be equal."); 31 | binding2.GetHashCode().Should().Be(binding1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 32 | binding2.Should().NotBeSameAs(binding1, because: "Cloning should not return the same reference."); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/UnitTests/Model/RunnerTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class RunnerTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | private static Runner CreateTestRunner() => new() 15 | { 16 | InterfaceUri = FeedTest.Test1Uri, 17 | Command = "run2", 18 | Bindings = {EnvironmentBindingTest.CreateTestBinding()}, 19 | Versions = new VersionRange("1.0..!2.0"), 20 | Arguments = {"--arg"} 21 | }; 22 | 23 | /// 24 | /// Ensures that the class can be correctly cloned. 25 | /// 26 | [Fact] 27 | public void Clone() 28 | { 29 | var runner1 = CreateTestRunner(); 30 | var runner2 = runner1.CloneRunner(); 31 | 32 | // Ensure data stayed the same 33 | runner2.Should().Be(runner1, because: "Cloned objects should be equal."); 34 | runner2.GetHashCode().Should().Be(runner1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 35 | runner2.Should().NotBeSameAs(runner1, because: "Cloning should not return the same reference."); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/UnitTests/Model/SingleFileTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Model; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class SingleFileTest 10 | { 11 | /// 12 | /// Creates a fictive test . 13 | /// 14 | internal static SingleFile CreateTestSingleFile() => new() 15 | { 16 | Href = new("http://example.com/test.exe"), 17 | Size = 128, 18 | Destination = "dest", 19 | Executable = true 20 | }; 21 | 22 | /// 23 | /// Ensures that the class can be correctly cloned. 24 | /// 25 | [Fact] 26 | public void Clone() 27 | { 28 | var singleFile1 = CreateTestSingleFile(); 29 | var singleFile2 = singleFile1.Clone(); 30 | 31 | // Ensure data stayed the same 32 | singleFile2.Should().Be(singleFile1, because: "Cloned objects should be equal."); 33 | singleFile2.GetHashCode().Should().Be(singleFile1.GetHashCode(), because: "Cloned objects' hashes should be equal."); 34 | singleFile2.Should().NotBeSameAs(singleFile1, because: "Cloning should not return the same reference."); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/PosixBinaryTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class PosixBinaryTest : CandidateTest 10 | { 11 | public static readonly PosixBinary Reference32 = new() {RelativePath = "elf32", Name = "elf32", Architecture = new(OS.Linux, Cpu.I386)}; 12 | public static readonly PosixBinary Reference64 = new() {RelativePath = "elf64", Name = "elf64", Architecture = new(OS.Linux, Cpu.X64)}; 13 | 14 | [Fact] 15 | public void Elf32() => TestAnalyze(Reference32, executable: true); 16 | 17 | [Fact] 18 | public void Elf64() => TestAnalyze(Reference64, executable: true); 19 | 20 | [Fact] 21 | public void NotExecutable() 22 | => new PosixBinary().Analyze(baseDirectory: Directory, file: Deploy(Reference32, xbit: false)) 23 | .Should().BeFalse(); 24 | 25 | [Fact] 26 | public void NotElf() 27 | => new PosixBinary().Analyze(baseDirectory: Directory, file: Deploy(PosixScriptTest.Reference, xbit: true)) 28 | .Should().BeFalse(); 29 | } 30 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/PosixScriptTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class PosixScriptTest : CandidateTest 10 | { 11 | public static readonly PosixScript Reference = new() 12 | { 13 | RelativePath = "sh", 14 | Architecture = new(OS.Posix), 15 | Name = "sh", 16 | NeedsTerminal = true 17 | }; 18 | 19 | [Fact] 20 | public void Sh() => TestAnalyze(Reference, executable: true); 21 | 22 | [Fact] 23 | public void NotExecutable() 24 | => new PosixScript().Analyze(baseDirectory: Directory, file: Deploy(Reference, xbit: false)) 25 | .Should().BeFalse(); 26 | 27 | [Fact] 28 | public void NoShebang() 29 | => new PosixScript().Analyze(baseDirectory: Directory, file: Deploy(WindowsExeTest.Reference32, xbit: true)) 30 | .Should().BeFalse(); 31 | } 32 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/PythonScriptTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Publish.EntryPoints; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class PythonScriptTest : CandidateTest 10 | { 11 | public static readonly PythonScript Reference = new() {RelativePath = "python", Name = "python", NeedsTerminal = true}; 12 | public static readonly PythonScript ReferenceWithExtension = new() {RelativePath = "python.py", Name = "python", NeedsTerminal = true}; 13 | public static readonly PythonScript ReferenceWithExtensionWindows = new() {RelativePath = "python.pyw", Name = "python", NeedsTerminal = false}; 14 | 15 | [Fact] 16 | public void NoExtension() => TestAnalyze(Reference, executable: true); 17 | 18 | [Fact] 19 | public void NotExecutable() 20 | => new PythonScript().Analyze(baseDirectory: Directory, file: Deploy(Reference, xbit: false)) 21 | .Should().BeFalse(); 22 | 23 | [Fact] 24 | public void WithExtension() => TestAnalyze(ReferenceWithExtension); 25 | 26 | [Fact] 27 | public void WithExtensionWindows() => TestAnalyze(ReferenceWithExtensionWindows); 28 | } 29 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/batch.cmd: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-aspnetcore.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet-aspnetcore.dll -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-aspnetcore.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet-aspnetcore.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-aspnetcore.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "net6.0", 4 | "frameworks": [ 5 | { 6 | "name": "Microsoft.NETCore.App", 7 | "version": "6.0.0" 8 | }, 9 | { 10 | "name": "Microsoft.AspNetCore.App", 11 | "version": "6.0.0" 12 | } 13 | ], 14 | "configProperties": { 15 | "System.GC.Server": true, 16 | "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, 17 | "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-windowsdesktop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet-windowsdesktop.dll -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-windowsdesktop.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet-windowsdesktop.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet-windowsdesktop.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "net6.0", 4 | "frameworks": [ 5 | { 6 | "name": "Microsoft.NETCore.App", 7 | "version": "6.0.0" 8 | }, 9 | { 10 | "name": "Microsoft.WindowsDesktop.App", 11 | "version": "6.0.0" 12 | } 13 | ], 14 | "configProperties": { 15 | "System.Reflection.Metadata.MetadataUpdater.IsSupported": false 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet.dll -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/dotnet.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/dotnet.runtimeconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtimeOptions": { 3 | "tfm": "net6.0", 4 | "framework": { 5 | "name": "Microsoft.NETCore.App", 6 | "version": "6.0.0" 7 | }, 8 | "configProperties": { 9 | "System.Reflection.Metadata.MetadataUpdater.IsSupported": false 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/elf32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/elf32 -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/elf64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/elf64 -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/netfx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/netfx.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/netfx64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/netfx64.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/netfx_terminal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/netfx_terminal.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/python: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | import locale 4 | from logging import warn 5 | try: 6 | locale.setlocale(locale.LC_ALL, '') 7 | except locale.Error: 8 | warn('Error setting locale (eg. Invalid locale)') 9 | 10 | ## PATH ## 11 | 12 | from zeroinstall.cmd import main 13 | import sys 14 | main(sys.argv[1:]) 15 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/python.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/python.pyw: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ls 3 | -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/windows32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/windows32.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/windows32_terminal.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/windows32_terminal.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/EntryPoints/windows64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/EntryPoints/windows64.exe -------------------------------------------------------------------------------- /src/UnitTests/Publish/testArchive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Publish/testArchive.zip -------------------------------------------------------------------------------- /src/UnitTests/Services/Fetchers/testArchive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Services/Fetchers/testArchive.zip -------------------------------------------------------------------------------- /src/UnitTests/Services/ServiceProviderTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services; 5 | 6 | public class ServiceProviderTest : TestWithRedirect 7 | { 8 | private readonly ServiceProvider _provider = new(new SilentTaskHandler()); 9 | 10 | [Fact] 11 | public void SolveOfflineFail() 12 | { 13 | _provider.TrySolveOffline(FeedTest.Test1Uri) 14 | .Should().BeNull(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/UnitTests/Services/Solvers/BacktrackingSolverTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services.Solvers; 5 | 6 | /// 7 | /// Runs test methods for . 8 | /// 9 | public class BacktrackingSolverTest : SolverTest 10 | { 11 | protected override ISolver BuildSolver(ISelectionCandidateProvider candidateProvider) 12 | => new BacktrackingSolver(candidateProvider); 13 | } 14 | -------------------------------------------------------------------------------- /src/UnitTests/Services/Solvers/SolverUtilsTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Services.Solvers; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class SolverUtilsTest 10 | { 11 | [Fact] 12 | public void GetNormalizedAlternativesFillsInDefaultValues() 13 | { 14 | var requirements = new Requirements(new FeedUri("http://test/feed.xml")).ForCurrentSystem(); 15 | requirements.Should().Be(new Requirements(new FeedUri("http://test/feed.xml"), Command.NameRun, Architecture.CurrentSystem) {Languages = {CultureInfo.CurrentUICulture}}); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Deployment/DirectoryOperationTestBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.Store.FileSystem; 5 | using ZeroInstall.Store.Manifests; 6 | 7 | namespace ZeroInstall.Store.Deployment; 8 | 9 | /// 10 | /// Common base class for testing classes derived from. 11 | /// 12 | public abstract class DirectoryOperationTestBase : IDisposable 13 | { 14 | protected readonly TemporaryDirectory TempDir = new("0install-test-dir"); 15 | public virtual void Dispose() => TempDir.Dispose(); 16 | 17 | protected readonly string File1Path; 18 | protected readonly string SubdirPath; 19 | protected readonly string File2Path; 20 | protected readonly Manifest Manifest; 21 | 22 | protected DirectoryOperationTestBase() 23 | { 24 | File1Path = Path.Combine(TempDir, "file1"); 25 | FileUtils.Touch(File1Path); 26 | 27 | SubdirPath = Path.Combine(TempDir, "subdir"); 28 | Directory.CreateDirectory(SubdirPath); 29 | 30 | File2Path = Path.Combine(SubdirPath, "file2"); 31 | FileUtils.Touch(File2Path); 32 | 33 | var builder = new ManifestBuilder(ManifestFormat.Sha256New); 34 | new ReadDirectory(TempDir, builder).Run(); 35 | Manifest = builder.Manifest; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Implementations/ImplementationStoreExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using ZeroInstall.FileSystem; 5 | using ZeroInstall.Store.FileSystem; 6 | using ZeroInstall.Store.Manifests; 7 | 8 | namespace ZeroInstall.Store.Implementations; 9 | 10 | public static class ImplementationStoreExtensions 11 | { 12 | /// 13 | /// Adds a dummy/test implementation to the implementation store. 14 | /// 15 | public static string Add(this ImplementationStore store, ManifestDigest manifestDigest, TestRoot root) 16 | { 17 | string id = manifestDigest.Best!; 18 | string path = Path.Combine(store.Path, id); 19 | 20 | root.Build(path); 21 | var builder = new ManifestBuilder(ManifestFormat.FromPrefix(id)); 22 | new ReadDirectory(path, builder).Run(); 23 | builder.Manifest.Save(Path.Combine(path, Manifest.ManifestFile)); 24 | 25 | return path; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Manifests/ManifestFormatTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall.Store.Manifests; 5 | 6 | /// 7 | /// Contains test methods for . 8 | /// 9 | public class ManifestFormatTest 10 | { 11 | [Fact] 12 | public void FromPrefix() 13 | { 14 | ManifestFormat.FromPrefix("sha1new=abc").Should().BeSameAs(ManifestFormat.Sha1New); 15 | ManifestFormat.FromPrefix("sha256=abc").Should().BeSameAs(ManifestFormat.Sha256); 16 | ManifestFormat.FromPrefix("sha256new_abc").Should().BeSameAs(ManifestFormat.Sha256New); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Trust/BouncyCastleTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | using NanoByte.Common.Streams; 5 | 6 | namespace ZeroInstall.Store.Trust; 7 | 8 | /// 9 | /// Runs test methods for . 10 | /// 11 | public class BouncyCastleTest : OpenPgpTest, IDisposable 12 | { 13 | private readonly TemporaryDirectory _homeDir = new("0install-unit-test"); 14 | 15 | public void Dispose() => _homeDir?.Dispose(); 16 | 17 | protected override IOpenPgp OpenPgp => new BouncyCastle(_homeDir); 18 | 19 | protected override void DeployKeyRings() 20 | { 21 | typeof(OpenPgpTest).CopyEmbeddedToFile("pubring.gpg", Path.Combine(_homeDir, "pubring.gpg")); 22 | typeof(OpenPgpTest).CopyEmbeddedToFile("secring.gpg", Path.Combine(_homeDir, "secring.gpg")); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Trust/pubkey.gpg: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP PUBLIC KEY BLOCK----- 2 | Version: BCPG C# v1.7.4137.9283 3 | 4 | mI0EVDXfFQEEAOLv0eSdXtnEvW/pcQiky+8hINKO4SRekTkg2tTr/owJmoG4oyQ6 5 | tSxA7LQ+vzBxUO+yYaMkZ2g8KJBBkb/DCYI5FbGVJitj4TiZSOLxAHA/S3d5O6s8 6 | nZRVZHdC5/3kTtp5+BUvXHjyVEQauCwZycHTclCtqP7ECScqbT86LZetABEBAAG0 7 | HFRlc3QgVXNlciA8dGVzdEAwaW5zdGFsbC5kZT6IuAQTAQIAIgUCVDXfFQIbAwYL 8 | CQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ3u1EtJviRmGqkwP/aLRAgqfRJDzN 9 | I/Ogftwx2sOBDgGnC7x6AClRGZGG9kZBxuk6l0g6hzunIjlG/WVihWVbS0f40vv2 10 | hhV62BxJapalMqRYfTvwZ/UbKpC/nubfqVK9iP72iYoy/MxN39smC8iHEoNmzNxk 11 | PPmjyd2NRQ3NatHA0DR4KxS0mB0Vf+mwAgAD 12 | =bWBm 13 | -----END PGP PUBLIC KEY BLOCK----- 14 | -------------------------------------------------------------------------------- /src/UnitTests/Store/Trust/pubring.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Store/Trust/pubring.gpg -------------------------------------------------------------------------------- /src/UnitTests/Store/Trust/secring.gpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Store/Trust/secring.gpg -------------------------------------------------------------------------------- /src/UnitTests/Store/Trust/signature.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0install/0install-dotnet/1b498696d872f1c0456adc54f6b43e41b13be1cf/src/UnitTests/Store/Trust/signature.dat -------------------------------------------------------------------------------- /src/UnitTests/TestWithMocks.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall; 5 | 6 | /// 7 | /// Common base class for test fixtures that use a . 8 | /// 9 | public abstract class TestWithMocks : IDisposable 10 | { 11 | private readonly Dictionary _mocks = []; 12 | 13 | /// 14 | /// Retrieves a for a specific type. Multiple requests for the same type return the same mock instance. 15 | /// 16 | /// All created s are automatically verified after the test completes. 17 | protected Mock GetMock() where T : class 18 | => (Mock)_mocks.GetOrAdd(typeof(T), () => new Mock(MockBehavior.Strict)); 19 | 20 | public virtual void Dispose() 21 | { 22 | foreach (var mock in _mocks.Values) 23 | mock.VerifyAll(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/UnitTests/TestWithMocksAndRedirect.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall; 5 | 6 | /// 7 | /// Common base class for test fixtures that use a and . 8 | /// 9 | public abstract class TestWithMocksAndRedirect : TestWithMocks 10 | { 11 | private readonly TestWithRedirect _redirect = new(); 12 | 13 | public override void Dispose() 14 | { 15 | try 16 | { 17 | base.Dispose(); 18 | } 19 | finally 20 | { 21 | _redirect.Dispose(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/UnitTests/TestWithRedirect.cs: -------------------------------------------------------------------------------- 1 | // Copyright Bastian Eicher et al. 2 | // Licensed under the GNU Lesser Public License 3 | 4 | namespace ZeroInstall; 5 | 6 | /// 7 | /// Common base class for test fixtures that use . 8 | /// 9 | public class TestWithRedirect : IDisposable 10 | { 11 | private readonly TemporaryDirectory _tempDir; 12 | private readonly IDisposable _redirect; 13 | 14 | public TestWithRedirect() 15 | { 16 | _tempDir = new("0install-test-redirect"); 17 | _redirect = Locations.Redirect(_tempDir); 18 | } 19 | 20 | public virtual void Dispose() 21 | { 22 | _redirect.Dispose(); 23 | _tempDir.Dispose(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/XmlSerializer.Generator.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/build.ps1: -------------------------------------------------------------------------------- 1 | Param ([String]$Version = "1.0.0-pre") 2 | $ErrorActionPreference = "Stop" 3 | pushd $PSScriptRoot 4 | 5 | function Run-DotNet { 6 | ..\0install.ps1 run --batch --version 9.0.. https://apps.0install.net/dotnet/sdk.xml @args 7 | if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"} 8 | } 9 | 10 | echo "Build binaries" 11 | if ($env:CI) { $ci = "/p:ContinuousIntegrationBuild=True" } 12 | Run-DotNet msbuild /v:Quiet /t:Restore /t:Build /p:Configuration=Release /p:Version=$Version $ci 13 | 14 | echo "Prepare binaries for publishing" 15 | Run-DotNet msbuild /v:Quiet /t:Publish /p:NoBuild=True /p:BuildProjectReferences=False /p:Configuration=Release /p:TargetFramework=net8.0 /p:Version=$Version Commands 16 | Remove-Item ..\artifacts\Release\net8.0\publish\* -Include *.xml,*.pdb 17 | 18 | echo "Build minimal binaries" 19 | Run-DotNet msbuild /v:Quiet /t:Restore /t:Build /p:Configuration=Minimal /p:Version=$Version 20 | 21 | popd 22 | -------------------------------------------------------------------------------- /src/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | cd `dirname $0` 4 | 5 | # Find dotnet 6 | #if command -v dotnet > /dev/null 2> /dev/null; then 7 | # dotnet="dotnet" 8 | #else 9 | dotnet="../0install.sh run --version 9.0.. https://apps.0install.net/dotnet/sdk.xml" 10 | #fi 11 | 12 | # Avoid terminal rendering issues in CI 13 | if [ -n "$CI" ]; then 14 | export MSBUILDTERMINALLOGGER="off" 15 | fi 16 | 17 | echo "Build binaries" 18 | $dotnet msbuild -v:Quiet -t:Restore -t:Build -p:Configuration=Release -p:Version=${1:-1.0.0-pre} ${CI+-p:ContinuousIntegrationBuild=True} 19 | 20 | echo "Prepare binaries for publishing" 21 | $dotnet msbuild -v:Quiet -t:Publish -p:NoBuild=True -p:BuildProjectReferences=False -p:Configuration=Release -p:TargetFramework=net8.0 -p:Version=${1:-1.0.0-pre} Commands 22 | find ../artifacts/Release/net8.0/publish -name "{*.xml,*.pdb}" -type f -delete 23 | 24 | echo "Build minimal binaries" 25 | $dotnet msbuild -v:Quiet -t:Restore -t:Build -p:Configuration=Minimal -p:Version=${1:-1.0.0-pre} 26 | -------------------------------------------------------------------------------- /src/test.ps1: -------------------------------------------------------------------------------- 1 | $ErrorActionPreference = "Stop" 2 | pushd $PSScriptRoot 3 | 4 | function Run-DotNet { 5 | ..\0install.ps1 run --batch --version 9.0..!9.1 https://apps.0install.net/dotnet/sdk.xml @args 6 | if ($LASTEXITCODE -ne 0) {throw "Exit Code: $LASTEXITCODE"} 7 | } 8 | 9 | echo "Unit tests" 10 | Run-DotNet test --verbosity quiet --no-build --configuration Release UnitTests\UnitTests.csproj 11 | 12 | popd 13 | -------------------------------------------------------------------------------- /src/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | cd `dirname $0` 4 | 5 | # Find dotnet 6 | #if command -v dotnet > /dev/null 2> /dev/null; then 7 | # dotnet="dotnet" 8 | #else 9 | dotnet="../0install.sh run --version 9.0..!9.1 https://apps.0install.net/dotnet/sdk.xml" 10 | #fi 11 | 12 | echo "Unit tests" 13 | $dotnet test --verbosity quiet --no-build --configuration Release --framework net9.0 UnitTests/UnitTests.csproj 14 | --------------------------------------------------------------------------------