packages feed

fbrnch 0.9.1.1 → 1.0.0

raw patch · 59 files changed

+1229/−3784 lines, 59 filesdep +bodhidep +copr-apidep +fedora-distsdep −lensdep −lens-aesondep −unordered-containersdep ~bugzilla-redhatdep ~rpm-nvr

Dependencies added: bodhi, copr-api, fedora-dists, http-common, pagure, unix

Dependencies removed: lens, lens-aeson, unordered-containers

Dependency ranges changed: bugzilla-redhat, rpm-nvr

Files

CHANGELOG.md view
@@ -1,5 +1,82 @@ # Changelog +## next+- 'repoquery': new experimental command++## 1.0.0 (2022-02-21)+- rpm's _sourcedir is now acts as a source cache directory:+  sources are in the package dir, but may be hardlinks to _sourcedir+- getSources checks compression integrity to re-download partial tarballs+  and missing sources entries now only prompt once+- initial support for %autorelease (#24)+- 'build': consolidate nvr output+- 'build': skip branch if already built+- 'build': --changelog-notes to use spec changelog for Bodhi notes+- 'bump': new --local switch+- 'commit': --first-line to only use 1st line from changelog+- 'commit': --staged to only commit staged changes+- 'commit': extract incremental commit message from diff+- 'copr': --exclude-arch option+- 'count': new command to count packages with .spec files+- 'diff': new --status, --filter and --filter-not options+- 'log' renamed to 'compare'+- 'mock': use system arch, not hardcoded to x86_64+- 'parallel': more compact and precise output+- 'parallel': only sleep 3s for job start and 1s when job still pending+- 'parallel': error with pending package layers and number of packages+- 'parallel': new --skip-to-layer option for restarting after failure+- 'prep': --clone option+- 'prep': install any required srpm macros (golang, rust, fonts)+- 'reviews': output one line per package+- 'switch': informative error when detached and use "git switch"+- 'update': --source-only to update sources without version bump+- 'update': add --force to re-download sources from upstream+- 'update': check changelog versions before bumping+- 'update': use --allow-head for updating a detached rebase+- error with package name when no .spec file found+- Merge: rebase after non-ancestor merge+- ListReviews: use anonymous bugzilla queries+- checkOnBranch and gitCurrentBranch now prompt if detached HEAD++- update to bugzilla-redhat-1.0 and use API key bzApiKeySession+- 'build': build by branch by default instead of by package, if >1 package+- 'build': --[no-]waitrepo option changes default behavior with autoupdate+- 'commit': replace --staged with --unstaged+- 'commit': tweak changelog filter to "+- " prefix+- 'copr': handle --all-fedora and --all-epel+- 'list': use pagure-hs release with new Object API+- 'mock': add --no-clean-all and --shell to enter chroot after building+- 'parallel': output enhancements+- 'prep': add --pull option (alternative to --clone)+- 'prep': add --verbose for prep output+- 'pull': add --lenient to ignore non-git dirs/files+- 'pull': handle old master branch better+- 'push': new git push command+- 'rename-master' renamed to 'rename-rawhide'+- 'request-branches': output branch names with newline+- 'scratch': print package header by default+- 'sort': add --parallel option to group dependent packages+- 'update': only run spectool -g once with --force+- 'update': only sed edit sources if it exists+- 'update': improve the mver/pkg/dirty logic+- Bodhi: fix for aeson-2.0+- Bugzilla: getBzUser save email id in ~/.config/fbrnch/bugzilla+- Bugzilla: many queries now use anonymous session+- Krb: factor out klistEntryFedora adding maybeFasIdFromKrb+- Krb: klist errors if no tickets+- Package: add checkLookasideCache to checkSourcesMatch+- Package: builtRpms: check in %_rpmdir if not distgit+- Package: fix lookaside check url+- Package: handle Dynamic BRs locally+- Package: refactor checkCompression+- allow anonymous cloning of packages+- decouple bodhi-hs, copr-hs, pagure-hs, pdc-hs+- fedora-dists-2.0 was released: remove the submodule+- kojiWatchTask: don't backtrace for task failure+- latest fedora-dists uses cached-json-file & has better releaseBranch err+- readme: note https checkouts currently assumed anonymous (#27)+- require rpm-nvr-0.1.1 for VerComp bugfix+ ## 0.9.1.1 (2021-08-01) - getSources: fix mixup between sources and patches - 'reviews': add --pattern for package prefix
README.md view
@@ -96,7 +96,7 @@  One can change the branch of one or more packages: ```-$ fbrnch switch f34 [package] ...+$ fbrnch switch f35 [package] ... ```  You can also git pull over packages:@@ -144,13 +144,13 @@  You can merge branches with: ```-$ fbrnch merge f33 package+$ fbrnch merge f34 package ```-which will offer to merge f34 (or some of it) into f33.+which will offer to merge f35 (or some of it) into f34.  Merging can also be done together with building: ```-$ fbrnch build f34 package+$ fbrnch build f35 package ``` will ask if you want to merge newer commits from a newer branch, then push and build it.@@ -233,9 +233,9 @@  ``` $ fbrnch --version-0.9.1.1+1.0.0 $ fbrnch --help-Fedora package branch building tool+Fedora branch building tool  Usage: fbrnch [--version] COMMAND   This tool helps with updating and building package branches@@ -264,7 +264,7 @@   local                    Build locally   srpm                     Build srpm   diff                     Diff local changes-  log                      Show commits between branches+  compare                  Show commits between branches   mock                     Local mock build   install-deps             Install package build dependencies   install                  Build locally and install package(s)@@ -273,6 +273,7 @@   bump                     Bump release for package   commit                   Git commit packages   pull                     Git pull packages+  push                     Git push packages   create-review            Create a Package Review request   update-review            Update a Package Review   review-package           Run fedora-review on a package Review Request bug@@ -284,39 +285,18 @@   find-review              Find package review bug   command                  Run shell command in package dirs ($p)   copr                     Build package(s) in Fedora Copr-  rename-master            Rename local master branch to rawhide+  rename-rawhide           Rename local 'master' branch to 'rawhide'+  count                    Count number of living packages   graph                    Output dependency graph ``` -## Known issues-- parallel builds will push local package commits without asking-- currently it only checks if already built by NVR not githash-- authentication is not implemented yet natively for Koji, Bodhi, Pagure-  (and source upload)-  - so python clients are used for "writing"-    (specifically koji, bodhi-client, fedpkg),-    but all queries are done directly by Web APIs for speed and control.--## Motivation, history, talks-This project started off (as "fedbrnch") basically as a simple tool to-build a package across branches (ie for current releases).  Then bugzilla-and Bodhi integration was added, and gradually more features, including-some generic commands across packages which had already been done before-in fedora-haskell-tools.--I have given a couple of short talks about fbranch:-- Nest with Fedora: [youtube](https://www.youtube.com/watch?v=40kTBsA674U) and [slides](https://github.com/juhp/presentations/blob/master/fedora-nest-2020-fbrnch/fbrnch-nest.md)-- Lightning talk at devconf.cz 2021: [youtube](https://www.youtube.com/watch?v=O2-6rDuPMRA&t=2s)- ## Installation fbrnch is packaged in Fedora: `sudo dnf install fbrnch`.  ## Build from source 1. Install openssl-devel -2. Clone the git repo and in the source dir, setup the git submodules:--`git submodule update --init`+2. Clone the git repo.  3. Then either: @@ -345,6 +325,28 @@ - klist and fkinit - git - ssh & scp (for uploading package reviews)+- bugzilla API key++## Known issues+- parallel builds will push local package commits without asking+- currently it only checks if already built by NVR not githash+- authentication is not implemented yet natively for Koji, Bodhi, Pagure+  (and source upload)+  - so python clients are used for "writing"+    (specifically koji, bodhi-client, fedpkg),+    but all queries are done directly by Web APIs for speed and control.+- https checkouts are currently assumed to an anonymous git checkouts++## Motivation, history, talks+This project started off (as "fedbrnch") basically as a simple tool to+build a package across branches (ie for current releases).  Then bugzilla+and Bodhi integration was added, and gradually more features, including+some generic commands across packages which had already been done before+in fedora-haskell-tools.++I have given a couple of short talks about fbranch:+- Nest with Fedora: [youtube](https://www.youtube.com/watch?v=40kTBsA674U) and [slides](https://github.com/juhp/presentations/blob/master/fedora-nest-2020-fbrnch/fbrnch-nest.md)+- Lightning talk at devconf.cz 2021: [youtube](https://www.youtube.com/watch?v=O2-6rDuPMRA&t=2s)  ## Contribute Bug reports, feedback, and pull requests welcome.
fbrnch.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.0 name:                fbrnch-version:             0.9.1.1+version:             1.0.0 synopsis:            Build and create Fedora package repos and branches description:             fbrnch (fedora branch) is a convenient packaging tool for@@ -27,18 +27,13 @@ license-file:        LICENSE author:              Jens Petersen <petersen@redhat.com> maintainer:          Jens Petersen <petersen@fedoraproject.org>-copyright:           2019-2021 Jens Petersen+copyright:           2019-2022 Jens Petersen category:            Distribution build-type:          Simple extra-doc-files:     CHANGELOG.md                      README.md-                     libs/bodhi-hs/LICENSE-                     libs/copr-hs/LICENSE-                     libs/fedora-dists/LICENSE-                     libs/pagure-hs/LICENSE-                     libs/pdc-hs/LICENSE tested-with:         GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4,-                     GHC == 8.6.5,  GHC == 8.8.4, GHC == 8.10.4+                     GHC == 8.6.5,  GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2  source-repository head   type:                git@@ -68,7 +63,8 @@                        Cmd.Override                        Cmd.Parallel                        Cmd.PkgReview-                       Cmd.Pull+                       Cmd.Prep+                       Cmd.PullPush                        Cmd.Repoquery                        Cmd.RequestBranch                        Cmd.RequestRepo@@ -92,69 +88,51 @@                        Pagure                        Paths_fbrnch                        Prompt-                       -- copr-                       Web.Fedora.Copr-                       Web.Fedora.Copr.API-                       -- fedora-dists-                       Distribution.Fedora-                       Distribution.Fedora.Branch-                       Distribution.Fedora.Products-                       Distribution.Fedora.ReadProducts-                       -- pdc-                       Fedora.PDC-                       -- bodhi-                       Fedora.Bodhi-                       -- pagure-                       Fedora.Pagure+                       Types    hs-source-dirs:      src-                       libs/copr-hs/src-                       libs/fedora-dists/src-                       libs/pdc-hs/src-                       libs/bodhi-hs/src-                       libs/pagure-hs/src   default-language:    Haskell2010    build-depends:       aeson,                        async,                        -- pretty-terminal needs 4.9:                        base >= 4.9 && < 5,-                       -- bodhi,-                       bugzilla-redhat >= 0.3,+                       bodhi,+                       bugzilla-redhat >= 1.0,                        bytestring,                        config-ini,-                       -- copr,+                       copr-api,                        directory >= 1.2.3,                        email-validate,                        extra,-                       -- fedora-dists > 2.0,+                       fedora-dists >= 2.0,                        filepath,                        http-conduit,                        http-directory >= 0.1.5,                        http-query,                        koji,                        network-uri,+                       -- (for simple_cmd_args < 0.1.7):                        optparse-applicative,-                       -- pagure,+                       pagure >= 0.1,                        pretty-terminal,                        process,+                       -- regex-tdfa,                        rpmbuild-order >= 0.4.5,-                       rpm-nvr,+                       rpm-nvr >= 0.1.1,                        simple-cmd >= 0.2.0,                        simple-cmd-args >= 0.1.6,                        text,                        time,                        typed-process >= 0.2.4.0,                        utf8-string,-                       xdg-basedir,-                       -- for copr:-                       unordered-containers,-                       -- for bodhi and pagure:-                       lens,-                       lens-aeson+                       unix,+                       xdg-basedir -  if impl(ghc<8.0)+  if impl(ghc<8.3)        build-depends: semigroups+  if impl(ghc<8.4)+       build-depends: http-common < 0.8.3.4    ghc-options:         -threaded                        -Wall
− libs/bodhi-hs/LICENSE
@@ -1,21 +0,0 @@-MIT License--Copyright (c) 2020 Jens Petersen--Permission is hereby granted, free of charge, to any person obtaining a copy-of this software and associated documentation files (the "Software"), to deal-in the Software without restriction, including without limitation the rights-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell-copies of the Software, and to permit persons to whom the Software is-furnished to do so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.
− libs/bodhi-hs/src/Fedora/Bodhi.hs
@@ -1,187 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings #-}--{- |-Copyright: (c) 2020 Jens Petersen-SPDX-License-Identifier: MIT-Maintainer: Jens Petersen <juhpetersen@gmail.com>--Fedora Bodhi REST client library--}--module Fedora.Bodhi-  ( bodhiBuild-  , bodhiBuilds-  , bodhiComment-  , bodhiComments-  , bodhiCSRF-  , bodhiOverride-  , bodhiOverrides-  , bodhiOverrideDates-  , bodhiPackages-  , bodhiRelease-  , bodhiReleases-  , bodhiUpdate-  , bodhiUpdates-  , bodhiUser-  , bodhiUsers-  , lookupKey-  , lookupKey'-  , queryBodhi-  , makeKey-  , makeItem-  , maybeKey-  , Query-  , QueryItem-  ) where--#if (defined(VERSION_lens_aeson))-import Control.Lens-import Data.Aeson.Lens-#else-import Lens.Micro-import Lens.Micro.Aeson-#endif-import Data.Aeson.Types-import Data.Text (Text)-import Data.Time.LocalTime-import Network.HTTP.Query--server :: String-server = "bodhi.fedoraproject.org"---- | Returns build JSON for NVR------ https://bodhi.fedoraproject.org/docs/server_api/rest/builds.html#service-0-bodhiBuild :: String -> IO Object-bodhiBuild nvr = do-  res <- queryBodhi [] $ "builds" +/+ nvr-  return $ res ^. _Object---- | returns JSON list of builds------ https://bodhi.fedoraproject.org/docs/server_api/rest/builds.html#service-1-bodhiBuilds :: Query -> IO [Object]-bodhiBuilds params = do-  res <- queryBodhi params "builds/"-  return $ res ^.. key "builds" . values . _Object---- | Returns comment JSON for id------ https://bodhi.fedoraproject.org/docs/server_api/rest/comments.html#service-0-bodhiComment :: String -> IO Object-bodhiComment cid = do-  res <- queryBodhi [] $ "comments" +/+ cid-  return $ res ^. _Object---- | returns JSON list of comments------ https://bodhi.fedoraproject.org/docs/server_api/rest/comments.html#service-1-bodhiComments :: Query -> IO [Object]-bodhiComments params = do-  res <- queryBodhi params "comments/"-  return $ res ^.. key "comments" . values . _Object---- | Get CSRF token------ https://bodhi.fedoraproject.org/docs/server_api/rest/csrf.html-bodhiCSRF :: IO (Maybe Text)-bodhiCSRF = do-  res <- queryBodhi [] "csrf"-  return $ res ^? key "csrf_token" . _String---- | Returns override JSON for NVR------ https://bodhi.fedoraproject.org/docs/server_api/rest/overrides.html#service-0-bodhiOverride :: String -> IO (Maybe Object)-bodhiOverride nvr = do-  res <- queryBodhi [] $ "overrides" +/+ nvr-  return $ res ^? key "override" . _Object---- | Returns override expiration and submission dates for NVR-bodhiOverrideDates :: String -> IO (Maybe (LocalTime,LocalTime))-bodhiOverrideDates nvr = do-  mobj <- bodhiOverride nvr-  case mobj of-    Nothing -> do-      putStrLn $ "Override for " ++ nvr ++ " not found"-      return Nothing-    Just obj -> return $ readDates obj-  where-    readDates :: Object -> Maybe (LocalTime,LocalTime)-    readDates =-      parseMaybe $ \obj -> do-        expire <- obj .: "expiration_date"-        submit <- obj .: "submission_date"-        return (expire,submit)---- | returns JSON list of overrides------ https://bodhi.fedoraproject.org/docs/server_api/rest/overrides.html#service-1-bodhiOverrides :: Query -> IO [Object]-bodhiOverrides params = do-  res <- queryBodhi params "overrides/"-  return $ res ^.. key "overrides" . values . _Object---- | Packages query------ https://bodhi.fedoraproject.org/docs/server_api/rest/packages.html#service-0-bodhiPackages :: Query -> IO [Object]-bodhiPackages params = do-  res <- queryBodhi params "packages/"-  return $ res ^.. key "packages" . values . _Object---- | read releases metadata from Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/releases.html#service-0-bodhiRelease :: String -> IO Object-bodhiRelease rel = do-  res <- queryBodhi [] $ "releases" +/+ rel-  return $ res ^. _Object---- | read releases metadata from Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/releases.html#service-1-bodhiReleases :: Query -> IO [Object]--- FIXME handle errors:--- fromList [("status",String "error"),("errors",Array [Object (fromList [("location",String "body"),("name",String "name"),("description",String "No such release")])])]-bodhiReleases params = do-  res <- queryBodhi params "releases/"-  return $ res ^.. key "releases" . values . _Object---- | read an update from Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/updates.html#service-0-bodhiUpdate :: String -> IO (Maybe Object)-bodhiUpdate update = do-  res <- queryBodhi [] $ "updates" +/+ update-  return $ res ^? key "update" . _Object---- | search for updates on Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/updates.html#service-2-bodhiUpdates :: Query -> IO [Object]-bodhiUpdates params = do-  res <- queryBodhi params "updates/"-  return $ res ^.. key "updates" . values . _Object---- | user info from Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/users.html#service-0-bodhiUser :: String -> IO Object-bodhiUser user = do-  res <- queryBodhi [] $ "users" +/+ user-  return $ res ^. _Object---- | list users from Bodhi------ https://bodhi.fedoraproject.org/docs/server_api/rest/users.html#service-1-bodhiUsers :: Query -> IO [Object]-bodhiUsers params = do-  res <- queryBodhi params "users/"-  return $ res ^.. key "users" . values . _Object---- | low-level query-queryBodhi :: Query -> String -> IO Value-queryBodhi params path =-  let url = "https://" ++ server +/+ path-  in webAPIQuery url params
− libs/copr-hs/LICENSE
@@ -1,674 +0,0 @@-                    GNU GENERAL PUBLIC LICENSE-                       Version 3, 29 June 2007-- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.--                            Preamble--  The GNU General Public License is a free, copyleft license for-software and other kinds of works.--  The licenses for most software and other practical works are designed-to take away your freedom to share and change the works.  By contrast,-the GNU General Public License is intended to guarantee your freedom to-share and change all versions of a program--to make sure it remains free-software for all its users.  We, the Free Software Foundation, use the-GNU General Public License for most of our software; it applies also to-any other work released this way by its authors.  You can apply it to-your programs, too.--  When we speak of free software, we are referring to freedom, not-price.  Our General Public Licenses are designed to make sure that you-have the freedom to distribute copies of free software (and charge for-them if you wish), that you receive source code or can get it if you-want it, that you can change the software or use pieces of it in new-free programs, and that you know you can do these things.--  To protect your rights, we need to prevent others from denying you-these rights or asking you to surrender the rights.  Therefore, you have-certain responsibilities if you distribute copies of the software, or if-you modify it: responsibilities to respect the freedom of others.--  For example, if you distribute copies of such a program, whether-gratis or for a fee, you must pass on to the recipients the same-freedoms that you received.  You must make sure that they, too, receive-or can get the source code.  And you must show them these terms so they-know their rights.--  Developers that use the GNU GPL protect your rights with two steps:-(1) assert copyright on the software, and (2) offer you this License-giving you legal permission to copy, distribute and/or modify it.--  For the developers' and authors' protection, the GPL clearly explains-that there is no warranty for this free software.  For both users' and-authors' sake, the GPL requires that modified versions be marked as-changed, so that their problems will not be attributed erroneously to-authors of previous versions.--  Some devices are designed to deny users access to install or run-modified versions of the software inside them, although the manufacturer-can do so.  This is fundamentally incompatible with the aim of-protecting users' freedom to change the software.  The systematic-pattern of such abuse occurs in the area of products for individuals to-use, which is precisely where it is most unacceptable.  Therefore, we-have designed this version of the GPL to prohibit the practice for those-products.  If such problems arise substantially in other domains, we-stand ready to extend this provision to those domains in future versions-of the GPL, as needed to protect the freedom of users.--  Finally, every program is threatened constantly by software patents.-States should not allow patents to restrict development and use of-software on general-purpose computers, but in those that do, we wish to-avoid the special danger that patents applied to a free program could-make it effectively proprietary.  To prevent this, the GPL assures that-patents cannot be used to render the program non-free.--  The precise terms and conditions for copying, distribution and-modification follow.--                       TERMS AND CONDITIONS--  0. Definitions.--  "This License" refers to version 3 of the GNU General Public License.--  "Copyright" also means copyright-like laws that apply to other kinds of-works, such as semiconductor masks.--  "The Program" refers to any copyrightable work licensed under this-License.  Each licensee is addressed as "you".  "Licensees" and-"recipients" may be individuals or organizations.--  To "modify" a work means to copy from or adapt all or part of the work-in a fashion requiring copyright permission, other than the making of an-exact copy.  The resulting work is called a "modified version" of the-earlier work or a work "based on" the earlier work.--  A "covered work" means either the unmodified Program or a work based-on the Program.--  To "propagate" a work means to do anything with it that, without-permission, would make you directly or secondarily liable for-infringement under applicable copyright law, except executing it on a-computer or modifying a private copy.  Propagation includes copying,-distribution (with or without modification), making available to the-public, and in some countries other activities as well.--  To "convey" a work means any kind of propagation that enables other-parties to make or receive copies.  Mere interaction with a user through-a computer network, with no transfer of a copy, is not conveying.--  An interactive user interface displays "Appropriate Legal Notices"-to the extent that it includes a convenient and prominently visible-feature that (1) displays an appropriate copyright notice, and (2)-tells the user that there is no warranty for the work (except to the-extent that warranties are provided), that licensees may convey the-work under this License, and how to view a copy of this License.  If-the interface presents a list of user commands or options, such as a-menu, a prominent item in the list meets this criterion.--  1. Source Code.--  The "source code" for a work means the preferred form of the work-for making modifications to it.  "Object code" means any non-source-form of a work.--  A "Standard Interface" means an interface that either is an official-standard defined by a recognized standards body, or, in the case of-interfaces specified for a particular programming language, one that-is widely used among developers working in that language.--  The "System Libraries" of an executable work include anything, other-than the work as a whole, that (a) is included in the normal form of-packaging a Major Component, but which is not part of that Major-Component, and (b) serves only to enable use of the work with that-Major Component, or to implement a Standard Interface for which an-implementation is available to the public in source code form.  A-"Major Component", in this context, means a major essential component-(kernel, window system, and so on) of the specific operating system-(if any) on which the executable work runs, or a compiler used to-produce the work, or an object code interpreter used to run it.--  The "Corresponding Source" for a work in object code form means all-the source code needed to generate, install, and (for an executable-work) run the object code and to modify the work, including scripts to-control those activities.  However, it does not include the work's-System Libraries, or general-purpose tools or generally available free-programs which are used unmodified in performing those activities but-which are not part of the work.  For example, Corresponding Source-includes interface definition files associated with source files for-the work, and the source code for shared libraries and dynamically-linked subprograms that the work is specifically designed to require,-such as by intimate data communication or control flow between those-subprograms and other parts of the work.--  The Corresponding Source need not include anything that users-can regenerate automatically from other parts of the Corresponding-Source.--  The Corresponding Source for a work in source code form is that-same work.--  2. Basic Permissions.--  All rights granted under this License are granted for the term of-copyright on the Program, and are irrevocable provided the stated-conditions are met.  This License explicitly affirms your unlimited-permission to run the unmodified Program.  The output from running a-covered work is covered by this License only if the output, given its-content, constitutes a covered work.  This License acknowledges your-rights of fair use or other equivalent, as provided by copyright law.--  You may make, run and propagate covered works that you do not-convey, without conditions so long as your license otherwise remains-in force.  You may convey covered works to others for the sole purpose-of having them make modifications exclusively for you, or provide you-with facilities for running those works, provided that you comply with-the terms of this License in conveying all material for which you do-not control copyright.  Those thus making or running the covered works-for you must do so exclusively on your behalf, under your direction-and control, on terms that prohibit them from making any copies of-your copyrighted material outside their relationship with you.--  Conveying under any other circumstances is permitted solely under-the conditions stated below.  Sublicensing is not allowed; section 10-makes it unnecessary.--  3. Protecting Users' Legal Rights From Anti-Circumvention Law.--  No covered work shall be deemed part of an effective technological-measure under any applicable law fulfilling obligations under article-11 of the WIPO copyright treaty adopted on 20 December 1996, or-similar laws prohibiting or restricting circumvention of such-measures.--  When you convey a covered work, you waive any legal power to forbid-circumvention of technological measures to the extent such circumvention-is effected by exercising rights under this License with respect to-the covered work, and you disclaim any intention to limit operation or-modification of the work as a means of enforcing, against the work's-users, your or third parties' legal rights to forbid circumvention of-technological measures.--  4. Conveying Verbatim Copies.--  You may convey verbatim copies of the Program's source code as you-receive it, in any medium, provided that you conspicuously and-appropriately publish on each copy an appropriate copyright notice;-keep intact all notices stating that this License and any-non-permissive terms added in accord with section 7 apply to the code;-keep intact all notices of the absence of any warranty; and give all-recipients a copy of this License along with the Program.--  You may charge any price or no price for each copy that you convey,-and you may offer support or warranty protection for a fee.--  5. Conveying Modified Source Versions.--  You may convey a work based on the Program, or the modifications to-produce it from the Program, in the form of source code under the-terms of section 4, provided that you also meet all of these conditions:--    a) The work must carry prominent notices stating that you modified-    it, and giving a relevant date.--    b) The work must carry prominent notices stating that it is-    released under this License and any conditions added under section-    7.  This requirement modifies the requirement in section 4 to-    "keep intact all notices".--    c) You must license the entire work, as a whole, under this-    License to anyone who comes into possession of a copy.  This-    License will therefore apply, along with any applicable section 7-    additional terms, to the whole of the work, and all its parts,-    regardless of how they are packaged.  This License gives no-    permission to license the work in any other way, but it does not-    invalidate such permission if you have separately received it.--    d) If the work has interactive user interfaces, each must display-    Appropriate Legal Notices; however, if the Program has interactive-    interfaces that do not display Appropriate Legal Notices, your-    work need not make them do so.--  A compilation of a covered work with other separate and independent-works, which are not by their nature extensions of the covered work,-and which are not combined with it such as to form a larger program,-in or on a volume of a storage or distribution medium, is called an-"aggregate" if the compilation and its resulting copyright are not-used to limit the access or legal rights of the compilation's users-beyond what the individual works permit.  Inclusion of a covered work-in an aggregate does not cause this License to apply to the other-parts of the aggregate.--  6. Conveying Non-Source Forms.--  You may convey a covered work in object code form under the terms-of sections 4 and 5, provided that you also convey the-machine-readable Corresponding Source under the terms of this License,-in one of these ways:--    a) Convey the object code in, or embodied in, a physical product-    (including a physical distribution medium), accompanied by the-    Corresponding Source fixed on a durable physical medium-    customarily used for software interchange.--    b) Convey the object code in, or embodied in, a physical product-    (including a physical distribution medium), accompanied by a-    written offer, valid for at least three years and valid for as-    long as you offer spare parts or customer support for that product-    model, to give anyone who possesses the object code either (1) a-    copy of the Corresponding Source for all the software in the-    product that is covered by this License, on a durable physical-    medium customarily used for software interchange, for a price no-    more than your reasonable cost of physically performing this-    conveying of source, or (2) access to copy the-    Corresponding Source from a network server at no charge.--    c) Convey individual copies of the object code with a copy of the-    written offer to provide the Corresponding Source.  This-    alternative is allowed only occasionally and noncommercially, and-    only if you received the object code with such an offer, in accord-    with subsection 6b.--    d) Convey the object code by offering access from a designated-    place (gratis or for a charge), and offer equivalent access to the-    Corresponding Source in the same way through the same place at no-    further charge.  You need not require recipients to copy the-    Corresponding Source along with the object code.  If the place to-    copy the object code is a network server, the Corresponding Source-    may be on a different server (operated by you or a third party)-    that supports equivalent copying facilities, provided you maintain-    clear directions next to the object code saying where to find the-    Corresponding Source.  Regardless of what server hosts the-    Corresponding Source, you remain obligated to ensure that it is-    available for as long as needed to satisfy these requirements.--    e) Convey the object code using peer-to-peer transmission, provided-    you inform other peers where the object code and Corresponding-    Source of the work are being offered to the general public at no-    charge under subsection 6d.--  A separable portion of the object code, whose source code is excluded-from the Corresponding Source as a System Library, need not be-included in conveying the object code work.--  A "User Product" is either (1) a "consumer product", which means any-tangible personal property which is normally used for personal, family,-or household purposes, or (2) anything designed or sold for incorporation-into a dwelling.  In determining whether a product is a consumer product,-doubtful cases shall be resolved in favor of coverage.  For a particular-product received by a particular user, "normally used" refers to a-typical or common use of that class of product, regardless of the status-of the particular user or of the way in which the particular user-actually uses, or expects or is expected to use, the product.  A product-is a consumer product regardless of whether the product has substantial-commercial, industrial or non-consumer uses, unless such uses represent-the only significant mode of use of the product.--  "Installation Information" for a User Product means any methods,-procedures, authorization keys, or other information required to install-and execute modified versions of a covered work in that User Product from-a modified version of its Corresponding Source.  The information must-suffice to ensure that the continued functioning of the modified object-code is in no case prevented or interfered with solely because-modification has been made.--  If you convey an object code work under this section in, or with, or-specifically for use in, a User Product, and the conveying occurs as-part of a transaction in which the right of possession and use of the-User Product is transferred to the recipient in perpetuity or for a-fixed term (regardless of how the transaction is characterized), the-Corresponding Source conveyed under this section must be accompanied-by the Installation Information.  But this requirement does not apply-if neither you nor any third party retains the ability to install-modified object code on the User Product (for example, the work has-been installed in ROM).--  The requirement to provide Installation Information does not include a-requirement to continue to provide support service, warranty, or updates-for a work that has been modified or installed by the recipient, or for-the User Product in which it has been modified or installed.  Access to a-network may be denied when the modification itself materially and-adversely affects the operation of the network or violates the rules and-protocols for communication across the network.--  Corresponding Source conveyed, and Installation Information provided,-in accord with this section must be in a format that is publicly-documented (and with an implementation available to the public in-source code form), and must require no special password or key for-unpacking, reading or copying.--  7. Additional Terms.--  "Additional permissions" are terms that supplement the terms of this-License by making exceptions from one or more of its conditions.-Additional permissions that are applicable to the entire Program shall-be treated as though they were included in this License, to the extent-that they are valid under applicable law.  If additional permissions-apply only to part of the Program, that part may be used separately-under those permissions, but the entire Program remains governed by-this License without regard to the additional permissions.--  When you convey a copy of a covered work, you may at your option-remove any additional permissions from that copy, or from any part of-it.  (Additional permissions may be written to require their own-removal in certain cases when you modify the work.)  You may place-additional permissions on material, added by you to a covered work,-for which you have or can give appropriate copyright permission.--  Notwithstanding any other provision of this License, for material you-add to a covered work, you may (if authorized by the copyright holders of-that material) supplement the terms of this License with terms:--    a) Disclaiming warranty or limiting liability differently from the-    terms of sections 15 and 16 of this License; or--    b) Requiring preservation of specified reasonable legal notices or-    author attributions in that material or in the Appropriate Legal-    Notices displayed by works containing it; or--    c) Prohibiting misrepresentation of the origin of that material, or-    requiring that modified versions of such material be marked in-    reasonable ways as different from the original version; or--    d) Limiting the use for publicity purposes of names of licensors or-    authors of the material; or--    e) Declining to grant rights under trademark law for use of some-    trade names, trademarks, or service marks; or--    f) Requiring indemnification of licensors and authors of that-    material by anyone who conveys the material (or modified versions of-    it) with contractual assumptions of liability to the recipient, for-    any liability that these contractual assumptions directly impose on-    those licensors and authors.--  All other non-permissive additional terms are considered "further-restrictions" within the meaning of section 10.  If the Program as you-received it, or any part of it, contains a notice stating that it is-governed by this License along with a term that is a further-restriction, you may remove that term.  If a license document contains-a further restriction but permits relicensing or conveying under this-License, you may add to a covered work material governed by the terms-of that license document, provided that the further restriction does-not survive such relicensing or conveying.--  If you add terms to a covered work in accord with this section, you-must place, in the relevant source files, a statement of the-additional terms that apply to those files, or a notice indicating-where to find the applicable terms.--  Additional terms, permissive or non-permissive, may be stated in the-form of a separately written license, or stated as exceptions;-the above requirements apply either way.--  8. Termination.--  You may not propagate or modify a covered work except as expressly-provided under this License.  Any attempt otherwise to propagate or-modify it is void, and will automatically terminate your rights under-this License (including any patent licenses granted under the third-paragraph of section 11).--  However, if you cease all violation of this License, then your-license from a particular copyright holder is reinstated (a)-provisionally, unless and until the copyright holder explicitly and-finally terminates your license, and (b) permanently, if the copyright-holder fails to notify you of the violation by some reasonable means-prior to 60 days after the cessation.--  Moreover, your license from a particular copyright holder is-reinstated permanently if the copyright holder notifies you of the-violation by some reasonable means, this is the first time you have-received notice of violation of this License (for any work) from that-copyright holder, and you cure the violation prior to 30 days after-your receipt of the notice.--  Termination of your rights under this section does not terminate the-licenses of parties who have received copies or rights from you under-this License.  If your rights have been terminated and not permanently-reinstated, you do not qualify to receive new licenses for the same-material under section 10.--  9. Acceptance Not Required for Having Copies.--  You are not required to accept this License in order to receive or-run a copy of the Program.  Ancillary propagation of a covered work-occurring solely as a consequence of using peer-to-peer transmission-to receive a copy likewise does not require acceptance.  However,-nothing other than this License grants you permission to propagate or-modify any covered work.  These actions infringe copyright if you do-not accept this License.  Therefore, by modifying or propagating a-covered work, you indicate your acceptance of this License to do so.--  10. Automatic Licensing of Downstream Recipients.--  Each time you convey a covered work, the recipient automatically-receives a license from the original licensors, to run, modify and-propagate that work, subject to this License.  You are not responsible-for enforcing compliance by third parties with this License.--  An "entity transaction" is a transaction transferring control of an-organization, or substantially all assets of one, or subdividing an-organization, or merging organizations.  If propagation of a covered-work results from an entity transaction, each party to that-transaction who receives a copy of the work also receives whatever-licenses to the work the party's predecessor in interest had or could-give under the previous paragraph, plus a right to possession of the-Corresponding Source of the work from the predecessor in interest, if-the predecessor has it or can get it with reasonable efforts.--  You may not impose any further restrictions on the exercise of the-rights granted or affirmed under this License.  For example, you may-not impose a license fee, royalty, or other charge for exercise of-rights granted under this License, and you may not initiate litigation-(including a cross-claim or counterclaim in a lawsuit) alleging that-any patent claim is infringed by making, using, selling, offering for-sale, or importing the Program or any portion of it.--  11. Patents.--  A "contributor" is a copyright holder who authorizes use under this-License of the Program or a work on which the Program is based.  The-work thus licensed is called the contributor's "contributor version".--  A contributor's "essential patent claims" are all patent claims-owned or controlled by the contributor, whether already acquired or-hereafter acquired, that would be infringed by some manner, permitted-by this License, of making, using, or selling its contributor version,-but do not include claims that would be infringed only as a-consequence of further modification of the contributor version.  For-purposes of this definition, "control" includes the right to grant-patent sublicenses in a manner consistent with the requirements of-this License.--  Each contributor grants you a non-exclusive, worldwide, royalty-free-patent license under the contributor's essential patent claims, to-make, use, sell, offer for sale, import and otherwise run, modify and-propagate the contents of its contributor version.--  In the following three paragraphs, a "patent license" is any express-agreement or commitment, however denominated, not to enforce a patent-(such as an express permission to practice a patent or covenant not to-sue for patent infringement).  To "grant" such a patent license to a-party means to make such an agreement or commitment not to enforce a-patent against the party.--  If you convey a covered work, knowingly relying on a patent license,-and the Corresponding Source of the work is not available for anyone-to copy, free of charge and under the terms of this License, through a-publicly available network server or other readily accessible means,-then you must either (1) cause the Corresponding Source to be so-available, or (2) arrange to deprive yourself of the benefit of the-patent license for this particular work, or (3) arrange, in a manner-consistent with the requirements of this License, to extend the patent-license to downstream recipients.  "Knowingly relying" means you have-actual knowledge that, but for the patent license, your conveying the-covered work in a country, or your recipient's use of the covered work-in a country, would infringe one or more identifiable patents in that-country that you have reason to believe are valid.--  If, pursuant to or in connection with a single transaction or-arrangement, you convey, or propagate by procuring conveyance of, a-covered work, and grant a patent license to some of the parties-receiving the covered work authorizing them to use, propagate, modify-or convey a specific copy of the covered work, then the patent license-you grant is automatically extended to all recipients of the covered-work and works based on it.--  A patent license is "discriminatory" if it does not include within-the scope of its coverage, prohibits the exercise of, or is-conditioned on the non-exercise of one or more of the rights that are-specifically granted under this License.  You may not convey a covered-work if you are a party to an arrangement with a third party that is-in the business of distributing software, under which you make payment-to the third party based on the extent of your activity of conveying-the work, and under which the third party grants, to any of the-parties who would receive the covered work from you, a discriminatory-patent license (a) in connection with copies of the covered work-conveyed by you (or copies made from those copies), or (b) primarily-for and in connection with specific products or compilations that-contain the covered work, unless you entered into that arrangement,-or that patent license was granted, prior to 28 March 2007.--  Nothing in this License shall be construed as excluding or limiting-any implied license or other defenses to infringement that may-otherwise be available to you under applicable patent law.--  12. No Surrender of Others' Freedom.--  If conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License.  If you cannot convey a-covered work so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you may-not convey it at all.  For example, if you agree to terms that obligate you-to collect a royalty for further conveying from those to whom you convey-the Program, the only way you could satisfy both those terms and this-License would be to refrain entirely from conveying the Program.--  13. Use with the GNU Affero General Public License.--  Notwithstanding any other provision of this License, you have-permission to link or combine any covered work with a work licensed-under version 3 of the GNU Affero General Public License into a single-combined work, and to convey the resulting work.  The terms of this-License will continue to apply to the part which is the covered work,-but the special requirements of the GNU Affero General Public License,-section 13, concerning interaction through a network will apply to the-combination as such.--  14. Revised Versions of this License.--  The Free Software Foundation may publish revised and/or new versions of-the GNU General Public License from time to time.  Such new versions will-be similar in spirit to the present version, but may differ in detail to-address new problems or concerns.--  Each version is given a distinguishing version number.  If the-Program specifies that a certain numbered version of the GNU General-Public License "or any later version" applies to it, you have the-option of following the terms and conditions either of that numbered-version or of any later version published by the Free Software-Foundation.  If the Program does not specify a version number of the-GNU General Public License, you may choose any version ever published-by the Free Software Foundation.--  If the Program specifies that a proxy can decide which future-versions of the GNU General Public License can be used, that proxy's-public statement of acceptance of a version permanently authorizes you-to choose that version for the Program.--  Later license versions may give you additional or different-permissions.  However, no additional obligations are imposed on any-author or copyright holder as a result of your choosing to follow a-later version.--  15. Disclaimer of Warranty.--  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.--  16. Limitation of Liability.--  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF-SUCH DAMAGES.--  17. Interpretation of Sections 15 and 16.--  If the disclaimer of warranty and limitation of liability provided-above cannot be given local legal effect according to their terms,-reviewing courts shall apply local law that most closely approximates-an absolute waiver of all civil liability in connection with the-Program, unless a warranty or assumption of liability accompanies a-copy of the Program in return for a fee.--                     END OF TERMS AND CONDITIONS--            How to Apply These Terms to Your New Programs--  If you develop a new program, and you want it to be of the greatest-possible use to the public, the best way to achieve this is to make it-free software which everyone can redistribute and change under these terms.--  To do so, attach the following notices to the program.  It is safest-to attach them to the start of each source file to most effectively-state the exclusion of warranty; and each file should have at least-the "copyright" line and a pointer to where the full notice is found.--    <one line to give the program's name and a brief idea of what it does.>-    Copyright (C) <year>  <name of author>--    This program is free software: you can redistribute it and/or modify-    it under the terms of the GNU General Public License as published by-    the Free Software Foundation, either version 3 of the License, or-    (at your option) any later version.--    This program is distributed in the hope that it will be useful,-    but WITHOUT ANY WARRANTY; without even the implied warranty of-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-    GNU General Public License for more details.--    You should have received a copy of the GNU General Public License-    along with this program.  If not, see <https://www.gnu.org/licenses/>.--Also add information on how to contact you by electronic and paper mail.--  If the program does terminal interaction, make it output a short-notice like this when it starts in an interactive mode:--    <program>  Copyright (C) <year>  <name of author>-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.-    This is free software, and you are welcome to redistribute it-    under certain conditions; type `show c' for details.--The hypothetical commands `show w' and `show c' should show the appropriate-parts of the General Public License.  Of course, your program's commands-might be different; for a GUI interface, you would use an "about box".--  You should also get your employer (if you work as a programmer) or school,-if any, to sign a "copyright disclaimer" for the program, if necessary.-For more information on this, and how to apply and follow the GNU GPL, see-<https://www.gnu.org/licenses/>.--  The GNU General Public License does not permit incorporating your program-into proprietary programs.  If your program is a subroutine library, you-may consider it more useful to permit linking proprietary applications with-the library.  If this is what you want to do, use the GNU Lesser General-Public License instead of this License.  But first, please read-<https://www.gnu.org/licenses/why-not-lgpl.html>.
− libs/copr-hs/src/Web/Fedora/Copr.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--{- |-Copyright: (c) 2020 Jens Petersen-SPDX-License-Identifier: GPL-2.0-only-Maintainer: Jens Petersen <petersen@redhat.com>--Copr REST client library--}--module Web.Fedora.Copr-  (coprChroots,-   fedoraCopr)-where--import Data.Aeson.Types (Object)-import qualified Data.HashMap.Lazy as H-import Data.List (sort)-import Data.Text (Text)--import Web.Fedora.Copr.API--coprChroots :: String -> String -> String -> IO [Text]-coprChroots server owner project = do-  proj <- coprGetProject server owner project-  case lookupKey "chroot_repos" proj :: Maybe Object of-    Nothing ->-        case lookupKey "error" proj of-          Just err -> error err-          Nothing -> return []-    Just obj -> return $ (reverse . sort . H.keys) obj--fedoraCopr :: String-fedoraCopr = "copr.fedorainfracloud.org"
− libs/copr-hs/src/Web/Fedora/Copr/API.hs
@@ -1,190 +0,0 @@-{-# LANGUAGE CPP #-}--{- |-Copyright: (c) 2020 Jens Petersen-SPDX-License-Identifier: GPL-2.0-only-Maintainer: Jens Petersen <petersen@redhat.com>--Copr REST client library--}--module Web.Fedora.Copr.API-  ( coprGetProject-  , coprGetProjectsList-  , coprSearchProjects-  , coprGetBuild-  , coprGetBuildSourceChroot-  , coprGetBuildSourceConfig-  , coprGetBuildPackageList-  , coprGetBuildChroot-  , coprGetBuildChrootList-  , coprGetBuildChrootConfig-  , coprMockChrootList-  , coprGetPackage-  , coprGetPackageList-  , coprGetProjectChroot-  , coprGetProjectChrootBuildConfig-  , queryCopr-  , maybeKey-  , makeKey-  , makeItem-  , lookupKey-  , lookupKey'-  )-where--import Data.Aeson.Types-import Network.HTTP.Query---- # Projects---- | List project details------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/project.py#_9-coprGetProject :: String -> String -> String -> IO Object-coprGetProject server owner project = do-  let path = "project"-      params = [makeItem "ownername" owner, makeItem "projectname" project]-  queryCopr server path params---- | List projects of owner------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/project.py#_26-coprGetProjectsList :: String -> String -> IO Value--- FIXME limit=int or maybe pagination?-coprGetProjectsList server owner = do-  let path = "project/list"-      params = makeKey "ownername" owner-  queryCopr server path params---- | search projects by query string------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/project.py#_43-coprSearchProjects :: String -> String -> IO Value-coprSearchProjects server query = do-  let path = "project/search"-      params = makeKey "query" query-  queryCopr server path params---- # Builds---- | get build------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build.py#_10-coprGetBuild :: String -> Int -> IO Object-coprGetBuild server bid = do-  let path = "build" +/+ show bid-  queryCopr server path []---- | get srpm build------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build.py#_22-coprGetBuildSourceChroot :: String -> Int -> IO Object-coprGetBuildSourceChroot server bid = do-  let path = "build/source-chroot" +/+ show bid-  queryCopr server path []---- | get build source config------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build.py#_34-coprGetBuildSourceConfig :: String -> Int -> IO Object-coprGetBuildSourceConfig server bid = do-  let path = "build/source-build-config" +/+ show bid-  queryCopr server path []---- | get list of packages------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build.py#_46-coprGetBuildPackageList :: String -> Query -> IO Value-coprGetBuildPackageList server params = do-  let path = "build/list"-  queryCopr server path params---- # Build chroot---- | get build chroot------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build_chroot.py#_8-coprGetBuildChroot :: String -> Int -> String -> IO Value-coprGetBuildChroot server bid chroot = do-  let path = "build-chroot" +/+ show bid +/+ chroot-  queryCopr server path []---- | list of build chroots------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build_chroot.py#_25-coprGetBuildChrootList :: String -> Int -> IO Value-coprGetBuildChrootList server bid = do-  let path = "build-chroot/list" +/+ show bid-  queryCopr server path []---- | get build config for chroot------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/build_chroot.py#_44-coprGetBuildChrootConfig :: String -> Int -> String -> IO Value-coprGetBuildChrootConfig server bid chroot = do-  let path = "build-chroot/build-config" +/+ show bid +/+ chroot-  queryCopr server path []---- # Mock chroot---- | list of all available mock chroots------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/mock_chroot.py-coprMockChrootList :: String -> IO Value-coprMockChrootList server = do-  let path = "mock-chroots/list"-  queryCopr server path []---- # Package---- | Get project package details------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/package.py#_9-coprGetPackage :: String -> String -> String -> String -> IO Value-coprGetPackage server owner project package = do-  let path = "package"-      params = [makeItem "ownername" owner,-                makeItem "projectname" project,-                makeItem "packagename" package]-  queryCopr server path params---- | List project packages------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/package.py#_28-coprGetPackageList :: String -> String -> String -> IO Value-coprGetPackageList server owner project = do-  let path = "package/list"-      params = [makeItem "ownername" owner, makeItem "projectname" project]-  queryCopr server path params---- # Project chroot---- | get build chroot------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/project_chroot.py#_10-coprGetProjectChroot :: String -> String -> String -> String -> IO Value-coprGetProjectChroot server owner project chroot = do-  let path = "project-chroot"-      params = [makeItem "ownername" owner,-                makeItem "projectname" project,-                makeItem "chrootname" chroot]-  queryCopr server path params---- | list of build chroots------ https://pagure.io/copr/copr/blob/master/f/python/copr/v3/proxies/project_chroot.py#_29-coprGetProjectChrootBuildConfig :: String -> String -> String -> String -> IO Value-coprGetProjectChrootBuildConfig server owner project chroot = do-  let path = "project-chroot/build-config"-      params = [makeItem "ownername" owner,-                makeItem "projectname" project,-                makeItem "chrootname" chroot]-  queryCopr server path params----- | low-level query-queryCopr :: FromJSON a => String -> String -> Query -> IO a-queryCopr server path params =-  let url = "https://" ++ server +/+ "api_3" +/+ path-  in webAPIQuery url params
− libs/fedora-dists/LICENSE
@@ -1,674 +0,0 @@-                    GNU GENERAL PUBLIC LICENSE-                       Version 3, 29 June 2007-- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.--                            Preamble--  The GNU General Public License is a free, copyleft license for-software and other kinds of works.--  The licenses for most software and other practical works are designed-to take away your freedom to share and change the works.  By contrast,-the GNU General Public License is intended to guarantee your freedom to-share and change all versions of a program--to make sure it remains free-software for all its users.  We, the Free Software Foundation, use the-GNU General Public License for most of our software; it applies also to-any other work released this way by its authors.  You can apply it to-your programs, too.--  When we speak of free software, we are referring to freedom, not-price.  Our General Public Licenses are designed to make sure that you-have the freedom to distribute copies of free software (and charge for-them if you wish), that you receive source code or can get it if you-want it, that you can change the software or use pieces of it in new-free programs, and that you know you can do these things.--  To protect your rights, we need to prevent others from denying you-these rights or asking you to surrender the rights.  Therefore, you have-certain responsibilities if you distribute copies of the software, or if-you modify it: responsibilities to respect the freedom of others.--  For example, if you distribute copies of such a program, whether-gratis or for a fee, you must pass on to the recipients the same-freedoms that you received.  You must make sure that they, too, receive-or can get the source code.  And you must show them these terms so they-know their rights.--  Developers that use the GNU GPL protect your rights with two steps:-(1) assert copyright on the software, and (2) offer you this License-giving you legal permission to copy, distribute and/or modify it.--  For the developers' and authors' protection, the GPL clearly explains-that there is no warranty for this free software.  For both users' and-authors' sake, the GPL requires that modified versions be marked as-changed, so that their problems will not be attributed erroneously to-authors of previous versions.--  Some devices are designed to deny users access to install or run-modified versions of the software inside them, although the manufacturer-can do so.  This is fundamentally incompatible with the aim of-protecting users' freedom to change the software.  The systematic-pattern of such abuse occurs in the area of products for individuals to-use, which is precisely where it is most unacceptable.  Therefore, we-have designed this version of the GPL to prohibit the practice for those-products.  If such problems arise substantially in other domains, we-stand ready to extend this provision to those domains in future versions-of the GPL, as needed to protect the freedom of users.--  Finally, every program is threatened constantly by software patents.-States should not allow patents to restrict development and use of-software on general-purpose computers, but in those that do, we wish to-avoid the special danger that patents applied to a free program could-make it effectively proprietary.  To prevent this, the GPL assures that-patents cannot be used to render the program non-free.--  The precise terms and conditions for copying, distribution and-modification follow.--                       TERMS AND CONDITIONS--  0. Definitions.--  "This License" refers to version 3 of the GNU General Public License.--  "Copyright" also means copyright-like laws that apply to other kinds of-works, such as semiconductor masks.--  "The Program" refers to any copyrightable work licensed under this-License.  Each licensee is addressed as "you".  "Licensees" and-"recipients" may be individuals or organizations.--  To "modify" a work means to copy from or adapt all or part of the work-in a fashion requiring copyright permission, other than the making of an-exact copy.  The resulting work is called a "modified version" of the-earlier work or a work "based on" the earlier work.--  A "covered work" means either the unmodified Program or a work based-on the Program.--  To "propagate" a work means to do anything with it that, without-permission, would make you directly or secondarily liable for-infringement under applicable copyright law, except executing it on a-computer or modifying a private copy.  Propagation includes copying,-distribution (with or without modification), making available to the-public, and in some countries other activities as well.--  To "convey" a work means any kind of propagation that enables other-parties to make or receive copies.  Mere interaction with a user through-a computer network, with no transfer of a copy, is not conveying.--  An interactive user interface displays "Appropriate Legal Notices"-to the extent that it includes a convenient and prominently visible-feature that (1) displays an appropriate copyright notice, and (2)-tells the user that there is no warranty for the work (except to the-extent that warranties are provided), that licensees may convey the-work under this License, and how to view a copy of this License.  If-the interface presents a list of user commands or options, such as a-menu, a prominent item in the list meets this criterion.--  1. Source Code.--  The "source code" for a work means the preferred form of the work-for making modifications to it.  "Object code" means any non-source-form of a work.--  A "Standard Interface" means an interface that either is an official-standard defined by a recognized standards body, or, in the case of-interfaces specified for a particular programming language, one that-is widely used among developers working in that language.--  The "System Libraries" of an executable work include anything, other-than the work as a whole, that (a) is included in the normal form of-packaging a Major Component, but which is not part of that Major-Component, and (b) serves only to enable use of the work with that-Major Component, or to implement a Standard Interface for which an-implementation is available to the public in source code form.  A-"Major Component", in this context, means a major essential component-(kernel, window system, and so on) of the specific operating system-(if any) on which the executable work runs, or a compiler used to-produce the work, or an object code interpreter used to run it.--  The "Corresponding Source" for a work in object code form means all-the source code needed to generate, install, and (for an executable-work) run the object code and to modify the work, including scripts to-control those activities.  However, it does not include the work's-System Libraries, or general-purpose tools or generally available free-programs which are used unmodified in performing those activities but-which are not part of the work.  For example, Corresponding Source-includes interface definition files associated with source files for-the work, and the source code for shared libraries and dynamically-linked subprograms that the work is specifically designed to require,-such as by intimate data communication or control flow between those-subprograms and other parts of the work.--  The Corresponding Source need not include anything that users-can regenerate automatically from other parts of the Corresponding-Source.--  The Corresponding Source for a work in source code form is that-same work.--  2. Basic Permissions.--  All rights granted under this License are granted for the term of-copyright on the Program, and are irrevocable provided the stated-conditions are met.  This License explicitly affirms your unlimited-permission to run the unmodified Program.  The output from running a-covered work is covered by this License only if the output, given its-content, constitutes a covered work.  This License acknowledges your-rights of fair use or other equivalent, as provided by copyright law.--  You may make, run and propagate covered works that you do not-convey, without conditions so long as your license otherwise remains-in force.  You may convey covered works to others for the sole purpose-of having them make modifications exclusively for you, or provide you-with facilities for running those works, provided that you comply with-the terms of this License in conveying all material for which you do-not control copyright.  Those thus making or running the covered works-for you must do so exclusively on your behalf, under your direction-and control, on terms that prohibit them from making any copies of-your copyrighted material outside their relationship with you.--  Conveying under any other circumstances is permitted solely under-the conditions stated below.  Sublicensing is not allowed; section 10-makes it unnecessary.--  3. Protecting Users' Legal Rights From Anti-Circumvention Law.--  No covered work shall be deemed part of an effective technological-measure under any applicable law fulfilling obligations under article-11 of the WIPO copyright treaty adopted on 20 December 1996, or-similar laws prohibiting or restricting circumvention of such-measures.--  When you convey a covered work, you waive any legal power to forbid-circumvention of technological measures to the extent such circumvention-is effected by exercising rights under this License with respect to-the covered work, and you disclaim any intention to limit operation or-modification of the work as a means of enforcing, against the work's-users, your or third parties' legal rights to forbid circumvention of-technological measures.--  4. Conveying Verbatim Copies.--  You may convey verbatim copies of the Program's source code as you-receive it, in any medium, provided that you conspicuously and-appropriately publish on each copy an appropriate copyright notice;-keep intact all notices stating that this License and any-non-permissive terms added in accord with section 7 apply to the code;-keep intact all notices of the absence of any warranty; and give all-recipients a copy of this License along with the Program.--  You may charge any price or no price for each copy that you convey,-and you may offer support or warranty protection for a fee.--  5. Conveying Modified Source Versions.--  You may convey a work based on the Program, or the modifications to-produce it from the Program, in the form of source code under the-terms of section 4, provided that you also meet all of these conditions:--    a) The work must carry prominent notices stating that you modified-    it, and giving a relevant date.--    b) The work must carry prominent notices stating that it is-    released under this License and any conditions added under section-    7.  This requirement modifies the requirement in section 4 to-    "keep intact all notices".--    c) You must license the entire work, as a whole, under this-    License to anyone who comes into possession of a copy.  This-    License will therefore apply, along with any applicable section 7-    additional terms, to the whole of the work, and all its parts,-    regardless of how they are packaged.  This License gives no-    permission to license the work in any other way, but it does not-    invalidate such permission if you have separately received it.--    d) If the work has interactive user interfaces, each must display-    Appropriate Legal Notices; however, if the Program has interactive-    interfaces that do not display Appropriate Legal Notices, your-    work need not make them do so.--  A compilation of a covered work with other separate and independent-works, which are not by their nature extensions of the covered work,-and which are not combined with it such as to form a larger program,-in or on a volume of a storage or distribution medium, is called an-"aggregate" if the compilation and its resulting copyright are not-used to limit the access or legal rights of the compilation's users-beyond what the individual works permit.  Inclusion of a covered work-in an aggregate does not cause this License to apply to the other-parts of the aggregate.--  6. Conveying Non-Source Forms.--  You may convey a covered work in object code form under the terms-of sections 4 and 5, provided that you also convey the-machine-readable Corresponding Source under the terms of this License,-in one of these ways:--    a) Convey the object code in, or embodied in, a physical product-    (including a physical distribution medium), accompanied by the-    Corresponding Source fixed on a durable physical medium-    customarily used for software interchange.--    b) Convey the object code in, or embodied in, a physical product-    (including a physical distribution medium), accompanied by a-    written offer, valid for at least three years and valid for as-    long as you offer spare parts or customer support for that product-    model, to give anyone who possesses the object code either (1) a-    copy of the Corresponding Source for all the software in the-    product that is covered by this License, on a durable physical-    medium customarily used for software interchange, for a price no-    more than your reasonable cost of physically performing this-    conveying of source, or (2) access to copy the-    Corresponding Source from a network server at no charge.--    c) Convey individual copies of the object code with a copy of the-    written offer to provide the Corresponding Source.  This-    alternative is allowed only occasionally and noncommercially, and-    only if you received the object code with such an offer, in accord-    with subsection 6b.--    d) Convey the object code by offering access from a designated-    place (gratis or for a charge), and offer equivalent access to the-    Corresponding Source in the same way through the same place at no-    further charge.  You need not require recipients to copy the-    Corresponding Source along with the object code.  If the place to-    copy the object code is a network server, the Corresponding Source-    may be on a different server (operated by you or a third party)-    that supports equivalent copying facilities, provided you maintain-    clear directions next to the object code saying where to find the-    Corresponding Source.  Regardless of what server hosts the-    Corresponding Source, you remain obligated to ensure that it is-    available for as long as needed to satisfy these requirements.--    e) Convey the object code using peer-to-peer transmission, provided-    you inform other peers where the object code and Corresponding-    Source of the work are being offered to the general public at no-    charge under subsection 6d.--  A separable portion of the object code, whose source code is excluded-from the Corresponding Source as a System Library, need not be-included in conveying the object code work.--  A "User Product" is either (1) a "consumer product", which means any-tangible personal property which is normally used for personal, family,-or household purposes, or (2) anything designed or sold for incorporation-into a dwelling.  In determining whether a product is a consumer product,-doubtful cases shall be resolved in favor of coverage.  For a particular-product received by a particular user, "normally used" refers to a-typical or common use of that class of product, regardless of the status-of the particular user or of the way in which the particular user-actually uses, or expects or is expected to use, the product.  A product-is a consumer product regardless of whether the product has substantial-commercial, industrial or non-consumer uses, unless such uses represent-the only significant mode of use of the product.--  "Installation Information" for a User Product means any methods,-procedures, authorization keys, or other information required to install-and execute modified versions of a covered work in that User Product from-a modified version of its Corresponding Source.  The information must-suffice to ensure that the continued functioning of the modified object-code is in no case prevented or interfered with solely because-modification has been made.--  If you convey an object code work under this section in, or with, or-specifically for use in, a User Product, and the conveying occurs as-part of a transaction in which the right of possession and use of the-User Product is transferred to the recipient in perpetuity or for a-fixed term (regardless of how the transaction is characterized), the-Corresponding Source conveyed under this section must be accompanied-by the Installation Information.  But this requirement does not apply-if neither you nor any third party retains the ability to install-modified object code on the User Product (for example, the work has-been installed in ROM).--  The requirement to provide Installation Information does not include a-requirement to continue to provide support service, warranty, or updates-for a work that has been modified or installed by the recipient, or for-the User Product in which it has been modified or installed.  Access to a-network may be denied when the modification itself materially and-adversely affects the operation of the network or violates the rules and-protocols for communication across the network.--  Corresponding Source conveyed, and Installation Information provided,-in accord with this section must be in a format that is publicly-documented (and with an implementation available to the public in-source code form), and must require no special password or key for-unpacking, reading or copying.--  7. Additional Terms.--  "Additional permissions" are terms that supplement the terms of this-License by making exceptions from one or more of its conditions.-Additional permissions that are applicable to the entire Program shall-be treated as though they were included in this License, to the extent-that they are valid under applicable law.  If additional permissions-apply only to part of the Program, that part may be used separately-under those permissions, but the entire Program remains governed by-this License without regard to the additional permissions.--  When you convey a copy of a covered work, you may at your option-remove any additional permissions from that copy, or from any part of-it.  (Additional permissions may be written to require their own-removal in certain cases when you modify the work.)  You may place-additional permissions on material, added by you to a covered work,-for which you have or can give appropriate copyright permission.--  Notwithstanding any other provision of this License, for material you-add to a covered work, you may (if authorized by the copyright holders of-that material) supplement the terms of this License with terms:--    a) Disclaiming warranty or limiting liability differently from the-    terms of sections 15 and 16 of this License; or--    b) Requiring preservation of specified reasonable legal notices or-    author attributions in that material or in the Appropriate Legal-    Notices displayed by works containing it; or--    c) Prohibiting misrepresentation of the origin of that material, or-    requiring that modified versions of such material be marked in-    reasonable ways as different from the original version; or--    d) Limiting the use for publicity purposes of names of licensors or-    authors of the material; or--    e) Declining to grant rights under trademark law for use of some-    trade names, trademarks, or service marks; or--    f) Requiring indemnification of licensors and authors of that-    material by anyone who conveys the material (or modified versions of-    it) with contractual assumptions of liability to the recipient, for-    any liability that these contractual assumptions directly impose on-    those licensors and authors.--  All other non-permissive additional terms are considered "further-restrictions" within the meaning of section 10.  If the Program as you-received it, or any part of it, contains a notice stating that it is-governed by this License along with a term that is a further-restriction, you may remove that term.  If a license document contains-a further restriction but permits relicensing or conveying under this-License, you may add to a covered work material governed by the terms-of that license document, provided that the further restriction does-not survive such relicensing or conveying.--  If you add terms to a covered work in accord with this section, you-must place, in the relevant source files, a statement of the-additional terms that apply to those files, or a notice indicating-where to find the applicable terms.--  Additional terms, permissive or non-permissive, may be stated in the-form of a separately written license, or stated as exceptions;-the above requirements apply either way.--  8. Termination.--  You may not propagate or modify a covered work except as expressly-provided under this License.  Any attempt otherwise to propagate or-modify it is void, and will automatically terminate your rights under-this License (including any patent licenses granted under the third-paragraph of section 11).--  However, if you cease all violation of this License, then your-license from a particular copyright holder is reinstated (a)-provisionally, unless and until the copyright holder explicitly and-finally terminates your license, and (b) permanently, if the copyright-holder fails to notify you of the violation by some reasonable means-prior to 60 days after the cessation.--  Moreover, your license from a particular copyright holder is-reinstated permanently if the copyright holder notifies you of the-violation by some reasonable means, this is the first time you have-received notice of violation of this License (for any work) from that-copyright holder, and you cure the violation prior to 30 days after-your receipt of the notice.--  Termination of your rights under this section does not terminate the-licenses of parties who have received copies or rights from you under-this License.  If your rights have been terminated and not permanently-reinstated, you do not qualify to receive new licenses for the same-material under section 10.--  9. Acceptance Not Required for Having Copies.--  You are not required to accept this License in order to receive or-run a copy of the Program.  Ancillary propagation of a covered work-occurring solely as a consequence of using peer-to-peer transmission-to receive a copy likewise does not require acceptance.  However,-nothing other than this License grants you permission to propagate or-modify any covered work.  These actions infringe copyright if you do-not accept this License.  Therefore, by modifying or propagating a-covered work, you indicate your acceptance of this License to do so.--  10. Automatic Licensing of Downstream Recipients.--  Each time you convey a covered work, the recipient automatically-receives a license from the original licensors, to run, modify and-propagate that work, subject to this License.  You are not responsible-for enforcing compliance by third parties with this License.--  An "entity transaction" is a transaction transferring control of an-organization, or substantially all assets of one, or subdividing an-organization, or merging organizations.  If propagation of a covered-work results from an entity transaction, each party to that-transaction who receives a copy of the work also receives whatever-licenses to the work the party's predecessor in interest had or could-give under the previous paragraph, plus a right to possession of the-Corresponding Source of the work from the predecessor in interest, if-the predecessor has it or can get it with reasonable efforts.--  You may not impose any further restrictions on the exercise of the-rights granted or affirmed under this License.  For example, you may-not impose a license fee, royalty, or other charge for exercise of-rights granted under this License, and you may not initiate litigation-(including a cross-claim or counterclaim in a lawsuit) alleging that-any patent claim is infringed by making, using, selling, offering for-sale, or importing the Program or any portion of it.--  11. Patents.--  A "contributor" is a copyright holder who authorizes use under this-License of the Program or a work on which the Program is based.  The-work thus licensed is called the contributor's "contributor version".--  A contributor's "essential patent claims" are all patent claims-owned or controlled by the contributor, whether already acquired or-hereafter acquired, that would be infringed by some manner, permitted-by this License, of making, using, or selling its contributor version,-but do not include claims that would be infringed only as a-consequence of further modification of the contributor version.  For-purposes of this definition, "control" includes the right to grant-patent sublicenses in a manner consistent with the requirements of-this License.--  Each contributor grants you a non-exclusive, worldwide, royalty-free-patent license under the contributor's essential patent claims, to-make, use, sell, offer for sale, import and otherwise run, modify and-propagate the contents of its contributor version.--  In the following three paragraphs, a "patent license" is any express-agreement or commitment, however denominated, not to enforce a patent-(such as an express permission to practice a patent or covenant not to-sue for patent infringement).  To "grant" such a patent license to a-party means to make such an agreement or commitment not to enforce a-patent against the party.--  If you convey a covered work, knowingly relying on a patent license,-and the Corresponding Source of the work is not available for anyone-to copy, free of charge and under the terms of this License, through a-publicly available network server or other readily accessible means,-then you must either (1) cause the Corresponding Source to be so-available, or (2) arrange to deprive yourself of the benefit of the-patent license for this particular work, or (3) arrange, in a manner-consistent with the requirements of this License, to extend the patent-license to downstream recipients.  "Knowingly relying" means you have-actual knowledge that, but for the patent license, your conveying the-covered work in a country, or your recipient's use of the covered work-in a country, would infringe one or more identifiable patents in that-country that you have reason to believe are valid.--  If, pursuant to or in connection with a single transaction or-arrangement, you convey, or propagate by procuring conveyance of, a-covered work, and grant a patent license to some of the parties-receiving the covered work authorizing them to use, propagate, modify-or convey a specific copy of the covered work, then the patent license-you grant is automatically extended to all recipients of the covered-work and works based on it.--  A patent license is "discriminatory" if it does not include within-the scope of its coverage, prohibits the exercise of, or is-conditioned on the non-exercise of one or more of the rights that are-specifically granted under this License.  You may not convey a covered-work if you are a party to an arrangement with a third party that is-in the business of distributing software, under which you make payment-to the third party based on the extent of your activity of conveying-the work, and under which the third party grants, to any of the-parties who would receive the covered work from you, a discriminatory-patent license (a) in connection with copies of the covered work-conveyed by you (or copies made from those copies), or (b) primarily-for and in connection with specific products or compilations that-contain the covered work, unless you entered into that arrangement,-or that patent license was granted, prior to 28 March 2007.--  Nothing in this License shall be construed as excluding or limiting-any implied license or other defenses to infringement that may-otherwise be available to you under applicable patent law.--  12. No Surrender of Others' Freedom.--  If conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License.  If you cannot convey a-covered work so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you may-not convey it at all.  For example, if you agree to terms that obligate you-to collect a royalty for further conveying from those to whom you convey-the Program, the only way you could satisfy both those terms and this-License would be to refrain entirely from conveying the Program.--  13. Use with the GNU Affero General Public License.--  Notwithstanding any other provision of this License, you have-permission to link or combine any covered work with a work licensed-under version 3 of the GNU Affero General Public License into a single-combined work, and to convey the resulting work.  The terms of this-License will continue to apply to the part which is the covered work,-but the special requirements of the GNU Affero General Public License,-section 13, concerning interaction through a network will apply to the-combination as such.--  14. Revised Versions of this License.--  The Free Software Foundation may publish revised and/or new versions of-the GNU General Public License from time to time.  Such new versions will-be similar in spirit to the present version, but may differ in detail to-address new problems or concerns.--  Each version is given a distinguishing version number.  If the-Program specifies that a certain numbered version of the GNU General-Public License "or any later version" applies to it, you have the-option of following the terms and conditions either of that numbered-version or of any later version published by the Free Software-Foundation.  If the Program does not specify a version number of the-GNU General Public License, you may choose any version ever published-by the Free Software Foundation.--  If the Program specifies that a proxy can decide which future-versions of the GNU General Public License can be used, that proxy's-public statement of acceptance of a version permanently authorizes you-to choose that version for the Program.--  Later license versions may give you additional or different-permissions.  However, no additional obligations are imposed on any-author or copyright holder as a result of your choosing to follow a-later version.--  15. Disclaimer of Warranty.--  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY-APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR-PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM-IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.--  16. Limitation of Liability.--  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF-SUCH DAMAGES.--  17. Interpretation of Sections 15 and 16.--  If the disclaimer of warranty and limitation of liability provided-above cannot be given local legal effect according to their terms,-reviewing courts shall apply local law that most closely approximates-an absolute waiver of all civil liability in connection with the-Program, unless a warranty or assumption of liability accompanies a-copy of the Program in return for a fee.--                     END OF TERMS AND CONDITIONS--            How to Apply These Terms to Your New Programs--  If you develop a new program, and you want it to be of the greatest-possible use to the public, the best way to achieve this is to make it-free software which everyone can redistribute and change under these terms.--  To do so, attach the following notices to the program.  It is safest-to attach them to the start of each source file to most effectively-state the exclusion of warranty; and each file should have at least-the "copyright" line and a pointer to where the full notice is found.--    <one line to give the program's name and a brief idea of what it does.>-    Copyright (C) <year>  <name of author>--    This program is free software: you can redistribute it and/or modify-    it under the terms of the GNU General Public License as published by-    the Free Software Foundation, either version 3 of the License, or-    (at your option) any later version.--    This program is distributed in the hope that it will be useful,-    but WITHOUT ANY WARRANTY; without even the implied warranty of-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-    GNU General Public License for more details.--    You should have received a copy of the GNU General Public License-    along with this program.  If not, see <https://www.gnu.org/licenses/>.--Also add information on how to contact you by electronic and paper mail.--  If the program does terminal interaction, make it output a short-notice like this when it starts in an interactive mode:--    <program>  Copyright (C) <year>  <name of author>-    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.-    This is free software, and you are welcome to redistribute it-    under certain conditions; type `show c' for details.--The hypothetical commands `show w' and `show c' should show the appropriate-parts of the General Public License.  Of course, your program's commands-might be different; for a GUI interface, you would use an "about box".--  You should also get your employer (if you work as a programmer) or school,-if any, to sign a "copyright disclaimer" for the program, if necessary.-For more information on this, and how to apply and follow the GNU GPL, see-<https://www.gnu.org/licenses/>.--  The GNU General Public License does not permit incorporating your program-into proprietary programs.  If your program is a subroutine library, you-may consider it more useful to permit linking proprietary applications with-the library.  If this is what you want to do, use the GNU Lesser General-Public License instead of this License.  But first, please read-<https://www.gnu.org/licenses/why-not-lgpl.html>.
− libs/fedora-dists/src/Distribution/Fedora.hs
@@ -1,216 +0,0 @@-{-# LANGUAGE CPP #-}---- |--- Module      :  Distribution.Fedora--- Copyright   :  (C) 2014-2020  Jens Petersen------ Maintainer  :  Jens Petersen <petersen@fedoraproject.org>------ Explanation: Fedora Dist type and functions---- This program is free software: you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation, either version 3 of the License, or--- (at your option) any later version.--module Distribution.Fedora-  (Dist(..),-   getReleaseIds,-   getFedoraReleaseIds,-   getFedoraDists,-   getEPELReleaseIds,-   getRawhideDist,-   getLatestFedoraDist,-   getLatestEPELDist,-   rawhideVersionId,-   distBranch,-   distRepo,-   distUpdates,-   distOverride,-   mockConfig,-   distVersion,-   kojicmd,-   rpkg,-   rpmDistTag) where--import qualified Data.Text as T-import Data.Text (Text)-import Data.Version-import Text.Read-import Text.ParserCombinators.ReadP (char, eof, string)--#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>), (*>))-import Data.Traversable (traverse)-#endif--import Distribution.Fedora.ReadProducts-import Distribution.Fedora.Products---- | The `Dist` datatype specifies the target OS and version.--- (roughly corresponds to a git branch)-data Dist = RHEL Version -- ^ RHEL version-          | EPEL Int -- ^ EPEL release-          | Fedora Int -- ^ Fedora release-  deriving (Eq, Ord)--instance Show Dist where-  show (Fedora n) = "f" ++ show n-  show (EPEL n) = (if n <= 6 then "el" else "epel") ++ show n-  show (RHEL v) = "rhel-" ++ showVersion v---- | Read from eg "f29", "epel7"-instance Read Dist where-  readPrec = choice [pFedora, pEPEL, pRHEL] where-    pFedora = Fedora <$> (lift (char 'f') *> readPrec)-    pEPEL = EPEL <$> (lift (string "epel") *> readPrec)-    pRHEL = RHEL <$> lift (do-      v <- string "rhel-" >> parseVersion-      eof-      return v)--getReleases :: IO [Release]-getReleases = do-  file <- getProductsFile-  reverse <$> parseReleases file---- | gets list of current releases (Fedora and EPEL)------ The data is stored in ~/.fedora/product-versions.json--- and refreshed from Fedora PDC if older than 5.5 hours-getReleaseIds :: IO [Text]-getReleaseIds = map releaseProductVersionId <$> getReleases--getProductReleases :: Text -> IO [Release]-getProductReleases name =-  filter (\p -> releaseProduct p == name) <$> getReleases---- getRelease :: Text -> IO (Maybe Release)--- getRelease pv =---   find (\p -> releaseProductVersionId p == pv) <$> getReleases--getFedoraReleases :: IO [Release]-getFedoraReleases =-  getProductReleases (T.pack "fedora")---- | gets current Fedora releases-getFedoraReleaseIds :: IO [Text]-getFedoraReleaseIds =-  map releaseProductVersionId <$> getFedoraReleases--getEPELReleases :: IO [Release]-getEPELReleases =-  getProductReleases (T.pack "epel")---- | gets current EPEL releases-getEPELReleaseIds :: IO [Text]-getEPELReleaseIds =-  map releaseProductVersionId <$> getEPELReleases---- | Rawhide version id-rawhideVersionId :: Text-rawhideVersionId = T.pack "fedora-rawhide"---- fails on rawhide - only use on other releases-releaseMajorVersion :: Release -> Int-releaseMajorVersion = read . T.unpack . releaseVersion--releaseDist :: Release -> Dist-releaseDist = Fedora . releaseMajorVersion--releaseDists :: [Release] -> [Dist]-releaseDists rels =-  map mkDist rels-  where-    mkDist :: Release -> Dist-    mkDist r | releaseProductVersionId r == rawhideVersionId = newerDist latestbranch-             | otherwise = releaseDist r--    latestbranch = maximum $ filter (\p -> releaseProductVersionId p /= rawhideVersionId) rels--    newerDist = Fedora . (+ 1) . releaseMajorVersion---- | get list of current Fedora Dist's-getFedoraDists :: IO [Dist]-getFedoraDists = releaseDists <$> getFedoraReleases---- | get current Dist for Fedora Rawhide-getRawhideDist :: IO Dist-getRawhideDist =-  head . releaseDists <$> getFedoraReleases---- | get newest Fedora branch-getLatestFedoraDist :: IO Dist-getLatestFedoraDist =-  releaseDist . maximum . filter (\p -> releaseProductVersionId p /= rawhideVersionId) <$> getFedoraReleases---- | get newest EPEL release-getLatestEPELDist :: IO Dist-getLatestEPELDist =-  EPEL . releaseMajorVersion . maximum <$> getEPELReleases---- activeRelease :: Text -> IO Bool--- activeRelease pv = do---   res <- filter (\p -> releaseProductVersionId p == pv) <$> getReleases---   return $ not (null res)---- | Maps `Dist` to package dist-git branch name, relative to latest branch------ > distBranch (Fedora 32) (Fedora 33) == "rawhide"--- > distBranch (Fedora 32) (Fedora 31) == "f31"-distBranch :: Dist -- ^ latest branch-           -> Dist -> String-distBranch branch (Fedora n) | Fedora n > branch = "rawhide"-distBranch _ d = show d---- | Map `Dist` to DNF/YUM repo name, relative to latest branch-distRepo :: Dist -> Dist -> String-distRepo branched (Fedora n) | Fedora n > branched = "rawhide"-                             | otherwise = "fedora"-distRepo _ (EPEL _) = "epel"-distRepo _ (RHEL _) = "rhel"---- | Map `Dist` to Maybe the DNF/YUM updates repo name, relative to latest branch-distUpdates :: Dist -> Dist -> Maybe String-distUpdates branched (Fedora n) | Fedora n > branched  = Nothing-distUpdates _ (Fedora _) = Just "updates"-distUpdates _ _ = Nothing---- | Whether dist has overrides in Bodhi, relative to latest branch-distOverride :: Dist -> Dist -> Bool-distOverride branch (Fedora n) = Fedora n <= branch-distOverride _ (EPEL n) = n < 9-distOverride _ _ = False---- | OS release major version for `Dist`, relative to latest branch-distVersion :: Dist -> Dist -> String-distVersion branch (Fedora n) | Fedora n > branch = "rawhide"-distVersion _ (Fedora n) = show n-distVersion _ (EPEL n) = show n-distVersion _ (RHEL n) = show n---- | Mock configuration for `Dist` and arch, relative to latest branch-mockConfig :: Dist -> Dist -> String -> String-mockConfig branch dist arch =-  let prefix =-        case dist of-          Fedora _ -> "fedora"-          _ -> distRepo branch dist-  in-  prefix ++ "-" ++ distVersion branch dist ++ "-" ++ arch---- | `Dist` tag (appended to rpm package release field)-rpmDistTag :: Dist -> String-rpmDistTag (Fedora n) = ".fc" ++ show n-rpmDistTag (EPEL n) = ".el" ++ show n-rpmDistTag (RHEL v) = ".el" ++ (show . head . versionBranch) v---- | Command line tool for `Dist` (eg "koji")-kojicmd :: Dist -> String-kojicmd (RHEL _) = "brew"-kojicmd _ =  "koji"---- | rpkg command for `Dist` (eg "fedpkg")-rpkg :: Dist -> String-rpkg (RHEL _) = "rhpkg"-rpkg _ = "fedpkg"
− libs/fedora-dists/src/Distribution/Fedora/Branch.hs
@@ -1,181 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP               #-}---- |--- Module      :  Distribution.Fedora.Branch--- Copyright   :  (C) 2020  Jens Petersen------ Maintainer  :  Jens Petersen <petersen@fedoraproject.org>------ Explanation: Fedora Branch type and functions---- This program is free software: you can redistribute it and/or modify--- it under the terms of the GNU General Public License as published by--- the Free Software Foundation, either version 3 of the License, or--- (at your option) any later version.--module Distribution.Fedora.Branch-  ( Branch(..)-  , readBranch-  , readBranch'-  , eitherBranch-  , eitherBranch'-  , readActiveBranch-  , readActiveBranch'-  , eitherActiveBranch-  , newerBranch-  , releaseBranch-  , getFedoraBranches-  , getFedoraBranched-  , branchDestTag-  , branchDist-  , branchTarget-  )-where--#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,8,0))-#else-import Control.Applicative ((<$>))-#endif--import Data.Char (isDigit)-import qualified Data.Text as T--import qualified Distribution.Fedora as Dist---- | Branch datatype------ Branch can be rawhide, or a fedora or epel branch-data Branch = EPEL Int | Fedora Int | Rawhide-  deriving (Eq, Ord)---- | Read a Fedora Branch name, otherwise return branch string-eitherBranch :: String -> Either String Branch-eitherBranch "rawhide" = Right Rawhide-eitherBranch ('f':ns) | all isDigit ns = let br = Fedora (read ns) in Right br-eitherBranch ('e':'p':'e':'l':n) | all isDigit n = let br = EPEL (read n) in Right br-eitherBranch ('e':'l':n) | all isDigit n = let br = EPEL (read n) in Right br-eitherBranch cs = Left cs---- | Read a Fedora Branch name, otherwise return an error message-eitherBranch' :: String -> Either String Branch-eitherBranch' cs = case eitherBranch cs of-  Right br -> Right br-  Left xs -> Left $ xs ++ " is not a known Fedora/EPEL branch"---- | Read a Fedora Branch name-readBranch :: String -> Maybe Branch-readBranch bs =-  case eitherBranch bs of-    Left _ -> Nothing-    Right br -> Just br---- | Unsafely read a Fedora Branch name: errors for unknown branches-readBranch' :: String -> Branch-readBranch' bs =-  case eitherBranch bs of-    Left e -> error' $! "unknown Fedora branch: " ++ e-    Right br -> br---- | Read a Branch name (one of the list of active branches)------ Provides error strings for inactive or unknown branches.-eitherActiveBranch :: [Branch] -> String -> Either String Branch-eitherActiveBranch active bs =-  case eitherBranch bs of-    Left e -> Left e-    Right br -> if br `elem` active-                then Right br-                else Left bs---- | Read a Branch name (one of the list of active branches)------ Similar to eitherActiceBranch but ignores any error string-readActiveBranch :: [Branch] -> String -> Maybe Branch-readActiveBranch active cs =-  case eitherActiveBranch active cs of-    Left _ -> Nothing-    Right br -> Just br---- | Read a Branch name (one of the list of active branches)------ Like readActiveBranch, but errors for inactive or unknown branches.-readActiveBranch' :: [Branch] -> String -> Branch-readActiveBranch' active cs =-  case eitherActiveBranch active cs of-    Left e -> error' $ "inactive Fedora branch: " ++ e-    Right br -> br--instance Show Branch where-  show Rawhide = "rawhide"-  show (Fedora n) = "f" ++ show n-  show (EPEL n) = (if n <= 6 then "el" else "epel") ++ show n---- | Map Branch to Koji destination tag-branchDestTag :: Branch -> String-branchDestTag Rawhide = "rawhide"-branchDestTag (Fedora n) = show (Fedora n) ++ "-updates-candidate"-branchDestTag (EPEL n) = show (EPEL n) ++ "-testing-candidate"---- | Default build target associated with a branch-branchTarget :: Branch -> String-branchTarget (Fedora n) = show (Fedora n)-branchTarget (EPEL n) = show (EPEL n)-branchTarget Rawhide = "rawhide"----getLatestBranch :: IO Branch---- | Returns newer branch than given one from supplied active branches.------ Branches should be in descending order, eg from getFedoraBranches-newerBranch :: Branch -> [Branch] -> Branch-newerBranch Rawhide _ = Rawhide-newerBranch (Fedora n) branches =-  if Fedora n `elem` branches-  then if Fedora (n+1) `elem` branches-       then Fedora (n+1)-       else Rawhide-  else error' $ "Unsupported branch: " ++ show (Fedora n)-newerBranch (EPEL n) branches =-  if EPEL n `elem` branches-  then if EPEL (n+1) `elem` branches-       then EPEL (n+1)-       else EPEL n-  else error' $ "Unsupported branch: " ++ show (EPEL n)----olderBranch :: Branch -> Branch---olderBranch Rawhide = latestBranch---olderBranch (Fedora n) = Fedora (n-1)---- | Returns list of active Fedora branches, including rawhide and EPEL-getFedoraBranches :: IO [Branch]-getFedoraBranches = map releaseBranch <$> Dist.getReleaseIds---- | Maps release-id to Branch-releaseBranch :: T.Text -> Branch-releaseBranch "fedora-rawhide" = Rawhide-releaseBranch rel | "fedora-" `T.isPrefixOf` rel =-                      let (_,ver) = T.breakOnEnd "-" rel in-                        Fedora $ read . T.unpack $ ver-                  | "epel-" `T.isPrefixOf` rel =-                      let (_,ver) = T.breakOnEnd "-" rel in-                        EPEL $ read . T.unpack $ ver-                  | otherwise = error' $ "Unsupport release: " ++ T.unpack rel---- | Returns list of active Fedora branches, excluding rawhide-getFedoraBranched :: IO [Branch]-getFedoraBranched = filter (/= Rawhide) <$> getFedoraBranches---- from simple-cmd-error' :: String -> a-#if (defined(MIN_VERSION_base) && MIN_VERSION_base(4,9,0))-error' = errorWithoutStackTrace-#else-error' = error-#endif---- | Convert a Branch to a Dist-branchDist :: Branch -> IO Dist.Dist-branchDist (Fedora n) = return $ Dist.Fedora n-branchDist (EPEL n) = return $ Dist.EPEL n-branchDist Rawhide = Dist.getRawhideDist
− libs/fedora-dists/src/Distribution/Fedora/Products.hs
@@ -1,52 +0,0 @@-{-# LANGUAGE RecordWildCards     #-}-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE CPP                 #-}--module Distribution.Fedora.Products-  ( Release(releaseProductVersionId,releaseVersion,releaseProduct)-  , parseReleases-  )-where--import qualified Data.ByteString.Lazy.Char8 as BL-import           Control.Monad      (mzero)-import           Data.Aeson(eitherDecode, Value(..), FromJSON(..), ToJSON(..),-                            pairs,-                            (.:), (.=), object)-#if !MIN_VERSION_base(4,13,0)-import           Data.Monoid((<>))-#endif-import           Data.Text (Text)-#if !MIN_VERSION_base(4,8,0)-import Control.Applicative ((<$>), (<*>))-#endif--data Release = Release {-    releaseProductVersionId :: Text,-    releaseReleases :: [Text],-    releaseAllowedPushTargets :: [[Maybe Value]],-    releaseActive :: Bool,-    releaseName :: Text,-    releaseVersion :: Text,-    releaseShort :: Text,-    releaseProduct :: Text-  } deriving (Show,Eq)--instance Ord Release where-  compare r1 r2 =-    compare (releaseProductVersionId r1) (releaseProductVersionId r2)--instance FromJSON Release where-  parseJSON (Object v) = Release <$> v .:  "product_version_id" <*> v .:  "releases" <*> v .:  "allowed_push_targets" <*> v .:  "active" <*> v .:  "name" <*> v .:  "version" <*> v .:  "short" <*> v .:  "product"-  parseJSON _          = mzero--instance ToJSON Release where-  toJSON     Release {..} = object ["product_version_id" .= releaseProductVersionId, "releases" .= releaseReleases, "allowed_push_targets" .= releaseAllowedPushTargets, "active" .= releaseActive, "name" .= releaseName, "version" .= releaseVersion, "short" .= releaseShort, "product" .= releaseProduct]-  toEncoding Release {..} = pairs  ("product_version_id" .= releaseProductVersionId<>"releases" .= releaseReleases<>"allowed_push_targets" .= releaseAllowedPushTargets<>"active" .= releaseActive<>"name" .= releaseName<>"version" .= releaseVersion<>"short" .= releaseShort<>"product" .= releaseProduct)--parseReleases :: FilePath -> IO [Release]-parseReleases filename = do-    input <- BL.readFile filename-    case eitherDecode input of-      Left  err -> error $ "Invalid JSON file: " ++ filename ++ "\n" ++ err-      Right r   -> return r
− libs/fedora-dists/src/Distribution/Fedora/ReadProducts.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE CPP                 #-}--module Distribution.Fedora.ReadProducts-  (getProductsFile)-where--import Control.Monad-import Data.Aeson(encode)-import qualified Data.ByteString.Lazy.Char8 as BL-import Data.Time.Clock (diffUTCTime, getCurrentTime)-import Fedora.PDC (makeKey, pdcProductVersions)-import System.Directory-import System.FilePath ((</>))--getProductsFile :: IO FilePath-getProductsFile = do-  home <- getHomeDirectory-  let dir = home </> ".fedora"-  dirExists <- doesDirectoryExist dir-  unless dirExists $ createDirectory dir-  let file = dir </> "product-versions-2.json"-  recent <- do-    have <- doesFileExist file-    if have then do-      ts <- getModificationTime file-      t <- getCurrentTime-      -- about 5.5 hours-      return $ diffUTCTime t ts < 20000-      else return False-  unless recent $-    pdcProductVersions "pdc.fedoraproject.org" (makeKey "active" "true") >>=-    BL.writeFile file . encode-  return file
− libs/pagure-hs/LICENSE
@@ -1,339 +0,0 @@-                    GNU GENERAL PUBLIC LICENSE-                       Version 2, June 1991-- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.--                            Preamble--  The licenses for most software are designed to take away your-freedom to share and change it.  By contrast, the GNU General Public-License is intended to guarantee your freedom to share and change free-software--to make sure the software is free for all its users.  This-General Public License applies to most of the Free Software-Foundation's software and to any other program whose authors commit to-using it.  (Some other Free Software Foundation software is covered by-the GNU Lesser General Public License instead.)  You can apply it to-your programs, too.--  When we speak of free software, we are referring to freedom, not-price.  Our General Public Licenses are designed to make sure that you-have the freedom to distribute copies of free software (and charge for-this service if you wish), that you receive source code or can get it-if you want it, that you can change the software or use pieces of it-in new free programs; and that you know you can do these things.--  To protect your rights, we need to make restrictions that forbid-anyone to deny you these rights or to ask you to surrender the rights.-These restrictions translate to certain responsibilities for you if you-distribute copies of the software, or if you modify it.--  For example, if you distribute copies of such a program, whether-gratis or for a fee, you must give the recipients all the rights that-you have.  You must make sure that they, too, receive or can get the-source code.  And you must show them these terms so they know their-rights.--  We protect your rights with two steps: (1) copyright the software, and-(2) offer you this license which gives you legal permission to copy,-distribute and/or modify the software.--  Also, for each author's protection and ours, we want to make certain-that everyone understands that there is no warranty for this free-software.  If the software is modified by someone else and passed on, we-want its recipients to know that what they have is not the original, so-that any problems introduced by others will not reflect on the original-authors' reputations.--  Finally, any free program is threatened constantly by software-patents.  We wish to avoid the danger that redistributors of a free-program will individually obtain patent licenses, in effect making the-program proprietary.  To prevent this, we have made it clear that any-patent must be licensed for everyone's free use or not licensed at all.--  The precise terms and conditions for copying, distribution and-modification follow.--                    GNU GENERAL PUBLIC LICENSE-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION--  0. This License applies to any program or other work which contains-a notice placed by the copyright holder saying it may be distributed-under the terms of this General Public License.  The "Program", below,-refers to any such program or work, and a "work based on the Program"-means either the Program or any derivative work under copyright law:-that is to say, a work containing the Program or a portion of it,-either verbatim or with modifications and/or translated into another-language.  (Hereinafter, translation is included without limitation in-the term "modification".)  Each licensee is addressed as "you".--Activities other than copying, distribution and modification are not-covered by this License; they are outside its scope.  The act of-running the Program is not restricted, and the output from the Program-is covered only if its contents constitute a work based on the-Program (independent of having been made by running the Program).-Whether that is true depends on what the Program does.--  1. You may copy and distribute verbatim copies of the Program's-source code as you receive it, in any medium, provided that you-conspicuously and appropriately publish on each copy an appropriate-copyright notice and disclaimer of warranty; keep intact all the-notices that refer to this License and to the absence of any warranty;-and give any other recipients of the Program a copy of this License-along with the Program.--You may charge a fee for the physical act of transferring a copy, and-you may at your option offer warranty protection in exchange for a fee.--  2. You may modify your copy or copies of the Program or any portion-of it, thus forming a work based on the Program, and copy and-distribute such modifications or work under the terms of Section 1-above, provided that you also meet all of these conditions:--    a) You must cause the modified files to carry prominent notices-    stating that you changed the files and the date of any change.--    b) You must cause any work that you distribute or publish, that in-    whole or in part contains or is derived from the Program or any-    part thereof, to be licensed as a whole at no charge to all third-    parties under the terms of this License.--    c) If the modified program normally reads commands interactively-    when run, you must cause it, when started running for such-    interactive use in the most ordinary way, to print or display an-    announcement including an appropriate copyright notice and a-    notice that there is no warranty (or else, saying that you provide-    a warranty) and that users may redistribute the program under-    these conditions, and telling the user how to view a copy of this-    License.  (Exception: if the Program itself is interactive but-    does not normally print such an announcement, your work based on-    the Program is not required to print an announcement.)--These requirements apply to the modified work as a whole.  If-identifiable sections of that work are not derived from the Program,-and can be reasonably considered independent and separate works in-themselves, then this License, and its terms, do not apply to those-sections when you distribute them as separate works.  But when you-distribute the same sections as part of a whole which is a work based-on the Program, the distribution of the whole must be on the terms of-this License, whose permissions for other licensees extend to the-entire whole, and thus to each and every part regardless of who wrote it.--Thus, it is not the intent of this section to claim rights or contest-your rights to work written entirely by you; rather, the intent is to-exercise the right to control the distribution of derivative or-collective works based on the Program.--In addition, mere aggregation of another work not based on the Program-with the Program (or with a work based on the Program) on a volume of-a storage or distribution medium does not bring the other work under-the scope of this License.--  3. You may copy and distribute the Program (or a work based on it,-under Section 2) in object code or executable form under the terms of-Sections 1 and 2 above provided that you also do one of the following:--    a) Accompany it with the complete corresponding machine-readable-    source code, which must be distributed under the terms of Sections-    1 and 2 above on a medium customarily used for software interchange; or,--    b) Accompany it with a written offer, valid for at least three-    years, to give any third party, for a charge no more than your-    cost of physically performing source distribution, a complete-    machine-readable copy of the corresponding source code, to be-    distributed under the terms of Sections 1 and 2 above on a medium-    customarily used for software interchange; or,--    c) Accompany it with the information you received as to the offer-    to distribute corresponding source code.  (This alternative is-    allowed only for noncommercial distribution and only if you-    received the program in object code or executable form with such-    an offer, in accord with Subsection b above.)--The source code for a work means the preferred form of the work for-making modifications to it.  For an executable work, complete source-code means all the source code for all modules it contains, plus any-associated interface definition files, plus the scripts used to-control compilation and installation of the executable.  However, as a-special exception, the source code distributed need not include-anything that is normally distributed (in either source or binary-form) with the major components (compiler, kernel, and so on) of the-operating system on which the executable runs, unless that component-itself accompanies the executable.--If distribution of executable or object code is made by offering-access to copy from a designated place, then offering equivalent-access to copy the source code from the same place counts as-distribution of the source code, even though third parties are not-compelled to copy the source along with the object code.--  4. You may not copy, modify, sublicense, or distribute the Program-except as expressly provided under this License.  Any attempt-otherwise to copy, modify, sublicense or distribute the Program is-void, and will automatically terminate your rights under this License.-However, parties who have received copies, or rights, from you under-this License will not have their licenses terminated so long as such-parties remain in full compliance.--  5. You are not required to accept this License, since you have not-signed it.  However, nothing else grants you permission to modify or-distribute the Program or its derivative works.  These actions are-prohibited by law if you do not accept this License.  Therefore, by-modifying or distributing the Program (or any work based on the-Program), you indicate your acceptance of this License to do so, and-all its terms and conditions for copying, distributing or modifying-the Program or works based on it.--  6. Each time you redistribute the Program (or any work based on the-Program), the recipient automatically receives a license from the-original licensor to copy, distribute or modify the Program subject to-these terms and conditions.  You may not impose any further-restrictions on the recipients' exercise of the rights granted herein.-You are not responsible for enforcing compliance by third parties to-this License.--  7. If, as a consequence of a court judgment or allegation of patent-infringement or for any other reason (not limited to patent issues),-conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License.  If you cannot-distribute so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you-may not distribute the Program at all.  For example, if a patent-license would not permit royalty-free redistribution of the Program by-all those who receive copies directly or indirectly through you, then-the only way you could satisfy both it and this License would be to-refrain entirely from distribution of the Program.--If any portion of this section is held invalid or unenforceable under-any particular circumstance, the balance of the section is intended to-apply and the section as a whole is intended to apply in other-circumstances.--It is not the purpose of this section to induce you to infringe any-patents or other property right claims or to contest validity of any-such claims; this section has the sole purpose of protecting the-integrity of the free software distribution system, which is-implemented by public license practices.  Many people have made-generous contributions to the wide range of software distributed-through that system in reliance on consistent application of that-system; it is up to the author/donor to decide if he or she is willing-to distribute software through any other system and a licensee cannot-impose that choice.--This section is intended to make thoroughly clear what is believed to-be a consequence of the rest of this License.--  8. If the distribution and/or use of the Program is restricted in-certain countries either by patents or by copyrighted interfaces, the-original copyright holder who places the Program under this License-may add an explicit geographical distribution limitation excluding-those countries, so that distribution is permitted only in or among-countries not thus excluded.  In such case, this License incorporates-the limitation as if written in the body of this License.--  9. The Free Software Foundation may publish revised and/or new versions-of the General Public License from time to time.  Such new versions will-be similar in spirit to the present version, but may differ in detail to-address new problems or concerns.--Each version is given a distinguishing version number.  If the Program-specifies a version number of this License which applies to it and "any-later version", you have the option of following the terms and conditions-either of that version or of any later version published by the Free-Software Foundation.  If the Program does not specify a version number of-this License, you may choose any version ever published by the Free Software-Foundation.--  10. If you wish to incorporate parts of the Program into other free-programs whose distribution conditions are different, write to the author-to ask for permission.  For software which is copyrighted by the Free-Software Foundation, write to the Free Software Foundation; we sometimes-make exceptions for this.  Our decision will be guided by the two goals-of preserving the free status of all derivatives of our free software and-of promoting the sharing and reuse of software generally.--                            NO WARRANTY--  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,-REPAIR OR CORRECTION.--  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE-POSSIBILITY OF SUCH DAMAGES.--                     END OF TERMS AND CONDITIONS--            How to Apply These Terms to Your New Programs--  If you develop a new program, and you want it to be of the greatest-possible use to the public, the best way to achieve this is to make it-free software which everyone can redistribute and change under these terms.--  To do so, attach the following notices to the program.  It is safest-to attach them to the start of each source file to most effectively-convey the exclusion of warranty; and each file should have at least-the "copyright" line and a pointer to where the full notice is found.--    <one line to give the program's name and a brief idea of what it does.>-    Copyright (C) <year>  <name of author>--    This program is free software; you can redistribute it and/or modify-    it under the terms of the GNU General Public License as published by-    the Free Software Foundation; either version 2 of the License, or-    (at your option) any later version.--    This program is distributed in the hope that it will be useful,-    but WITHOUT ANY WARRANTY; without even the implied warranty of-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the-    GNU General Public License for more details.--    You should have received a copy of the GNU General Public License along-    with this program; if not, write to the Free Software Foundation, Inc.,-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.--Also add information on how to contact you by electronic and paper mail.--If the program is interactive, make it output a short notice like this-when it starts in an interactive mode:--    Gnomovision version 69, Copyright (C) year name of author-    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.-    This is free software, and you are welcome to redistribute it-    under certain conditions; type `show c' for details.--The hypothetical commands `show w' and `show c' should show the appropriate-parts of the General Public License.  Of course, the commands you use may-be called something other than `show w' and `show c'; they could even be-mouse-clicks or menu items--whatever suits your program.--You should also get your employer (if you work as a programmer) or your-school, if any, to sign a "copyright disclaimer" for the program, if-necessary.  Here is a sample; alter the names:--  Yoyodyne, Inc., hereby disclaims all copyright interest in the program-  `Gnomovision' (which makes passes at compilers) written by James Hacker.--  <signature of Ty Coon>, 1 April 1989-  Ty Coon, President of Vice--This General Public License does not permit incorporating your program into-proprietary programs.  If your program is a subroutine library, you may-consider it more useful to permit linking proprietary applications with the-library.  If this is what you want to do, use the GNU Lesser General-Public License instead of this License.
− libs/pagure-hs/src/Fedora/Pagure.hs
@@ -1,236 +0,0 @@-{-# LANGUAGE CPP, OverloadedStrings #-}--{- |-Copyright: (c) 2020 Jens Petersen-SPDX-License-Identifier: GPL-2.0-only-Maintainer: Jens Petersen <petersen@redhat.com>--Pagure REST client library--}--module Fedora.Pagure-  ( pagureProjectInfo-  , pagureListProjects-  , pagureListProjectIssues-  , IssueTitleStatus(..)-  , pagureListProjectIssueTitlesStatus-  , pagureProjectIssueInfo-  , pagureListGitBranches-  , pagureListGitBranchesWithCommits-  , pagureListUsers-  , pagureUserForks-  , pagureUserInfo-  , pagureUserRepos-  , pagureListGroups-  , pagureProjectGitURLs-  , queryPagure-  , queryPagureSingle-  , queryPagurePaged-  , queryPagureCount-  , makeKey-  , makeItem-  , maybeKey-  , Query-  , QueryItem-  , lookupKey-  , lookupKey'-  ) where--import Control.Monad-#if (defined(VERSION_lens_aeson))-import Control.Lens-import Data.Aeson.Lens-#else-import Lens.Micro-import Lens.Micro.Aeson-#endif-import Data.Aeson.Types-import Data.Maybe-import Data.Text (Text)-import qualified Data.Text as T-import Network.HTTP.Query-import System.IO (hPutStrLn, stderr)---- | Project info------ `pagureProjectInfo server "<repo>"`--- `pagureProjectInfo server "<namespace>/<repo>"`------ https://pagure.io/api/0/#projects-tab-pagureProjectInfo :: String -> String -> IO (Either String Value)-pagureProjectInfo server project = do-  let path = project-  queryPagureSingle server path []---- | List projects------ https://pagure.io/api/0/#projects-tab-pagureListProjects :: String -> Query -> IO Value-pagureListProjects server params = do-  let path = "projects"-  queryPagure server path params---- | List project issues------ https://pagure.io/api/0/#issues-tab-pagureListProjectIssues :: String -> String -> Query -> IO (Either String Value)-pagureListProjectIssues server repo params = do-  let path = repo +/+ "issues"-  queryPagureSingle server path params--data IssueTitleStatus =-  IssueTitleStatus { pagureIssueId :: Integer-                   , pagureIssueTitle :: String-                   , pagureIssueStatus :: T.Text-                   , pagureIssueCloseStatus :: Maybe T.Text-                   }---- | List project issue titles------ https://pagure.io/api/0/#issues-tab-pagureListProjectIssueTitlesStatus :: String -> String -> Query-  -> IO (Either String [IssueTitleStatus])-pagureListProjectIssueTitlesStatus server repo params = do-  let path = repo +/+ "issues"-  res <- queryPagureSingle server path params-  return $ case res of-    Left e -> Left e-    Right v -> Right $ v ^.. key (T.pack "issues") . values . _Object & mapMaybe parseIssue-  where-    parseIssue :: Object -> Maybe IssueTitleStatus-    parseIssue =-      parseMaybe $ \obj -> do-        id' <- obj .: "id"-        title <- obj .: "title"-        status <- obj .: "status"-        mcloseStatus <- obj .:? "close_status"-        return $ IssueTitleStatus id' (T.unpack title) status mcloseStatus---- | Issue information------ https://pagure.io/api/0/#issues-tab-pagureProjectIssueInfo :: String -> String -> Int -> IO (Either String Object)-pagureProjectIssueInfo server repo issue = do-  let path = repo +/+ "issue" +/+ show issue-  res <- queryPagureSingle server path []-  return $ case res of-    Left e -> Left e-    Right v -> Right $ v ^. _Object---- | List repo branches------ https://pagure.io/api/0/#projects-tab-pagureListGitBranches :: String -> String -> IO (Either String [String])-pagureListGitBranches server repo = do-  let path = repo +/+ "git/branches"-  res <- queryPagureSingle server path []-  return $ case res of-    Left e -> Left e-    Right v -> Right $ v ^.. key (T.pack "branches") . values . _String & map T.unpack---- | List repo branches with commits------ https://pagure.io/api/0/#projects-tab-pagureListGitBranchesWithCommits :: String -> String -> IO (Either String Object)-pagureListGitBranchesWithCommits server repo = do-  let path = repo +/+ "git/branches"-      params = makeKey "with_commits" "1"-  res <- queryPagureSingle server path params-  return $ case res of-    Left e -> Left e-    Right v -> Right $ v ^. key (T.pack "branches") . _Object---- | List users------ https://pagure.io/api/0/#users-tab-pagureListUsers :: String -> String -> IO Value-pagureListUsers server pat = do-  let path = "users"-      params = makeKey "pattern" pat-  queryPagure server path params---- | User information------ https://pagure.io/api/0/#users-tab-pagureUserInfo :: String -> String -> Query -> IO (Either String Value)-pagureUserInfo server user params = do-  let path = "user" +/+ user-  queryPagureSingle server path params---- | List groups------ https://pagure.io/api/0/#groups-tab-pagureListGroups :: String -> Maybe String -> Query -> IO Value-pagureListGroups server mpat paging = do-  let path = "groups"-      params = maybeKey "pattern" mpat ++ paging-  queryPagure server path params---- | Project Git URLs------ https://pagure.io/api/0/#projects-tab-pagureProjectGitURLs :: String -> String -> IO (Either String Value)-pagureProjectGitURLs server repo = do-  let path = repo +/+ "git/urls"-  queryPagureSingle server path []----- | low-level query-queryPagure :: String -> String -> Query -> IO Value-queryPagure server path params =-  let url = "https://" ++ server +/+ "api/0" +/+ path-  in webAPIQuery url params---- | single query-queryPagureSingle :: String -> String -> Query -> IO (Either String Value)-queryPagureSingle server path params = do-  res <- queryPagure server path params-  if isJust (res ^? key "error") then-    return $ Left (res ^. key "error" . _String & T.unpack)-    else-    return $ Right res---- | count total number of hits-queryPagureCount :: String -> String -> Query -> String -> IO (Maybe Integer)-queryPagureCount server path params pagination = do-  res <- queryPagure server path (params ++ makeKey "per_page" "1")-  return $ res ^? key (T.pack pagination) . key "pages" . _Integer---- | get all pages of results------ Note this can potentially download very large amount of data.--- For potentially large queries, it is a good idea to queryPagureCount first.-queryPagurePaged :: String -> String -> Query -> (String,String) -> IO [Value]-queryPagurePaged server path params (pagination,paging) = do-  -- FIXME allow overriding per_page-  let maxPerPage = "100"-  res1 <- queryPagure server path (params ++ makeKey "per_page" maxPerPage)-  let mpages = res1 ^? key (T.pack pagination) . key "pages" . _Integer-  case mpages of-    Nothing -> return []-    Just pages -> do-      when (pages > 1) $-        hPutStrLn stderr $ "receiving " ++ show pages ++ " pages × " ++ maxPerPage ++ " results..."-      rest <- mapM nextPage [2..pages]-      return $ res1 : rest-  where-    nextPage p =-      queryPagure server path (params ++ makeKey "per_page" "100" ++ makeKey paging (show p))---- | list user's repos-pagureUserRepos :: String -> String -> IO [Text]-pagureUserRepos server user = do-  let path = "user" +/+ user-  pages <- queryPagurePaged server path [] ("repos_pagination", "repopage")-  return $ concatMap (getRepos "repos") pages--getRepos :: Text -> Value -> [Text]-getRepos field result =-  result ^.. key field . values . key "fullname" . _String---- | list user's forks-pagureUserForks :: String -> String -> IO [Text]-pagureUserForks server user = do-  let path = "user" +/+ user-  pages <- queryPagurePaged server path [] ("forks_pagination", "forkpage")-  return $ concatMap (getRepos "forks") pages
− libs/pdc-hs/LICENSE
@@ -1,21 +0,0 @@-MIT License--Copyright (c) 2020 Jens Petersen--Permission is hereby granted, free of charge, to any person obtaining a copy-of this software and associated documentation files (the "Software"), to deal-in the Software without restriction, including without limitation the rights-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell-copies of the Software, and to permit persons to whom the Software is-furnished to do so, subject to the following conditions:--The above copyright notice and this permission notice shall be included in all-copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE-SOFTWARE.
− libs/pdc-hs/src/Fedora/PDC.hs
@@ -1,209 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE OverloadedStrings #-}--{- |-Copyright: (c) 2020 Jens Petersen-SPDX-License-Identifier: MIT-Maintainer: Jens Petersen <juhpetersen@gmail.com>--Fedora PDC web api client library--}--module Fedora.PDC-  ( fedoraPDC-  , pdcArches-  , pdcChangesets-  , pdcComponentBranches-  , pdcComponentBranchSLAs-  , pdcComponentRelationshipTypes-  , pdcComponentSLATypes-  , pdcComposes-  , pdcComposeImages-  , pdcComposeImageRttTests-  , pdcComposeRpms-  , pdcComposeTreeRttTests-  , pdcContentDeliveryContentFormats-  , pdcGlobalComponents-  , pdcImages-  , pdcModules-  , pdcProductVersions-  , pdcProducts-  , pdcReleases-  , pdcWhereToFileBugs-  , pdcRpms-  , queryPDC-  , lookupKey-  , lookupKey'-  , makeKey-  , makeItem-  , maybeKey-  , Query-  , QueryItem-  , getResultsList-  )-where--import Data.Aeson.Types-import Network.HTTP.Query--fedoraPDC :: String-fedoraPDC = "pdc.fedoraproject.org"---- | Arch List------ https://pdc.fedoraproject.org/rest_api/v1/arches/-pdcArches :: String -> IO [Object]-pdcArches server =-  lookupKey' "results" <$> queryPDC server "arches" []---- https://pdc.fedoraproject.org/rest_api/v1/auth/ *---- https://pdc.fedoraproject.org/rest_api/v1/base-products/ no-op?---- https://pdc.fedoraproject.org/rest_api/v1/bugzilla-components/ no-op?---- | Changeset List------ https://pdc.fedoraproject.org/rest_api/v1/changesets/-pdcChangesets :: String -> Query -> IO Object-pdcChangesets server =-  queryPDC server "changesets"---- | Sla To Component Branch List------ https://pdc.fedoraproject.org/rest_api/v1/component-branch-slas/-pdcComponentBranchSLAs :: String -> Query -> IO Object-pdcComponentBranchSLAs server =-  queryPDC server "component-branch-slas"---- | Component Branch List------ https://pdc.fedoraproject.org/rest_api/v1/component-branches/-pdcComponentBranches :: String -> Query -> IO Object-pdcComponentBranches server =-  queryPDC server "component-branches"---- | Release Component Relationship Type List------ https://pdc.fedoraproject.org/rest_api/v1/component-relationship-types/-pdcComponentRelationshipTypes :: String -> IO [Object]-pdcComponentRelationshipTypes server =-  lookupKey' "results" <$> queryPDC server "component-relationship-types" []---- | Sla List------ https://pdc.fedoraproject.org/rest_api/v1/component-sla-types/-pdcComponentSLATypes :: String -> Query -> IO [Object]-pdcComponentSLATypes server params =-  lookupKey' "results" <$> queryPDC server "component-sla-types" params---- | Compose Image Rtt Test List------ https://pdc.fedoraproject.org/rest_api/v1/compose-image-rtt-tests/ (all untested?)-pdcComposeImageRttTests :: String -> Query -> IO Object-pdcComposeImageRttTests server =-  queryPDC server "compose-image-rtt-tests"---- | Compose Image Instance------ https://pdc.fedoraproject.org/rest_api/v1/compose-images/ {compose_id}/-pdcComposeImages :: String -> String -> IO Object-pdcComposeImages server compose =-  queryPDC server ("compose-images" +/+ compose ++ "/") []---- | Compose Rpm List (seems heavy)------ https://pdc.fedoraproject.org/rest_api/v1/compose-rpms/ {compose_id}/-pdcComposeRpms :: String -> String -> IO Object-pdcComposeRpms server compose =-  queryPDC server ("compose-rpms" +/+ compose ++ "/") []---- | Compose Tree Rtt Test List------ https://pdc.fedoraproject.org/rest_api/v1/compose-tree-rtt-tests/-pdcComposeTreeRttTests :: String -> Query -> IO Object-pdcComposeTreeRttTests server =-  queryPDC server "compose-tree-rtt-tests"---- | Compose List------ https://pdc.fedoraproject.org/rest_api/v1/composes/-pdcComposes :: String -> Maybe String -> Query -> IO Object-pdcComposes server mcompose params = do-  let path = "composes" +/+ maybe "" (++ "/") mcompose-  queryPDC server path params---- https://pdc.fedoraproject.org/rest_api/v1/composes/%7Bcompose_id%7D/rpm-mapping/%7Bpackage%7D/---- | Content Format List------ https://pdc.fedoraproject.org/rest_api/v1/content-delivery-content-formats/-pdcContentDeliveryContentFormats :: String -> Query -> IO [Object]-pdcContentDeliveryContentFormats server params =-  lookupKey' "results" <$> queryPDC server "content-delivery-content-formats" params---- | Global Component List------ https://pdc.fedoraproject.org/rest_api/v1/global-components/-pdcGlobalComponents :: String -> Query -> IO Object-pdcGlobalComponents server =-   queryPDC server "global-components"---- | Image List------ https://pdc.fedoraproject.org/rest_api/v1/images/-pdcImages :: String -> Query -> IO Object-pdcImages server =-   queryPDC server "images"---- | Module List------ https://pdc.fedoraproject.org/rest_api/v1/modules/-pdcModules :: String -> Query -> IO Object-pdcModules server =-  queryPDC server "modules"---- | Product Version List------ https://pdc.fedoraproject.org/rest_api/v1/product-versions/-pdcProductVersions :: String -> Query -> IO [Object]-pdcProductVersions server params =-  lookupKey' "results" <$> queryPDC server "product-versions" params---- | Product List------ https://pdc.fedoraproject.org/rest_api/v1/products/-pdcProducts :: String -> Query -> IO [Object]-pdcProducts server params =-  lookupKey' "results" <$> queryPDC server "products" params---- | Release List------ https://pdc.fedoraproject.org/rest_api/v1/releases/-pdcReleases :: String -> Query -> IO Object-pdcReleases server =-  queryPDC server "releases"---- | Filter Bugzilla Products And Components List------ https://pdc.fedoraproject.org/rest_api/v1/rpc/where-to-file-bugs/-pdcWhereToFileBugs :: String -> Query -> IO Object-pdcWhereToFileBugs server =-  queryPDC server "rpc/where-to-file-bugs"---- | Rpm List------ https://pdc.fedoraproject.org/rest_api/v1/rpms/-pdcRpms :: String -> Query -> IO Object-pdcRpms server =-  queryPDC server "rpms"---- | low-level query-queryPDC :: String -> String -> Query -> IO Object-queryPDC server path params =-  let url = "https://" ++ server +/+ "rest_api/v1" +/+ path-  in webAPIQuery url params---- | Get results key from a response object-getResultsList :: Object -> [Object]-getResultsList = lookupKey' "results"
src/Bodhi.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP, OverloadedStrings #-}  module Bodhi (   bodhiCreateOverride,@@ -8,6 +8,9 @@   ) where +#if MIN_VERSION_aeson(2,0,0)+import Data.Aeson.Key (fromText)+#endif import Data.Aeson.Types (Object, (.:), parseEither) import Data.Char (toLower) import Fedora.Bodhi hiding (bodhiUpdate)@@ -34,7 +37,12 @@     lookupKey'' k obj =       let errMsg e = error $ e ++ " " ++ show obj in         -- bodhi-hs has lookupKeyEither-        either errMsg id $ parseEither (.: k) obj+        either errMsg id $ parseEither (.: fromText k) obj++#if !MIN_VERSION_aeson(2,0,0)+    fromText :: T.Text -> T.Text+    fromText = id+#endif  -- FIXME should determine 3 days for branched devel release -- FIXME handle expired override?
src/Branches.hs view
@@ -6,7 +6,7 @@   isEPELBranch,   localBranches,   pagurePkgBranches,-  mockConfig,+  mockRoot,   module Distribution.Fedora.Branch,   AnyBranch(..),   anyBranch,@@ -17,8 +17,11 @@   listOfBranches,   listOfAnyBranches,   gitCurrentBranch,+  gitCurrentBranch',+  checkOnBranch,   systemBranch,   getReleaseBranch,+  getReleaseBranchWarn,   branchVersion,   anyBranchToRelease,   getRequestedBranches,@@ -26,12 +29,13 @@ ) where  import Common+import Common.System  import Data.Either import Data.Tuple import Distribution.Fedora.Branch-import SimpleCmd import SimpleCmd.Git+import System.Info (arch)  import Pagure import Prompt@@ -99,10 +103,12 @@   where     include p e = e ++ ": " ++ p -mockConfig :: Branch -> String-mockConfig Rawhide = "fedora-rawhide-x86_64"-mockConfig (Fedora n) = "fedora-" ++ show n ++ "-x86_64"-mockConfig (EPEL n) = "epel-" ++ show n ++ "-x86_64"+mockRoot :: Branch -> String+mockRoot br = do+  case br of+    Rawhide -> "fedora-rawhide-" ++ arch+    Fedora n -> "fedora-" ++ show n ++ "-" ++ arch+    EPEL n -> "epel-" ++ show n ++ "-" ++ arch  ------ @@ -167,9 +173,37 @@ getReleaseBranch =   gitCurrentBranch >>= anyBranchToRelease +getReleaseBranchWarn :: IO Branch+getReleaseBranchWarn =+  gitCurrentBranchWarn >>= anyBranchToRelease+ gitCurrentBranch :: IO AnyBranch-gitCurrentBranch =+gitCurrentBranch = do+  br <- gitCurrentBranch'+  if br == OtherBranch "HEAD"+    then do+    dir <- getDirectoryName+    prompt_ $ dir ++ ": " ++ show br ++ " is not a branch, please fix"+    gitCurrentBranch+    else return br++gitCurrentBranch' :: IO AnyBranch+gitCurrentBranch' = do   anyBranch <$> git "rev-parse" ["--abbrev-ref", "HEAD"]++gitCurrentBranchWarn :: IO AnyBranch+gitCurrentBranchWarn = do+  br <- gitCurrentBranch+  if br == OtherBranch "master"+    then do+    dir <- getDirectoryName+    prompt_ $ dir ++ ": " ++ show br ++ " is not a valid branch, please use 'rename-rawhide'"+    gitCurrentBranchWarn+    else return br+++checkOnBranch :: IO ()+checkOnBranch = void gitCurrentBranch  anyBranchToRelease :: AnyBranch -> IO Branch anyBranchToRelease (RelBranch rbr) = return rbr
src/Bugzilla.hs view
@@ -6,10 +6,13 @@   BugId,   -- session   BugzillaSession,-  bugIdsSession,   bugsSession,-  bzLoginSession,+  bugsAnon,+  bugIdsAnon,+  bzAnonSession,   bzReviewSession,+  bzReviewAnon,+  getBzUser,   reviewBugIdSession,   approvedReviewBugIdSession,   approvedReviewBugSession,@@ -56,7 +59,6 @@   putBugId,   -- request   newBzRequest,-  intAsText,   makeTextItem   ) where @@ -65,7 +67,6 @@ import qualified Common.Text as T import Prompt -import Control.Exception (finally) import Data.Aeson.Types (Array, Object) import qualified Data.ByteString.Char8 as B import Data.ByteString.UTF8@@ -73,12 +74,10 @@ import Network.HTTP.Conduit import Network.HTTP.Query import Network.HTTP.Simple-import System.Environment import System.Environment.XDG.BaseDir-import System.IO (hSetEcho, stdin) import qualified Text.Email.Validate as Email-import Web.Bugzilla.RedHat-import Web.Bugzilla.RedHat.Search+import Web.RedHatBugzilla+import Web.RedHatBugzilla.Search  createBug :: BugzillaSession -> [(String,String)] -> IO Int createBug session params = do@@ -136,14 +135,25 @@ brc :: T.Text brc = "bugzilla.redhat.com" -bzReviewSession :: IO (Maybe BugId,BugzillaSession)+bzReviewAnon :: IO (Maybe BugId)+bzReviewAnon = do+  pkg <- getDirectoryName+  bids <- bugIdsAnon $+          pkgReviews pkg .&&. statusOpen .&&. reviewApproved+  return $ case bids of+    [bid] -> Just bid+    _ -> Nothing++bzReviewSession :: IO (Maybe (BugId,BugzillaSession)) bzReviewSession = do   pkg <- getDirectoryName-  (bids,session) <- bugIdsSession $-                    pkgReviews pkg .&&. statusOpen .&&. reviewApproved+  bids <- bugIdsAnon $+          pkgReviews pkg .&&. statusOpen .&&. reviewApproved   case bids of-    [bid] -> return (Just bid, session)-    _ -> return (Nothing, session)+    [bid] -> do+      session <- bzApiKeySession+      return $ Just (bid, session)+    _ -> return Nothing  newtype BzUserRC = BzUserRC {rcUserEmail :: UserEmail}   deriving (Eq, Show)@@ -151,89 +161,75 @@ emailIsValid :: String -> Bool emailIsValid = Email.isValid . B.pack --- FIXME support bugzilla API key-bzLoginSession :: IO (BugzillaSession, UserEmail)-bzLoginSession = do-  user <- getBzUser-  ctx <- newBugzillaContext brc-  session <- getBzLoginSession ctx user-  return (session,user)+getBzUser :: IO UserEmail+getBzUser = do+  config <- getUserConfigFile "fbrnch" "bugzilla"+  haveConfig <- doesFileExist config+  if haveConfig+    then readIniConfig config rcParser rcUserEmail+    else do+    -- FIXME: option to override email+    email <- prompt "Bugzilla Username"+    when (emailIsValid email) $ do+      let configDir = takeDirectory config+      configDirExists <- doesDirectoryExist configDir+      unless configDirExists $ createDirectory configDir+      T.writeFile config $ "[" <> brc <> "]\nuser = " <> T.pack email <> "\n"+      putStrLn $ "Saved in " ++ config ++ "\n"+    getBzUser   where-    getBzUser :: IO UserEmail-    getBzUser = do-      home <- getEnv "HOME"-      let rc = home </> ".bugzillarc"-      -- FIXME assumption if file exists then it has b.r.c user-      ifM (doesFileExist rc)-        (readIniConfig rc rcParser rcUserEmail) $-        do-        -- FIXME: option to override email-        email <- prompt "Bugzilla Username"-        when (emailIsValid email) $ do-          T.writeFile rc $ "[" <> brc <> "]\nuser = " <> T.pack email <> "\n"-          putStrLn $ "Saved in " ++ rc-        getBzUser-      where-        rcParser :: IniParser BzUserRC-        rcParser =-          section brc $-          BzUserRC <$> fieldOf "user" string+    rcParser :: IniParser BzUserRC+    rcParser =+      section brc $+      BzUserRC <$> fieldOf "user" string -    getBzLoginSession :: BugzillaContext -> UserEmail -> IO BugzillaSession-    getBzLoginSession ctx user = do-      cache <- getUserCacheFile "python-bugzilla" "bugzillatoken"-      let cacheDir = takeDirectory cache-      cacheDirExists <- doesDirectoryExist cacheDir-      unless cacheDirExists $ createDirectory cacheDir-      tokenstatus <- ifM (notM (doesFileExist cache)) (return NoToken) $-        do-        token <- readIniConfig cache rcParser bzToken-        let session = LoginSession ctx $ BugzillaToken token-        let validreq = setRequestCheckStatus $-                       newBzRequest session ["valid_login"] [("login",Just user)]-        valid <- lookupKey' "result" . getResponseBody <$> httpJSON validreq-        return $ if valid then ValidToken session else InvalidToken token-      case tokenstatus of-        ValidToken session -> return session-        InvalidToken oldtoken -> do-          token <- bzLogin-          cmd_ "sed" ["-i", "s/" ++ T.unpack oldtoken ++ "/" ++ T.unpack token ++ "/", cache]-          return $ LoginSession ctx $ BugzillaToken token-        NoToken -> do-          token <- bzLogin-          T.writeFile cache $ "[" <> brc <> "]\ntoken = " <> token <> "\n"-          putStrLn $ "Saved in " ++ cache-          return $ LoginSession ctx $ BugzillaToken token-      where-        rcParser :: IniParser BzTokenConf-        rcParser =-          section brc $-          BzTokenConf <$> fieldOf "token" string+bzAnonSession :: BugzillaSession+bzAnonSession = anonymousSession brc -        bzLogin :: IO T.Text-        bzLogin = do-          putStrLn "No valid bugzilla login token, please login:"-          passwd <- withoutEcho $ prompt "Bugzilla Password"-          if null passwd then bzLogin-            else do-            let anonsession = AnonymousSession ctx-                tokenReq = setRequestCheckStatus $-                           newBzRequest anonsession ["login"]-                           [("login", Just user),-                            makeTextItem "password" passwd]-            res <- getResponseBody <$> httpJSON tokenReq-            case lookupKey "token" res of-              Nothing -> T.putStrLn (lookupKey' "message" res) >> bzLogin-              Just token -> return token+-- bzAnonSession' :: IO (BugzillaSession,BugzillaContext)+-- bzAnonSession' =+--   context <- newBugzillaContext brc+--   return (AnonymousSession context, context) -        withoutEcho :: IO a -> IO a-        withoutEcho action =-          finally (hSetEcho stdin False >> action) (hSetEcho stdin True)+bzApiKeySession :: IO BugzillaSession+bzApiKeySession = do+  (config,exists) <- do+    rc1 <- getUserConfigFile "python-bugzilla" "bugzillarc"+    haveRc1 <- doesFileExist rc1+    if haveRc1+      then return (rc1,haveRc1)+      else do+      home <- getHomeDirectory+      let rc2 = home </> ".bugzillarc"+      haveRc2 <- doesFileExist rc2+      return $ if haveRc2+               then (rc2,haveRc2)+               else (rc1,False)+  if not exists+    then+    -- do+    -- let configDir = takeDirectory config+    -- configDirExists <- doesDirectoryExist configDir+    -- unless configDirExists $ createDirectory configDir+    error' $ unlines+    ["No Bugzilla API key found",+     "Create a key at https://bugzilla.redhat.com/userprefs.cgi?tab=apikey",+     "Save the key under in '" ++ config ++ "' under:",+     "[bugzilla.redhat.com]",+     apiKeyField ++ " = <YourApiKey>"]+    else do+    apikey <- readIniConfig config rcParser bzApiKey+    return $ ApiKeySession brc $ BugzillaApiKey apikey+  where+    apiKeyField = "api_key" -newtype BzTokenConf = BzTokenConf {bzToken :: T.Text}-  deriving (Eq, Show)+    rcParser :: IniParser BzApiKeyConf+    rcParser =+      section brc $+      BzApiKeyConf <$> fieldOf (T.pack apiKeyField) string -data BzTokenStatus = ValidToken BugzillaSession | InvalidToken T.Text | NoToken+newtype BzApiKeyConf = BzApiKeyConf {bzApiKey :: T.Text}+  deriving (Eq, Show)  bugIdIs :: BugId -> SearchExpression bugIdIs bid = BugIdField .==. bid@@ -286,42 +282,49 @@ summaryContains keywrd =   SummaryField `contains` T.pack keywrd -bugIdsSession :: SearchExpression -> IO ([BugId],BugzillaSession)-bugIdsSession query = do-  (session,_) <- bzLoginSession-  bugs <- searchBugs' session query-  return (bugs, session)+bugIdsAnon :: SearchExpression -> IO [BugId]+bugIdsAnon = searchBugs' bzAnonSession +bugsAnon :: SearchExpression -> IO [Bug]+bugsAnon = searchBugs bzAnonSession++-- FIXME name is ambiguous bugsSession :: SearchExpression -> IO ([Bug],BugzillaSession) bugsSession query = do-  (session,_) <- bzLoginSession+  session <- bzApiKeySession   bugs <- searchBugs session query   return (bugs, session)  reviewBugIdSession :: String -> IO (BugId,BugzillaSession) reviewBugIdSession pkg = do-  (bugs,session) <- bugIdsSession $ pkgReviews pkg .&&. statusOpen+  bugs <- bugIdsAnon $ pkgReviews pkg .&&. statusOpen   case bugs of     [] -> error $ "No review bug found for " ++ pkg-    [bug] -> return (bug, session)+    [bug] -> do+      session <- bzApiKeySession+      return (bug, session)     _ -> error' "more than one review bug found!"  approvedReviewBugIdSession :: String -> IO (BugId,BugzillaSession) approvedReviewBugIdSession pkg = do-  (bugs,session) <- bugIdsSession $-                    pkgReviews pkg .&&. statusOpen .&&. reviewApproved+  bugs <- bugIdsAnon $+          pkgReviews pkg .&&. statusOpen .&&. reviewApproved   case bugs of     [] -> error $ "No review bug found for " ++ pkg-    [bug] -> return (bug, session)+    [bug] -> do+      session <- bzApiKeySession+      return (bug, session)     _ -> error' "more than one review bug found!"  approvedReviewBugSession :: String -> IO (Bug,BugzillaSession) approvedReviewBugSession pkg = do-  (bugs,session) <- bugsSession $-                    pkgReviews pkg .&&. statusOpen .&&. reviewApproved+  bugs <- bugsAnon $+          pkgReviews pkg .&&. statusOpen .&&. reviewApproved   case bugs of     [] -> error $ "No review bug found for " ++ pkg-    [bug] -> return (bug, session)+    [bug] -> do+      session <- bzApiKeySession+      return (bug, session)     _ -> error' "more than one review bug found!"  reviewBugToPackage :: Bug -> String@@ -378,11 +381,11 @@  putReviewBug :: Bool -> Bug -> IO () putReviewBug short bug = do-  if short then putStr $ reviewBugToPackage bug ++ " "+  if short+    then putStr $ reviewBugToPackage bug ++ " "     else do-    putStrLn $ reviewBugToPackage bug ++ " (" ++ T.unpack (bugStatus bug) ++ ")"+    putStr $ T.unpack (bugStatus bug) ++ " " ++ reviewBugToPackage bug ++ ": "     putBugId $ bugId bug-    putStrLn ""  putBug :: Bug -> IO () putBug bug = do@@ -398,8 +401,8 @@     prodVersion = T.unwords (bugVersion bug)  putBugId :: BugId -> IO ()-putBugId =-  T.putStrLn . (("https://" <> brc <> "/show_bug.cgi?id=") <>) . intAsText+putBugId bid =+  putStrLn $ "https://" <> T.unpack brc <> "/show_bug.cgi?id=" <> show bid  -- uniq for lists dropDuplicates :: Eq a => [a] -> [a]
src/Cmd/Bugs.hs view
@@ -17,5 +17,5 @@             case keyword of               Nothing -> statusOpen               Just key -> statusOpen .&&. summaryContains key-      (bugs, _) <- bugsSession $ pkgBugs (unPackage pkg) .&&. query+      bugs <- bugsAnon $ pkgBugs (unPackage pkg) .&&. query       mapM_ putBugVer $ sortBugsByProduct bugs
src/Cmd/Build.hs view
@@ -27,20 +27,23 @@   , buildoptNoFailFast :: Bool   , buildoptTarget :: Maybe String   , buildoptOverride :: Bool+  , buildoptWaitrepo :: Maybe Bool   , buildoptDryrun :: Bool   , buildoptUpdateType :: Maybe UpdateType+  , buildoptUseChangelog :: Bool+  , buildoptByPackage :: Bool   } +-- FIXME --sort -- FIXME --add-to-update nvr--- FIXME vertical vs horizontal builds (ie by package or branch) -- FIXME --rpmlint (only run for rawhide?) -- FIXME support --wait-build=NVR -- FIXME build from ref -- FIXME provide direct link to failed task/build.log -- FIXME --auto-override for deps in testing--- FIXME -B fails to find new branches--- FIXME --no-wait+-- FIXME -B fails to find new branches (fixed?) -- FIXME --ignore-dirty??+-- FIXME disallow override for autoupdate? buildCmd :: BuildOpts -> (BranchesReq, [String]) -> IO () buildCmd opts (breq, pkgs) = do   let singleBrnch = if isJust (buildoptTarget opts)@@ -49,7 +52,13 @@   let mlastOfPkgs = if length pkgs > 1                     then Just (Package (last pkgs))                     else Nothing-  withPackageByBranches (Just False) cleanGitFetchActive singleBrnch (buildBranch mlastOfPkgs opts) (breq, pkgs)+  if not (buildoptByPackage opts) && breq /= Branches [] && length pkgs > 1+    then do+    brs <- listOfBranches True True breq+    forM_ brs $ \br ->+      withPackageByBranches (Just False) cleanGitFetchActive singleBrnch (buildBranch mlastOfPkgs opts) (Branches [br], pkgs)+    else+    withPackageByBranches (Just False) cleanGitFetchActive singleBrnch (buildBranch mlastOfPkgs opts) (breq, pkgs)  -- FIXME what if untracked files buildBranch :: Maybe Package -> BuildOpts -> Package -> AnyBranch -> IO ()@@ -73,25 +82,28 @@   let spec = packageSpec pkg   checkForSpecFile spec   checkSourcesMatch spec-  nvr <- pkgNameVerRel' br spec   unpushed <- gitShortLog $ "origin/" ++ show br ++ "..HEAD"-  unless (null unpushed) $-    putStrLn $ "\n" ++ nvr ++ "\n"-  when (not merged || br == Rawhide) $-    unless (null unpushed) $ do-      putStrLn "Local commits:"-      mapM_ putStrLn unpushed+  nvr <- pkgNameVerRel' br spec+  putStrLn ""   mpush <-     if null unpushed then return Nothing-    else+    else do+      when (not merged || br == Rawhide) $ do+        putStrLn $ nvr ++ "\n"+        putStrLn "Local commits:"+        mapM_ putStrLn unpushed+        putStrLn ""       -- see mergeBranch for: unmerged == 1 (774b5890)       if tty && (not merged || (newrepo && ancestor && length unmerged == 1))-      then refPrompt unpushed $ "Press Enter to push and build" ++ (if length unpushed > 1 then "; or give a ref to push" else "") ++ (if not newrepo then "; or 'no' to skip pushing" else "")-      else return $ Just Nothing+        then do+        refPrompt unpushed $ "Press Enter to push and build" ++ (if length unpushed > 1 then "; or give a ref to push" else "") ++ (if not newrepo then "; or 'no' to skip pushing" else "")+        else return $ Just Nothing   let dryrun = buildoptDryrun opts   buildstatus <- maybeTimeout 30 $ kojiBuildStatus nvr   let mtarget = buildoptTarget opts       target = fromMaybe (branchTarget br) mtarget+      mwaitrepo = buildoptWaitrepo opts+      override = buildoptOverride opts   case buildstatus of     Just BuildComplete -> do       putStrLn $ nvr ++ " is already built"@@ -102,13 +114,14 @@         autoupdate <- checkAutoBodhiUpdate br         unless autoupdate $ do           unless (any (`elem` tags) [show br, show br ++ "-updates", show br ++ "-updates-pending", show br ++ "-updates-testing", show br ++ "-updates-testing-pending"]) $ do-            mbug <- fst <$>  bzReviewSession+            mbug <- bzReviewAnon             bodhiUpdate dryrun mbug spec nvr           unless (any (`elem` tags) [show br, show br ++ "-updates", show br ++ "-override"]) $-            when (buildoptOverride opts) $+            when override $             bodhiCreateOverride dryrun Nothing nvr-        when (isJust mlastpkg && mlastpkg /= Just pkg) $-          when (buildoptOverride opts || autoupdate) $+        when (isJust mlastpkg && mlastpkg /= Just pkg || mwaitrepo == Just True) $+          when ((override && mwaitrepo /= Just False) ||+                (autoupdate && mwaitrepo == Just True)) $             kojiWaitRepo dryrun target nvr     Just BuildBuilding -> do       putStrLn $ nvr ++ " is already building"@@ -132,8 +145,10 @@           let tag = fromMaybe (branchDestTag br) mtarget           mlatest <- kojiLatestNVR tag $ unPackage pkg           if equivNVR nvr (fromMaybe "" mlatest)-            then error' $ nvr ++ " is already latest" ++ if Just nvr /= mlatest then " (modulo disttag)" else ""+            then putStrLn $ nvr ++ " is already latest" ++ if Just nvr /= mlatest then " (modulo disttag)" else ""             else do+            when (null unpushed || merged && br /= Rawhide) $ do+              putStrLn $ nvr ++ "\n"             firstBuild <- do               mtestingRepo <- bodhiTestingRepo br               case mtestingRepo of@@ -162,11 +177,7 @@               kojiBuildBranch target pkg mbuildref ["--fail-fast" | not (buildoptNoFailFast opts)]             mBugSess <-               if firstBuild-              then do-              (mbid, session) <- bzReviewSession-              return $ case mbid of-                Just bid -> Just (bid,session)-                Nothing -> Nothing+              then bzReviewSession               else return Nothing             autoupdate <- checkAutoBodhiUpdate br             if autoupdate@@ -177,17 +188,20 @@                 -- FIXME diff previous changelog?                 bodhiUpdate dryrun (fmap fst mBugSess) spec nvr                 -- FIXME prompt for override note-                when (buildoptOverride opts) $+                when override $                   bodhiCreateOverride dryrun Nothing nvr-            when (isJust mlastpkg && mlastpkg /= Just pkg) $-              when (buildoptOverride opts || autoupdate) $+            when (isJust mlastpkg && mlastpkg /= Just pkg || mwaitrepo == Just True) $+              when ((override && mwaitrepo /= Just False) ||+                    (autoupdate && mwaitrepo == Just True)) $               kojiWaitRepo dryrun target nvr   where     bodhiUpdate :: Bool -> Maybe BugId -> FilePath -> String -> IO ()     bodhiUpdate dryrun mreview spec nvr = do       changelog <- if isJust mreview                    then getSummaryURL spec-                   else getChangeLog (Just "update") spec+                   else if buildoptUseChangelog opts+                        then cleanChangelog spec+                        else changeLogPrompt (Just "update") spec       let cbugs = mapMaybe extractBugReference $ lines changelog           bugs = let bids = [show rev | Just rev <- [mreview]] ++ cbugs in             if null bids then [] else ["--bugs", intercalate "," bids]
src/Cmd/Bump.hs view
@@ -10,39 +10,58 @@ import Koji import Package -bumpPkgs :: Maybe CommitOpt -> (BranchesReq,[String]) -> IO ()-bumpPkgs mopt =-  withPackageByBranches (Just False) cleanGitFetchActive AnyNumber bumpPkg+import System.IO.Extra++-- FIXME --force+-- FIXME --target+-- FIXME detect rpmautospec and add empty commit+bumpPkgs :: Bool -> Maybe CommitOpt -> (BranchesReq,[String]) -> IO ()+bumpPkgs local mopt =+  withPackageByBranches (Just local) (if local then cleanGit else cleanGitFetchActive)+  AnyNumber bumpPkg   where     bumpPkg :: Package -> AnyBranch -> IO ()     bumpPkg pkg br = do-      -- FIXME or check for unpushed bump-      mlatest <--        case br of-          RelBranch rbr ->-            let tag = branchDestTag rbr in-              kojiLatestNVR tag $ unPackage pkg-          _ -> return Nothing-      spec <- localBranchSpecFile pkg br-      rbr <--        case br of-          RelBranch rbr -> return rbr-          OtherBranch _ -> systemBranch-      nvr <- pkgNameVerRel' rbr spec-      if equivNVR nvr (fromMaybe "" mlatest) then do-        git_ "log" ["origin..HEAD", "--pretty=oneline"]-        let clmsg =-              case mopt of-                Just (CommitMsg msg) -> msg-                _ -> "rebuild"-        cmd_ "rpmdev-bumpspec" ["-c", clmsg, spec]-        let copts =-              case mopt of-                Nothing -> ["-m", "bump release"]-                Just opt ->-                  case opt of-                    CommitMsg msg -> ["-m", msg]-                    -- FIXME reject amend if already pushed-                    CommitAmend -> ["--amend", "--no-edit"]-        git_ "commit" $ "-a" : copts-        else putStrLn "already bumped"+      dead <- doesFileExist "dead.package"+      if dead+        then putStrLn "dead package"+        else do+        spec <- localBranchSpecFile pkg br+        rbr <-+          case br of+            RelBranch rbr -> return rbr+            OtherBranch _ -> systemBranch+        newnvr <- pkgNameVerRel' rbr spec+        moldnvr <-+          if local+          then do+            withTempFile $ \tempfile -> do+              git "show" ["origin:" ++ spec] >>= writeFile tempfile+              pkgNameVerRel rbr tempfile+          else+            case br of+              RelBranch rbr' ->+                let tag = branchDestTag rbr' in+                  kojiLatestNVR tag $ unPackage pkg+              -- FIXME fallback to local?+              _ -> return Nothing+        if equivNVR newnvr (fromMaybe "" moldnvr)+          then do+          git_ "log" ["origin..HEAD", "--pretty=oneline"]+          let clmsg =+                case mopt of+                  Just (CommitMsg msg) -> msg+                  _ -> "rebuild"+          -- FIXME check for rpmautospec first+          cmd_ "rpmdev-bumpspec" ["-c", clmsg, spec]+          let copts =+                case mopt of+                  Nothing -> ["-m", "bump release"]+                  Just opt ->+                    case opt of+                      CommitMsg msg -> ["-m", msg]+                      -- FIXME reject amend if already pushed+                      CommitAmend -> ["--amend", "--no-edit"]+          -- FIXME quiet commit?+          git_ "commit" $ "-a" : copts+          else putStrLn "already bumped"
src/Cmd/Clone.hs view
@@ -11,7 +11,7 @@ data CloneRequest = CloneUser (Maybe String) | ClonePkgs [String]  -- FIXME allow pagure repo wildcard--- FIXME --anonymous (detect commit rights? or a ssh key?)+-- FIXME (detect commit rights or a ssh key?) cloneCmd :: Maybe Branch -> CloneRequest -> IO () cloneCmd mbr request = do   pkgs <- case request of@@ -20,4 +20,6 @@               map (takeFileName . T.unpack) <$> pagureUserRepos srcfpo userid             -- FIXME detect/prevent "path/dir"             ClonePkgs ps -> return ps-  mapM_ (clonePkg False mbr) pkgs+  mfas <- maybeFasIdFromKrb+  let cloneuser = maybe AnonClone (const UserClone) mfas+  mapM_ (clonePkg False cloneuser mbr) pkgs
src/Cmd/Commit.hs view
@@ -10,8 +10,11 @@ import Prompt  -- FIXME use branches after all?-commitPkgs :: Maybe CommitOpt -> [String] -> IO ()-commitPkgs mopt args =+-- FIXME handle multiline changelog entries with "-m description"+commitPkgs :: Maybe CommitOpt -> Bool -> Bool -> [String] -> IO ()+commitPkgs mopt firstLine notstaged args = do+  when (isJust mopt && firstLine) $+    error' "--first-line cannot be used with other commit msg options"   if null args     then commitPkg "."     else mapM_ commitPkg args@@ -30,19 +33,31 @@             Nothing -> do               changelog <- do                 spec <- findSpecfile-                clog <- cleanChangelog <$> cmd "rpmspec" ["-q", "--srpm", "--qf", "%{changelogtext}", spec]-                when (length (lines clog) > 1) $-                  putStrLn clog-                diff <- git "diff" ["-U0", "HEAD"]-                if ("+- " ++ clog) `elem` lines diff-                  then putStrLn clog >> return clog-                  else putStrLn diff >> readCommitMsg+                clog <- lines <$> cleanChangelog spec+                case clog of+                  [] -> readCommitMsg+                  [msg] -> putStrLn msg >> return msg+                  msgs ->+                    if firstLine+                    then return $ removePrefix "- " $ head msgs+                    else do+                      diff <- git "diff" ["-U0", "HEAD"]+                      let newlogs =+                            filter (\c -> ("+- " ++ c) `elem` lines diff) clog+                      case newlogs of+                        [] -> putStrLn diff >> readCommitMsg+                        [msg] -> putStrLn msg >> return (removePrefix "- " msg)+                        _ -> mapM_ putStrLn newlogs >> readCommitMsg               return ["-m", changelog]-          git_ "commit" $ "-a" : opts+          git_ "commit" $ ["-a" | notstaged] ++ opts  readCommitMsg :: IO String readCommitMsg = do-  clog <- prompt "\nPlease input the commit message"-  if null clog-    then readCommitMsg-    else return clog+  tty <- isTty+  if tty+    then do+    clog <- prompt "\nPlease input the commit message"+    if null clog+      then readCommitMsg+      else return clog+    else error' "please input commit message in a terminal"
src/Cmd/Copr.hs view
@@ -12,6 +12,7 @@ import Common.System import qualified Common.Text as T import Package+import Types (Archs(..))  import Data.Ini.Config import Network.HTTP.Query (lookupKey, lookupKey')@@ -30,9 +31,12 @@ -- FIXME repo config with a setup command? -- FIXME interact with copr dist-git -- FIXME parallel copr builds-coprCmd :: Bool -> Bool -> BuildBy -> [String] -> String+-- FIXME --exclude-arch+-- FIXME skip existing builds+-- FIXME distless srpm+coprCmd :: Bool -> Bool -> BuildBy -> Maybe Archs -> String         -> (BranchesReq,[String]) -> IO ()-coprCmd dryrun listchroots buildBy archs project (breq, pkgs) = do+coprCmd dryrun listchroots buildBy marchs project (breq, pkgs) = do   chroots <- coprGetChroots   if listchroots     then mapM_ putStrLn chroots@@ -53,12 +57,18 @@             if null brs             then return $ (map (releaseBranch . T.pack) . nub . map removeArch) chroots             else listOfBranches False False breq+          BranchOpt AllFedora -> filter isFedoraBranch <$> getFedoraBranches+          BranchOpt AllEPEL -> filter isEPELBranch <$> getFedoraBranched           _ -> listOfBranches False False breq       let buildroots =             reverseSort $-            if null archs-            then [chroot | chroot <- chroots, removeArch chroot `elem` map branchRelease branches]-            else [chroot | arch <- archs, br <- branches, let chroot = branchRelease br ++ "-" ++ arch, chroot `elem` chroots]+            case marchs of+              Nothing ->+                [chroot | chroot <- chroots, removeArch chroot `elem` map branchRelease branches]+              Just (Archs archs) ->+                [chroot | arch <- archs, br <- branches, let chroot = branchRelease br ++ "-" ++ arch, chroot `elem` chroots]+              Just (ExcludedArchs exarchs) ->+                [chroot | chroot <- chroots, takeArch chroot `notElem` exarchs, removeArch chroot `elem` map branchRelease branches]       if null buildroots         then error' "No valid chroots"         else return buildroots@@ -92,6 +102,7 @@           staggerBuilds srpm initialChroots remainingChroots      removeArch relarch = init $ dropWhileEnd (/= '-') relarch+    takeArch relarch = takeWhileEnd (/= '-') relarch      staggerBuilds srpm initialChroots remainingChroots = do       mapM_ (coprBuild dryrun project srpm) initialChroots
src/Cmd/Diff.hs view
@@ -1,5 +1,6 @@ module Cmd.Diff (   diffCmd,+  DiffFilter(..),   DiffFormat(..),   DiffWork(..)   ) where@@ -11,65 +12,80 @@ import Package  data DiffFormat =-  DiffDefault | DiffQuiet | DiffContext Int | DiffMinimal | DiffStats-  deriving (Eq)+  DiffDefault | DiffContext Int | DiffMinimal | DiffStatus | DiffStats+  deriving Eq  data DiffWork =   DiffWorkAll | DiffWorkUnstage | DiffWorkStaged-  deriving (Eq)+  deriving Eq +data DiffFilter =+  DiffMatch String | DiffNotMatch String+  -- | DiffRegex String | DiffNotRegex String+  deriving Eq+ -- FIXME diff other branches without switching -- FIXME --older/--newer branch-diffCmd :: Bool -> DiffWork -> DiffFormat -> Maybe AnyBranch+diffCmd :: Bool -> DiffWork -> DiffFormat -> Bool -> Maybe DiffFilter -> Maybe AnyBranch         -> (Maybe Branch,[String]) -> IO ()-diffCmd speconly work fmt mwbr =+diffCmd speconly work fmt quiet mpatt mwbr =   withPackagesMaybeBranch Nothing dirtyGit ZeroOrOne diffPkg   where     diffPkg :: Package -> AnyBranch -> IO ()     diffPkg pkg br = do       gitSwitchBranch br-      let contxt = case fmt of-                     DiffContext n -> ["--unified=" ++ show n]-                     DiffMinimal -> ["--unified=0"]-                     -- FIXME hide "files changed" and "insertions" summary-                     DiffStats -> ["--compact-summary"]-                     _ -> []-          (workOpts,workArgs) =-            case work of-              DiffWorkAll -> ([],["HEAD" | isNothing mwbr])-              DiffWorkUnstage -> ([],[])-              DiffWorkStaged -> (["--cached"],[])-          file = [packageSpec pkg | speconly]-      withBranch <--        case mwbr of-          Nothing -> return []-          Just wbr ->-            let brn = show wbr in-              if '/' `elem` brn-              then return [brn]-              else do-                localbrs <- gitLines "branch" ["--format=%(refname:short)"]-                if brn `elem` localbrs-                  then return [brn]-                  else return ["origin/" ++ brn]-      let revdiff = case mwbr of-            Nothing -> []-            Just wbr -> case (wbr,br) of-              (RelBranch rwbr, RelBranch rbr) -> ["-R" | rwbr > rbr]-              _ -> []-      diff <- git "diff" $ contxt ++ workOpts ++ revdiff ++ withBranch ++ workArgs ++ file-      unless (null diff) $-        case fmt of-          DiffQuiet -> putStrLn $ unPackage pkg-          DiffMinimal -> do-            putPkgAnyBrnchHdr pkg br-            putStr $ minifyDiff diff-          _ -> do+      speconlyNone <-+        if speconly+        then notM $ doesFileExist $ packageSpec pkg+        else return False+      if speconlyNone+        then do+        dead <- doesFileExist "dead.package"+        unless dead $ putStrLn $ "no " ++ packageSpec pkg+        else do+        let contxt = case fmt of+                       DiffContext n -> ["--unified=" ++ show n]+                       DiffMinimal -> ["--unified=0"]+                       DiffStatus -> ["--name-status"]+                       -- FIXME hide "files changed" and "insertions" summary+                       DiffStats -> ["--compact-summary"]+                       _ -> []+            (workOpts,workArgs) =+              case work of+                DiffWorkAll -> ([],["HEAD" | isNothing mwbr])+                DiffWorkUnstage -> ([],[])+                DiffWorkStaged -> (["--cached"],[])+            file = [packageSpec pkg | speconly]+        withBranch <-+          case mwbr of+            Nothing -> return []+            Just wbr ->+              let brn = show wbr in+                if '/' `elem` brn+                then return [brn]+                else do+                  localbrs <- gitLines "branch" ["--format=%(refname:short)"]+                  if brn `elem` localbrs+                    then return [brn]+                    else return ["origin/" ++ brn]+        let revdiff = case mwbr of+              Nothing -> []+              Just wbr -> case (wbr,br) of+                (RelBranch rwbr, RelBranch rbr) -> ["-R" | rwbr > rbr]+                _ -> []+        diff <- gitLines "diff" $ contxt ++ workOpts ++ revdiff ++ withBranch ++ workArgs ++ file+        let diffout = (maybe id filterPattern mpatt . simplifyDiff fmt) diff+        -- FIXME: sometimes we may want to list even if diff but no diffout+        unless (null diffout) $+          if quiet+          then putStrLn $ unPackage pkg+          else do             putPkgAnyBrnchHdr pkg br-            putStrLn diff+            mapM_ putStrLn diffout         where-          minifyDiff =-            unlines . maybeRemoveDiffGit . filterCommon . lines+          simplifyDiff :: DiffFormat -> [String] -> [String]+          simplifyDiff DiffMinimal ds =+            (maybeRemoveDiffGit . filterCommon) ds             where               filterCommon =                 -- flist is from swish@@ -83,3 +99,11 @@                   if gitDiffs == [specDiffGit]                   then delete specDiffGit ls                   else ls+          -- drop "2 files changed, 113 insertions(+)"+          simplifyDiff DiffStats ds = if null ds then ds else init ds+          simplifyDiff _ ds = ds++          filterPattern :: DiffFilter -> [String] -> [String]+          filterPattern (DiffMatch patt) = filter (patt `isInfixOf`)+          filterPattern (DiffNotMatch patt) = filter (not . (patt `isInfixOf`))+            --  void $ runProcess $ setStderr nullStream $ proc "grep" [pat, file]
src/Cmd/Import.hs view
@@ -34,7 +34,7 @@       dir <- getCurrentDirectory       when (pkg /= takeFileName dir) $ do         -- FIXME check git repo exists-        clonePkg True Nothing pkg+        clonePkg True UserClone Nothing pkg         putStrLn ""         setCurrentDirectory pkg         -- FIXME: check branch is rawhide
src/Cmd/Install.hs view
@@ -16,6 +16,7 @@ -- FIXME --ignore-uninstalled subpackages -- FIXME --skip-unavailable -- FIXME --check any/all of package installed+-- FIXME add --debug or respect --verbose for dnf commands installCmd :: Bool -> Bool -> Maybe ForceShort -> [BCond] -> Bool            -> (Maybe Branch,[String]) -> IO () installCmd verbose recurse mforceshort bconds reinstall (mbr, pkgs) = do@@ -93,13 +94,14 @@              repoquerySrc = do               putStrLn $ "Repoquerying" +-+ p-              repoquery rbr ["--qf=%{source_name}", "--whatprovides", p]+              sysbr <- systemBranch+              repoquery sysbr rbr ["--qf=%{source_name}", "--whatprovides", p]          filterDebug = filter (\p -> not (any (`isInfixOf` p) ["-debuginfo-", "-debugsource-"]))  notInstalledCmd :: (Maybe Branch,[String]) -> IO () notInstalledCmd =-  withPackagesMaybeBranch Nothing Nothing ZeroOrOne notInstalledPkg+  withPackagesMaybeBranchNoHeadergit ZeroOrOne notInstalledPkg   where     notInstalledPkg :: Package -> AnyBranch -> IO ()     notInstalledPkg pkg br = do
src/Cmd/ListBranches.hs view
@@ -42,8 +42,7 @@         else         withExistingDirectory path $         if skipdead then-          ifM (doesFileExist "dead.package")-          (return ())+          unlessM (doesFileExist "dead.package")           doBranchesPkg         else doBranchesPkg       where@@ -55,7 +54,7 @@           pkg <- getPackageName path           if mode == Current             then do-            br <- gitCurrentBranch+            br <- gitCurrentBranch'             let onbranch =                   case br of                     RelBranch rbr -> Branches [rbr] == breq
src/Cmd/ListPackages.hs view
@@ -29,7 +29,7 @@       let path = "projects"           params = makeKey "short" "1" ++ fork ++ packager ++ makeKey "namespace" "rpms" ++ maybeKey "pattern" mpattern       pages <- queryPaged srcfpo count path params ("pagination", "page")-      mapM_ (printPage . toObject) pages+      mapM_ printPage pages       where         packager =           case mpackager of@@ -45,12 +45,8 @@           in           mapM_ (T.putStrLn . lookupKey' "name") projects -        toObject :: Value -> Object-        toObject (Object obj) = obj-        toObject v = error $ "not object: " ++ show v- -- FIXME limit max number of pages (10?) or --pages-queryPaged :: String -> Bool -> String -> Query -> (String,String) -> IO [Value]+queryPaged :: String -> Bool -> String -> Query -> (String,String) -> IO [Object] queryPaged server count path params (pagination,paging) =   if count     then do
src/Cmd/Local.hs view
@@ -1,9 +1,9 @@ module Cmd.Local (   commandCmd,+  countCmd,   installDepsCmd,   localCmd,   nvrCmd,-  prepCmd,   srpmCmd,   renameMasterCmd   ) where@@ -18,7 +18,6 @@ import Common import Common.System import Git-import InterleaveOutput (cmdSilent') import Package  -- FIXME generate build.log files@@ -44,46 +43,13 @@  srpmCmd :: Bool -> (Maybe Branch,[String]) -> IO () srpmCmd force =-  withPackagesMaybeBranch Nothing Nothing ZeroOrOne srpmBuildPkg+  withPackagesMaybeBranchNoHeadergit ZeroOrOne srpmBuildPkg   where     srpmBuildPkg :: Package -> AnyBranch -> IO ()     srpmBuildPkg pkg br = do       spec <- localBranchSpecFile pkg br       void $ generateSrpm' force (Just br) spec --- FIXME option to clone package-prepCmd :: (Maybe Branch,[String]) -> IO ()-prepCmd (breq,pkgs) =-  withPackagesMaybeBranch Nothing Nothing ZeroOrOne prepPackage (breq,pkgs)-  where-    prepPackage :: Package -> AnyBranch -> IO ()-    prepPackage pkg br = do-      dead <- doesFileExist "dead.package"-      if dead-        then do-        when (length pkgs > 1)$-          putStr $ unPackage pkg ++ ": "-        putStrLn "dead.package"-        else do-        spec <- localBranchSpecFile pkg br-        unlessM (doesFileExist spec) $-          error' $ spec ++ " not found"-        cwd <- getCurrentDirectory-        void $ getSources spec-        gitDir <- isGitRepo-        let rpmdirs =-              [ "--define="++ mcr +-+ cwd | gitDir,-                mcr <- ["_builddir", "_sourcedir"]]-            args = rpmdirs ++ ["-bp", spec]-        case br of-          RelBranch rbr -> do-            nvr <- pkgNameVerRel' rbr spec-            -- newline avoids error starting on same line-            putStr $ "Prepping " ++ nvr ++ ": "-          _ -> return ()-        cmdSilent' "rpmbuild" args-        putStrLn "done"- nvrCmd :: (BranchesReq, [String]) -> IO () nvrCmd =   withPackageByBranches Nothing Nothing AnyNumber nvrBranch@@ -134,8 +100,32 @@   renameMasterBranch :: Package -> AnyBranch -> IO ()   renameMasterBranch _pkg _br = do     locals <- gitLines "branch" ["--format=%(refname:short)"]+    -- FIXME dangling warning in current output:+      -- From ssh://pkgs.fedoraproject.org/rpms/hedgewars+      --  - [deleted]         (none)     -> origin/master+      --    (refs/remotes/origin/HEAD has become dangling)+      -- Branch 'rawhide' set up to track remote branch 'rawhide' from 'origin'.+    -- compare commands with github rename     when ("rawhide" `notElem` locals) $ do       git_ "fetch" ["--prune"]       git_ "branch" ["--move", "master", "rawhide"]       git_ "remote" ["set-head", "origin", "rawhide"]       git_ "branch" ["--set-upstream-to", "origin/rawhide", "rawhide"]++countCmd :: (Maybe Branch,[String]) -> IO ()+countCmd (mbr,pkgs) =+  foldM countPkg 0 pkgs >>= print+  where+    -- FIXME dead.package?+    countPkg :: Int -> String ->  IO Int+    countPkg n path =+      withExistingDirectory path $ do+      whenJust mbr $ gitSwitchBranch . RelBranch+      mspec <- if ".spec" `isExtensionOf` path+               then return $ Just $ takeFileName path+               else maybeFindSpecfile+      case mspec of+        Just spec -> do+          exists <- doesFileExist spec+          return $ n + if exists then 1 else 0+        Nothing -> return n
src/Cmd/Merge.hs view
@@ -85,5 +85,6 @@     else conflictPrompt unmerged $ "Press Enter to skip merge" ++ (if build then " and build" else "") ++ "; or give a ref to attempt merge"   -- ensure still on same branch!   gitSwitchBranch (RelBranch br)-  whenJust mmerge $ \ ref ->+  whenJust mmerge $ \ ref -> do     git_ "merge" [ref]+    git_ "rebase" []
src/Cmd/Mock.hs view
@@ -1,5 +1,6 @@ module Cmd.Mock-  ( mockCmd+  ( mockCmd,+    NoClean(..)   ) where @@ -11,10 +12,15 @@ import Git import Package --- FIXME handle non-release branches-mockCmd :: Bool -> Bool -> Bool -> Bool -> Maybe Branch+data NoClean = NoCleanBefore | NoCleanAfter | NoCleanAll+  deriving Eq++-- FIXME handle non-release branches (on-branch works)+-- FIXME option for --shell without rebuild+-- FIXME add --no-clean-all+mockCmd :: Bool -> Maybe NoClean -> Bool -> Bool -> Maybe Branch         -> (BranchesReq, [String]) -> IO ()-mockCmd dryrun noclean network noCleanAfter mroot (breq, ps) = do+mockCmd dryrun mnoclean network mockshell mroot (breq, ps) = do   branches <-     case breq of       Branches [] ->@@ -40,7 +46,22 @@                  in ["--resultdir=results" </> verrel]               _ -> []       let command = if length pkgs > 1 then "--chain" else "--rebuild"-      (if dryrun then cmdN else cmd_) "mock" $ [command, "--root", mockConfig rootBr] ++ ["--no-clean" | noclean] ++ ["--no-clean-after" | noCleanAfter] ++ ["--config-opts=cleanup_on_failure=False" | not noCleanAfter] ++ ["--enable-network" | network] ++ resultdir ++ srpms+          noclean = case mnoclean of+                      Nothing -> []+                      Just NoCleanBefore -> ["--no-clean"]+                      Just NoCleanAfter -> ["--no-cleanup-after"]+                      Just NoCleanAll -> ["--no-cleanup-all"]+          mockopts_common c = [c, "--root", mockRoot rootBr] ++ noclean ++ ["--enable-network" | network]+          mockbuild_opts = mockopts_common command ++ ["--config-opts=cleanup_on_failure=False" | mnoclean `elem` [Nothing, Just NoCleanBefore]] ++ resultdir ++ srpms+          mockshell_opts = mockopts_common "--shell" ++ ["--no-clean"]+      if dryrun+        then do+        cmdN "mock" mockbuild_opts+        when mockshell $ cmdN "mock" mockshell_opts+        else do+        ok <- cmdBool "mock" mockbuild_opts+        when mockshell $ cmd_ "mock" mockshell_opts+        unless ok $ error' "mockbuild failed"       where         prepSrpm :: AnyBranch -> FilePath -> IO FilePath         prepSrpm rbr pkgdir =
src/Cmd/Parallel.hs view
@@ -33,12 +33,18 @@  -- FIXME option to build multiple packages over branches in parallel -- FIXME use --wait-build=NVR--- FIXME check sources asap-parallelBuildCmd :: Bool -> Maybe SideTagTarget -> Maybe UpdateType -> (BranchesReq, [String]) -> IO ()-parallelBuildCmd dryrun msidetagTarget mupdatetype (breq, pkgs) = do+-- FIXME check sources as early as possible+-- FIXME --single-layer to build packages at once regardless+-- FIXME Haskell subpackages require release bump even with version bump+parallelBuildCmd :: Bool -> Int -> Maybe SideTagTarget -> Maybe UpdateType+                 -> (BranchesReq, [String]) -> IO ()+parallelBuildCmd dryrun firstlayer msidetagTarget mupdatetype (breq, pkgs) = do   branches <-     case pkgs of-      [] -> listOfBranches True True breq+      [] -> do+        unlessM isPkgGitSshRepo $+          error' "Please specify at least one package"+        listOfBranches True True breq       [p] -> withExistingDirectory p $ listOfBranches True True breq       _ -> case breq of              Branches [] -> error' "please specify a branch"@@ -50,21 +56,22 @@   when (isJust mtarget && length branches > 1) $     error' "You can only specify target with one branch"   case pkgs of-    [] -> do-      unlessM isPkgGitSshRepo $-        error' "Please specify at least one package"-      parallelBranches branches+    [] -> parallelBranches branches     [p] -> withExistingDirectory p $            parallelBranches branches     _ ->       forM_ branches $ \ rbr -> do-      layers <- dependencyLayers pkgs-      when (isNothing msidetagTarget && length layers > 1) $+      allLayers <- dependencyLayers pkgs+      let layers = drop firstlayer allLayers+      when (isNothing msidetagTarget && length allLayers > 1) $         unlessM (checkAutoBodhiUpdate rbr) $           error' "You must use --target/--sidetag to build package layers for this branch"       when (length branches > 1) $         putStrLn $ "# " ++ show rbr-      targets <- mapM (parallelBuild rbr) $ zip (reverse [0..(length layers - 1)]) layers+      -- FIXME: pass remaining layers for failure error+      targets <- mapM (parallelBuild rbr)+                 $ zip [firstlayer..length allLayers]+                 $ init $ tails layers -- tails ends in []       when (isJust msidetagTarget && null targets && not dryrun) $         error' "No target was returned from jobs!"       unless (isNothing msidetagTarget || null targets || dryrun) $ do@@ -76,7 +83,7 @@     parallelBranches :: [Branch] -> IO ()     parallelBranches brs = do       krbTicket-      putStrLn $ "Building " ++ show (length brs) ++ " branches in parallel:"+      putStrLn $ "= Building " ++ show (length brs) ++ " branches in parallel:"       putStrLn $ unwords $ map show brs       jobs <- mapM setupBranch brs       (failures,_mtarget) <- watchJobs Nothing [] jobs@@ -86,52 +93,60 @@         setupBranch :: Branch -> IO Job         setupBranch br = do           job <- startBuild False False br "." >>= async-          unless dryrun $ sleep 5+          unless dryrun $ sleep 3           return (show br,job) -    parallelBuild :: Branch -> (Int,[String]) -> IO String-    parallelBuild br (layersleft,layer) =  do+    parallelBuild :: Branch -> (Int,[[String]]) -> IO String+    parallelBuild _ (_,[]) = return "" -- should not reach here+    parallelBuild br (layernum, layer:nextLayers) =  do       krbTicket-      putStrLn $ "\nBuilding parallel layer of" +++      putStrLn $ "\n= Building parallel layer #" ++ show layernum ++         if nopkgs > 1-        then " " ++ show nopkgs ++ " packages:"+        then " (" ++ show nopkgs ++ " packages):"         else ":"       putStrLn $ unwords layer-      putStrLn $ "(" ++ show layersleft ++ " more layer" ++-        if layersleft > 1 then "s" else ""-        ++ " left)"+      -- maybe print total pending packages+      unless (null nextLayers) $+        putStrLn $ plural layersleft "more layer" ++ " left with " +++        let layerspkgs = map length nextLayers+        in case layerspkgs of+             [l] -> plural l "package"+             _ -> show layerspkgs ++ " packages"       jobs <- mapM setupBuild layer       (failures,mtarget) <- watchJobs Nothing [] jobs-      unless (null failures) $-        error' $ "Build failures: " ++ unwords failures+      -- FIXME prompt to continue?+      unless (null failures) $ do+        let pending = sum $ map length nextLayers+        error' $ "Build failures in layer " ++ show layernum ++ ": " +++          unwords failures ++ "\n\n" +++          show pending ++ " pending packages:\n" +++          unwords (map unwords nextLayers)       when (null jobs) $         error' "No jobs run"       return $ fromMaybe (error' "No target determined") mtarget       where         nopkgs = length layer+        layersleft = length nextLayers          setupBuild :: String -> IO Job         setupBuild pkg = do           job <- startBuild (layersleft > 0) (nopkgs > 5) br pkg >>= async-          unless dryrun $ sleep 5+          unless dryrun $ sleep 3           return (pkg,job)      watchJobs :: Maybe String -> [String] -> [Job] -> IO ([String],Maybe String)     watchJobs mtarget fails [] = return (fails,mtarget)     watchJobs mtarget fails (job:jobs) = do-      sleep 1       status <- poll (snd job)       case status of-        Nothing -> watchJobs mtarget fails (jobs ++ [job])+        Nothing -> sleep 1 >> watchJobs mtarget fails (jobs ++ [job])         Just (Right (target,nvr)) -> do-          putStrLn ""-          putStrLn $ nvr ++ " job " ++ color Yellow "completed" ++  " (" ++ show (length jobs) ++ " jobs left)"+          putStrLn $ color Yellow nvr ++ " job completed (" ++ show (length jobs) ++ " jobs left in layer)"           watchJobs (Just target) fails jobs         Just (Left except) -> do-          putStrLn ""           print except           let pkg = fst job-          putStrLn $ "** " ++ pkg ++ " job " ++ color Magenta "failed" ++ " ** (" ++ show (length jobs) ++ " jobs left)"+          putStrLn $ "** " ++ color Magenta pkg ++ " job " ++ color Magenta "failed" ++ " ** (" ++ show (length jobs) ++ " jobs left in layer)"           watchJobs mtarget (pkg : fails) jobs      -- FIXME prefix output with package name@@ -159,12 +174,14 @@                     case tags of                       [] -> do                         out <- head . lines <$> fedpkg "request-side-tag" []-                        if "Side tag '" `isPrefixOf` out then+                        if "Side tag '" `isPrefixOf` out+                          then do+                          putStrLn out                           return $ init . dropWhileEnd (/= '\'') $ dropPrefix "Side tag '" out                           else error' "'fedpkg request-side-tag' failed"                       [tag] -> return tag                       _ -> error' $ "More than one user side-tag found for " ++ show br-      putStrLn $ nvr ++ " (" ++ target ++ ")\n"+      putStrLn $ nvr ++ " (" ++ target ++ ")"       -- FIXME should compare git refs       -- FIXME check for target       buildstatus <- kojiBuildStatus nvr@@ -172,7 +189,7 @@       mlatest <- kojiLatestNVR tag $ unPackage pkg       case buildstatus of         Just BuildComplete -> do-          putStrLn $ nvr ++ " is " ++ color Green "already built"+          putStrLn $ color Green nvr ++ " is " ++ color Green "already built"           when (br /= Rawhide && morelayers && target == branchTarget br) $ do             tags <- kojiNVRTags nvr             unless (any (`elem` tags) [show br, show br ++ "-updates", show br ++ "-override"]) $@@ -210,24 +227,20 @@         kojiWaitTaskAndRepo :: Bool -> String -> String -> TaskID -> IO (String,String)         kojiWaitTaskAndRepo newpkg nvr target task = do           finish <- kojiWaitTask task-          putStrLn ""           if finish             then putStrLn $ color Green $ nvr ++ " build success"+            -- FIXME print koji task url             else error' $ color Red $ nvr ++ " build failed"           autoupdate <- checkAutoBodhiUpdate br           if autoupdate then             when newpkg $ do-            mBugSess <- do-              (mbid, session) <- bzReviewSession-              return $ case mbid of-                Just bid -> Just (bid,session)-                Nothing -> Nothing-            whenJust mBugSess $-              \ (bid,session) -> putBugBuild dryrun session bid nvr+            mBugSess <- bzReviewSession+            whenJust mBugSess $ \(bid,session) ->+              putBugBuild dryrun session bid nvr             else do             when (target == branchTarget br && morelayers) $               -- -- FIXME: avoid prompt in-              -- changelog <- getChangeLog Nothing spec+              -- changelog <- changeLogPrompt Nothing spec               -- bodhiUpdate (fmap fst mBugSess) changelog nvr               bodhiCreateOverride dryrun Nothing nvr           when morelayers $
src/Cmd/PkgReview.hs view
@@ -12,7 +12,7 @@ import qualified Common.Text as T  import Data.Char-import Network.HTTP.Directory+import Network.HTTP.Directory (httpExists, httpManager)  import Branches import Bugzilla@@ -82,7 +82,7 @@     error' "This NVR was already posted on the review bug: please bump"   mockRpmLint mock (scratchOpt == ScratchBuild) pkg spec srpm   (mkojiurl,specSrpmUrls) <- buildAndUpload scratchOpt srpm pkg spec-  changelog <- getChangeLog Nothing spec+  changelog <- changeLogPrompt Nothing spec   commentBug session bid (specSrpmUrls <> (if null changelog then "" else "\n\n" <> changelog) <> maybe "" ("\n\nKoji scratch build: " <>) mkojiurl)   -- putStrLn "Review bug updated"   where@@ -120,7 +120,7 @@     if mock then do       -- FIXME check that mock is installed       let resultsdir = "results_" ++ pkg-      cmd_ "mock" ["--root", mockConfig Rawhide, "--resultdir=" ++ resultsdir, srpm]+      cmd_ "mock" ["--root", mockRoot Rawhide, "--resultdir=" ++ resultsdir, srpm]       map (resultsdir </>) . filter ((== ".rpm") . takeExtension) <$> listDirectory resultsdir     else       builtRpms (RelBranch Rawhide) spec >>= filterM doesFileExist@@ -134,9 +134,10 @@ reviewPackage mpkg = do   -- FIXME if spec file exists use it directly   pkg <- maybe getDirectoryName return mpkg-  (bugs, _) <- if all isDigit pkg-    then bugsSession $ packageReview .&&. statusNewAssigned .&&. bugIdIs (read pkg)-    else bugsSession $ pkgReviews pkg .&&. statusNewAssigned+  bugs <- bugsAnon $+          if all isDigit pkg+          then packageReview .&&. statusNewAssigned .&&. bugIdIs (read pkg)+          else pkgReviews pkg .&&. statusNewAssigned   case bugs of     [bug] -> do       putReviewBug False bug
+ src/Cmd/Prep.hs view
@@ -0,0 +1,71 @@+module Cmd.Prep (+  prepCmd,+  PrepPre(..)+  ) where++import Branches+import Cmd.Clone+import Common+import Common.System+import Git+import InterleaveOutput (cmdSilent')+import Package++data PrepPre = PrepClone | PrepPull+  deriving Eq++prepCmd :: Maybe PrepPre -> Bool -> (Maybe Branch,[String]) -> IO ()+prepCmd mpre verbose (mbr,pkgs) = do+  when (mpre == Just PrepClone) $+    cloneCmd mbr (ClonePkgs pkgs)+  withPackagesMaybeBranchNoHeadergit ZeroOrOne prepPackage (mbr,pkgs)+  where+    prepPackage :: Package -> AnyBranch -> IO ()+    prepPackage pkg br = do+      when (mpre == Just PrepPull) $+        git_ "pull" []+      dead <- doesFileExist "dead.package"+      if dead+        then do+        when (length pkgs > 1)$+          putStr $ unPackage pkg ++ ": "+        putStrLn "dead.package"+        else do+        spec <- localBranchSpecFile pkg br+        unlessM (doesFileExist spec) $+          error' $ spec ++ " not found"+        cwd <- getCurrentDirectory+        void $ getSources spec+        installMissingMacros spec+        gitDir <- isGitRepo+        let rpmdirs =+              [ "--define="++ mcr +-+ cwd | gitDir,+                mcr <- ["_builddir", "_sourcedir"]]+            args = rpmdirs ++ ["-bp", spec]+        case br of+          RelBranch rbr -> do+            nvr <- pkgNameVerRel' rbr spec+            -- newline avoids error starting on same line+            putStr $ "Prepping " ++ nvr ++ ": "+          _ -> return ()+        (if verbose then cmdLog else cmdSilent') "rpmbuild" args+        putStrLn "done"+++srpmMacros :: [(String,String)]+srpmMacros =+  [("%gometa", "go-rpm-macros"),+   ("fontpkgname", "fonts-rpm-macros"),+   ("%cargo_prep", "rust-packaging")]++needSrpmMacro :: FilePath -> (String,String) -> IO (Maybe String)+needSrpmMacro spec (meta, macros) = do+  contents <- readFile spec+  return $ if meta `isInfixOf` contents then Just macros else Nothing++installMissingMacros :: FilePath -> IO ()+installMissingMacros spec = do+  macros <- mapMaybeM (needSrpmMacro spec) srpmMacros+  missing <- filterM notInstalled macros+  unless (null missing) $+    cmd_ "/usr/bin/sudo" $ ["/usr/bin/dnf", "install", "--assumeyes"] ++ missing
− src/Cmd/Pull.hs
@@ -1,15 +0,0 @@-module Cmd.Pull (pullPkgs) where--import Branches-import Git-import Package---- FIXME pulling more than one branch--- FIXME print nvr after pulling or old -> new-pullPkgs :: (BranchesReq, [String]) -> IO ()-pullPkgs =-  withPackageByBranches (Just False) cleanGitFetch AnyNumber pullPkg-  where-    pullPkg :: Package -> AnyBranch -> IO ()-    pullPkg _pkg _br =-      getReleaseBranch >>= gitMergeOrigin
+ src/Cmd/PullPush.hs view
@@ -0,0 +1,34 @@+module Cmd.PullPush (pullPkgs, pushPkgs) where++import Branches+import Git+import Package++-- FIXME pulling more than one branch+-- FIXME print nvr after pulling or old -> new+pullPkgs :: Bool -> (BranchesReq, [String]) -> IO ()+pullPkgs lenient =+  withPackageByBranches (Just False) (if lenient then Nothing else cleanGitFetch) AnyNumber pullPkg+  where+    pullPkg :: Package -> AnyBranch -> IO ()+    pullPkg pkg _br =+      if lenient+      then do+        haveGit <- isPkgGitRepo+        if haveGit+          then doPullPkg+          else putStrLn $ "ignoring " ++ unPackage pkg+      else doPullPkg+      where+        doPullPkg :: IO ()+        doPullPkg =+          getReleaseBranchWarn >>= gitMergeOrigin++pushPkgs :: (BranchesReq, [String]) -> IO ()+pushPkgs =+  withPackageByBranches (Just False) cleanGitFetch AnyNumber pushPkg+  where+    pushPkg :: Package -> AnyBranch -> IO ()+    pushPkg _pkg _br = do+      gitShortLog1 Nothing >>= putStrLn+      gitPushSilent Nothing
src/Cmd/Repoquery.hs view
@@ -6,14 +6,19 @@ import Common.System import Package +import qualified Data.List as L+ repoqueryCmd :: (BranchesReq, [String]) -> IO () repoqueryCmd (breq, pkgs) = do   query <- if null pkgs            then pure <$> getDirectoryName            else return pkgs   brs <- listOfBranches True False breq-  mapM_ (repoquery_ query) brs+  sysbr <- systemBranch+  mapM_ (repoquery_ sysbr query) brs   where-    repoquery_ :: [String] -> Branch -> IO ()-    repoquery_ query br =-      repoquery br query >>= putStrLn+    repoquery_ :: Branch -> [String] -> Branch -> IO ()+    repoquery_ sysbr query br = do+      let qf = ["--queryformat=%{repoid}: %{name}-%{version}-%{release}.%{arch}"+               | not (any ("--qf" `L.isPrefixOf`) query)]+      repoquery sysbr br (qf ++ query) >>= putStrLn
src/Cmd/RequestBranch.hs view
@@ -35,14 +35,14 @@   branches <- getRequestedBranches breq   newbranches <- filterExistingBranchRequests branches   unless (null newbranches) $ do-    (mbid,session) <- bzReviewSession+    mbidsession <- bzReviewSession     urls <- forM newbranches $ \ br -> do-      when mock $ fedpkg_ "mockbuild" ["--root", mockConfig br]+      when mock $ fedpkg_ "mockbuild" ["--root", mockRoot br]       when multiple $ putStr (unPackage pkg ++ " ")-      when (length newbranches > 1) $ putStr (show br ++ " ")+      when (length newbranches > 1) $ print br       fedpkg "request-branch" [show br]-    case mbid of-      Just bid -> commentBug session bid+    case mbidsession of+      Just (bid,session) -> commentBug session bid       Nothing -> putStrLn       $ unlines urls   where
src/Cmd/RequestRepo.hs view
@@ -68,7 +68,7 @@         putStrLn ""         branches <- getRequestedBranches breq         forM_ branches $ \ br -> do-          when mock $ fedpkg_ "mockbuild" ["--root", mockConfig br]+          when mock $ fedpkg_ "mockbuild" ["--root", mockRoot br]           putStr (show br ++ " ")           fedpkg_ "request-branch" ["--repo", pkg, show br]         putStrLn ""
src/Cmd/Reviews.hs view
@@ -18,5 +18,5 @@  findReview :: String -> IO () findReview pkg = do-  (bugs, _) <- bugIdsSession $ pkgReviews pkg-  mapM_ putBugId bugs+  bugIdsAnon (pkgReviews pkg)+    >>= mapM_ putBugId
src/Cmd/Scratch.hs view
@@ -11,16 +11,15 @@ import Git import Koji import Package--data Archs = Archs [String] | ExcludedArchs [String]+import Types (Archs(..))  -- FIXME default to rawhide/main? -- FIXME build from a specific git ref--- FIXME print message about uploading srpm+-- FIXME allow multiple --target's (parallel too) scratchCmd :: Bool -> Bool -> Bool -> Maybe Archs -> Maybe String            -> Maybe String -> (BranchesReq, [String]) -> IO () scratchCmd dryrun rebuildSrpm nofailfast marchopts mtarget mref (breq,pkgs) =-  withPackageByBranches (Just False) Nothing AnyNumber scratchBuild (breq,pkgs)+  withPackageByBranches (Just True) Nothing AnyNumber scratchBuild (breq,pkgs)   where     scratchBuild :: Package -> AnyBranch -> IO ()     scratchBuild pkg br = do
src/Cmd/Sort.hs view
@@ -6,8 +6,9 @@ where  import Control.Monad.Extra-import Distribution.RPM.Build.Graph -- (dependencySortRpmOpts)-import Distribution.RPM.Build.Order (dependencySortRpmOpts)+import Distribution.RPM.Build.Graph+import Distribution.RPM.Build.Order (dependencySortRpmOpts,+                                     dependencySortParallel)  import Branches import Git@@ -15,13 +16,15 @@  data RpmWith = RpmWith String | RpmWithout String -sortCmd :: Maybe RpmWith -> (Maybe Branch,[String]) -> IO ()-sortCmd _ (_,[]) = return ()-sortCmd mrpmwith (mbr, pkgs) = do-  withPackagesMaybeBranch Nothing Nothing ExactlyOne noop (mbr, pkgs)+sortCmd :: Bool -> Maybe RpmWith -> (Maybe Branch,[String]) -> IO ()+sortCmd _ _ (_,[]) = return ()+sortCmd parallel mrpmwith (mbr, pkgs) = do+  withPackagesMaybeBranchNoHeadergit ExactlyOne noop (mbr, pkgs)   let rpmopts = maybe [] toRpmOption mrpmwith-  packages <- dependencySortRpmOpts rpmopts $ reverse pkgs-  putStrLn $ unwords packages+  if parallel+    -- reverse because rpmbuild-order reverses the order of independent pkgs?+    then dependencySortParallel (reverse pkgs) >>= mapM_ (putStrLn . unwords)+    else dependencySortRpmOpts rpmopts (reverse pkgs) >>= putStrLn . unwords  noop :: Package -> AnyBranch -> IO () noop _pkg br =@@ -33,7 +36,7 @@  graphCmd :: Bool -> Maybe RpmWith -> (Maybe Branch,[FilePath]) -> IO () graphCmd dot mrpmwith (mbr, pkgs) = do-  withPackagesMaybeBranch Nothing Nothing ZeroOrOne noop (mbr, pkgs)+  withPackagesMaybeBranchNoHeadergit ZeroOrOne noop (mbr, pkgs)   let rpmopts = maybe [] toRpmOption mrpmwith   createGraph'''' False [] rpmopts False False True Nothing pkgs >>=     if dot then printGraph else renderGraph
src/Cmd/Status.hs view
@@ -107,11 +107,7 @@       let (days,nomRest) = diff `divMod'` nominalDay :: (Int,NominalDiffTime)           nominalHour = 3600 :: NominalDiffTime           hours = nomRest `div'` nominalHour :: Int-      putStr $ " " ++ showUnits days "day" +-+ showUnits hours "hour"--    showUnits :: Int -> String -> String-    showUnits i uni = show i ++ " " ++ uni ++-                      if i == 1 then "" else "s"+      putStr $ " " ++ plural days "day" +-+ plural hours "hour"  #if MIN_VERSION_time(1,8,0) #else
src/Cmd/Update.hs view
@@ -3,8 +3,6 @@   ) where -import SimpleCmd- import Branches import Common import Common.System@@ -13,32 +11,51 @@ import Krb import Package -updateCmd :: (Maybe Branch,[String]) -> IO ()-updateCmd (mbr,args) = do+import Data.RPM.VerCmp++-- FIXME check EVR increased+-- FIXME if multiple sources might need to bump release+updateCmd :: Bool -> Bool -> Bool -> (Maybe Branch,[String]) -> IO ()+updateCmd onlysources force allowHEAD (mbr,args) = do   pkgGit <- isPkgGitSshRepo-  let (mver,pkgs) = case args of-        [a] -> if pkgGit then (Just a,[]) else (Nothing,[a])-        _ -> (Nothing,args)-  withPackagesMaybeBranch (Just False) dirtyGitFetch ZeroOrOne (updatePkg mver) (mbr, pkgs)+  (mver,pkgs) <-+    case args of+      [a] -> do+        if pkgGit+          then return (Just a,[])+          else do+          mspec <- maybeFindSpecfile+          return $ if isJust mspec+                   then (Just a,[])+                   else (Nothing,[a])+      _ -> return (Nothing,args)+  let mgitops =+        let dirty = if allowHEAD then dirtyGitHEAD else dirtyGitFetch+        in if pkgGit+           then dirty+           else if null pkgs then Nothing else dirty+  withPackagesMaybeBranch (Just False) mgitops ZeroOrOne (updatePkg mver) (mbr, pkgs)   where     updatePkg :: Maybe String -> Package -> AnyBranch -> IO ()     updatePkg mver pkg br = do-      spec <- localBranchSpecFile pkg br+      spec <- if allowHEAD+              then findSpecfile+              else localBranchSpecFile pkg br       (curver,_) <- pkgVerRel spec       vdiff <- filter ("Version:" `isInfixOf`) . filter (not . ("@@ " `isPrefixOf`)) <$> gitLines "diff" ["-U0", "HEAD", spec]-      when (isNothing mver) $ do-        when (null vdiff) $-          error' "please specify version or edit in spec file"-        unless (length vdiff == 2) $-          error' $ "diff contains complex version change:\n" ++ unlines vdiff-      if Just curver == mver-        then putStrLn $ "already new version " ++ curver-        else do-        --FIXME: compare rpm versions-        -- if newver < oldver-        --   then putStrLn $ "current" +-+ display oldver +-+ "is newer!"-        --   else do-        pkgGit <- isPkgGitSshRepo+      unless (length vdiff `elem` [0,2]) $+        error' $ "diff contains complex version change:\n" ++ unlines vdiff+      case mver of+        Nothing -> do+          when (null vdiff && not onlysources) $+            error' "specify or edit version to update"+          putStrLn $ "current version: " ++ curver+        Just nver -> do+          when (length vdiff == 2) $+            error' $ "spec version already bumped to " ++ curver+          when (curver == nver) $+            putStrLn $ "already new version " ++ curver+      unless onlysources $ do         let (oldver,newver) =               case mver of                 Just nver -> (curver,nver)@@ -46,27 +63,47 @@                   case map (last . words) vdiff of                     [old,new] -> (old,new)                     _ -> error' "complex version change"+        -- FIXME take epoch into account+        when (rpmVerCompare oldver newver == GT) $+          putStrLn $ "current" +-+ oldver +-+ "is newer!"         putStrLn $ oldver ++ " ->\n" ++ newver-        when (curver /= newver) $ do+        if curver /= newver+          then do           editSpecField "Version" newver spec           editSpecField "Release" "0%{?dist}" spec           cmd_ "rpmdev-bumpspec" ["-c", "update to " ++ newver, spec]-        when pkgGit $ do-          sources <- map sourceFieldFile <$> cmdLines "spectool" ["-S", spec]-          cmd_ "sed" ["-i", "/" ++ unPackage pkg ++ "-" ++ oldver ++ "./d", "sources"]-          allExist <- and <$> mapM doesFileExist sources-          unless allExist $ do-            cmd_ "fedpkg" ["sources"]+          -- FIXME should be sure sources exists for distgit+          whenM (doesFileExist "sources") $+            cmd_ "sed" ["-i", "/" ++ unPackage pkg ++ "-" ++ oldver ++ "./d", "sources"]+          else do+          versions <- changelogVersions spec+          let missing = null versions || not ((newver ++ "-") `isPrefixOf` head versions)+          when missing $ do+            cmd_ "rpmdev-bumpspec" ["-c", "update to " ++ newver, spec]+            -- FIXME need to commit after add sources+            git_ "commit" ["-a", "-m", "update to " ++ newver]+      whenM isPkgGitSshRepo $ do+        -- FIXME forM_+        sources <- map sourceFieldFile <$> cmdLines "spectool" ["-S", spec]+        existing <- filterM doesFileExist sources+        unless (existing == sources) $ do+          cmd_ "fedpkg" ["sources"]+          unless force $+            -- FIXME only if not all exist             cmd_ "spectool" ["-g", "-S", spec]-          krbTicket-          copyFile "sources" "sources.fbrnch"-          cmd_ "fedpkg" $ "new-sources" : filter (".tar." `isInfixOf`) sources-          shell_ $ "cat sources.fbrnch >>" +-+ "sources"-          removeFile "sources.fbrnch"-          putStr "Prepping... "-          cmdSilent' "rpmbuild" ["-bp", spec]-          putStrLn "done"-          cmd_ "git" ["commit", "-a", "-m", "update to " ++ newver]+        when force $ do+          let archives = filter isArchiveFile existing+          forM_ archives removeFile+          cmd_ "spectool" ["-g", "-S", spec]+        krbTicket+        copyFile "sources" "sources.fbrnch"+        cmd_ "fedpkg" $ "new-sources" : filter isArchiveFile sources+        --shell_ $ "cat sources.fbrnch >>" +-+ "sources"+        removeFile "sources.fbrnch"+        putStr "Prepping... "+        cmdSilent' "rpmbuild" ["-bp", spec]+        putStrLn "done"+        -- FIXME git amend (if previous commit was update)      sourceFieldFile :: String -> FilePath     sourceFieldFile field =@@ -74,6 +111,11 @@         -- should be impossible         error "empty source field!"       else (takeFileName . last . words) field++    -- FIXME handle .tgz?+    isArchiveFile :: FilePath -> Bool+    isArchiveFile f =+      ".tar." `isInfixOf` f || ".zip" `isSuffixOf` f  pkgVerRel :: FilePath -> IO (String,String) pkgVerRel spec = do
src/Cmd/WaitRepo.hs view
@@ -9,6 +9,7 @@ import Koji import Package +-- FIXME first check/wait for build to actually exist waitrepoCmd :: Bool -> Maybe String -> (BranchesReq, [String]) -> IO () waitrepoCmd dryrun mtarget = do   withPackageByBranches (Just False) cleanGitFetchActive AnyNumber waitrepoBranch
src/Common.hs view
@@ -7,7 +7,8 @@ #if !MIN_VERSION_base(4,11,0)   (<>), #endif-  (+/+)+  (+/+),+  plural   ) where  import Control.Monad.Extra@@ -19,3 +20,13 @@ #endif  import Network.HTTP.Query ((+/+))++plural :: Int -> String -> String+plural i ns =+  mconcat+  [+    show i,+    " ",+    ns,+    if i == 1 then "" else "s"+  ]
src/Common/System.hs view
@@ -7,11 +7,17 @@   getDirectoryName,   isTty,   setNoBuffering,+#if !MIN_VERSION_filepath(1,4,2)+  isExtensionOf,+#endif #if !MIN_VERSION_simple_cmd(0,2,3)   cmdFull #endif   ) where +#if !MIN_VERSION_filepath(1,4,2)+import Data.List+#endif import SimpleCmd #if MIN_VERSION_simple_cmd(0,2,1)   hiding (ifM,whenM)@@ -47,4 +53,10 @@       if last str == '\n'       then init str       else str+#endif++#if !MIN_VERSION_filepath(1,4,2)+isExtensionOf :: String -> FilePath -> Bool+isExtensionOf ext@('.':_) = isSuffixOf ext . takeExtensions+isExtensionOf ext         = isSuffixOf ('.':ext) . takeExtensions #endif
src/Git.hs view
@@ -89,6 +89,7 @@  gitPushSilent :: Maybe String -> IO () gitPushSilent mref = do+  checkOnBranch   putStr "git pushing... "   out <- cmdQuiet "git" $ ["push", "--quiet", "origin"] ++ maybeToList mref   putStrLn $ if null out then "done\n" else "\n" ++ out@@ -158,13 +159,15 @@ gitLines c args = lines <$> git c args  gitSwitchBranch :: AnyBranch -> IO ()+gitSwitchBranch (OtherBranch "HEAD") = do+  dir <- getDirectoryName+  error' $ dir ++ ": HEAD is not a branch" gitSwitchBranch br = do   localbranches <- gitLines "branch" ["--format=%(refname:short)"]   if show br `elem` localbranches then do-    current <- git "rev-parse" ["--abbrev-ref", "HEAD"]-    when (current /= show br) $-      -- cmdSilent-      git_ "checkout" ["-q", show br]+    current <- gitCurrentBranch+    when (current /= br) $+      git_ "switch" ["-q", show br]     else do     -- check remote branch exists     remotebranch <-
src/InterleaveOutput.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE CPP #-}- module InterleaveOutput (cmdSilent', cmdSilentBool) where  import Data.ByteString.Lazy.UTF8 as B
src/Koji.hs view
@@ -28,11 +28,13 @@  import Control.Concurrent (threadDelay) import qualified Data.ByteString.Lazy.Char8 as B+import Data.Fixed (Micro) import Distribution.Koji import qualified Distribution.Koji.API as Koji import System.Exit import System.Process.Typed-import System.Time.Extra (sleep, timeout)+import System.Timeout (timeout)+import System.Time.Extra (sleep)  import Branches import Common@@ -93,7 +95,6 @@ kojiBuild' :: Bool -> String -> [String] -> IO KojiBuildTask kojiBuild' wait target args = do   krbTicket-  cmd_ "date" []   let srpm = if null args              then error' "no args passed to koji build"              else ".src.rpm" `isSuffixOf` last args@@ -104,16 +105,16 @@   -- [ERROR] koji: AuthError: unable to obtain a session   -- readCreateProcess: koji "build" "--nowait" "f33-build-side-25385" "--fail-fast" "--background" ... (exit 1): failed   (ret,out) <- readProcessStdout $ proc "koji" $ ["build", "--nowait", target] ++ args-  B.putStrLn $ if srpm-    -- drop uploading line until doing tee-    then (B.unlines . tail . B.lines) out-    else out+    -- for srpm: drop uploading line until doing tee+    -- for git: drop "Created task: "+    -- init to drop final newline+  logMsg $ (B.unpack . B.init . B.unlines . tail . B.lines) out   if ret == ExitSuccess then do     let kojiurl = B.unpack $ last $ B.words out         task = (TaskId . read) $ takeWhileEnd isDigit kojiurl     when wait $ do       kojiWatchTask task-      cmd_ "date" []+      cmd_ "date" ["+%T"]     return $ if wait then Right kojiurl else Left task     else do     prompt_ "Press Enter to resubmit Koji build"@@ -137,7 +138,7 @@   mst <- kojiGetTaskState fedoraHub task   case mst of     Just TaskClosed -> return ()-    Just TaskFailed -> error "Task failed!"+    Just TaskFailed -> error' "Task failed!"     Just TaskCanceled -> return ()     _ -> kojiWatchTask task @@ -151,7 +152,8 @@     Just ts ->       if ts `elem` openTaskStates       then do-        putChar '.'+        -- this makes parallel too noisy+        --putChar '.'         sleep 20         kojiWaitTask task       else return $ ts == TaskClosed@@ -188,8 +190,7 @@     waitRepo :: String -> Maybe Struct -> IO ()     waitRepo buildtag moldrepo = do       when (isJust moldrepo) $ do-        threadDelay (50 * 1000 * 1000) -- 50s-        putChar '.'+        threadDelay (fromEnum (50 :: Micro)) -- 50s       mrepo <- kojiGetRepo fedoraHub buildtag Nothing Nothing       case mrepo of         Nothing -> error' $ "failed to find koji repo for " ++ buildtag@@ -203,13 +204,13 @@               Just event -> do                 latest <- kojiLatestNVRRepo buildtag event (nameOfNVR nvr)                 if latest == Just nvr-                  then if isNothing moldrepo-                       then putStrLn $ nvr ++ " is in " ++ buildtag-                       else putStrLn "done"+                  then logMsg $ nvr +++                       if isNothing moldrepo+                       then " is in " ++ buildtag+                       else " appeared"                   else do-                  when (isNothing moldrepo) $ do-                    cmd_ "date" []-                    putStrLn $ "Waiting for " ++ buildtag ++ " to have " ++ nvr+                  when (isNothing moldrepo) $+                    logMsg $ "Waiting for " ++ buildtag ++ " to have " ++ nvr                   waitRepo buildtag mrepo  kojiTagArchs :: String -> IO [String]@@ -230,9 +231,9 @@         Just (buildtag,_desttag) -> do           kojiListSideTags fedoraKojiHub (Just buildtag) (Just user) -maybeTimeout :: Double -> IO a -> IO a+maybeTimeout :: Micro -> IO a -> IO a maybeTimeout secs act = do-  mres <- timeout secs act+  mres <- timeout (fromEnum secs) act   case mres of     Nothing -> do       warning "Connection timed out: retrying"
src/Krb.hs view
@@ -1,5 +1,6 @@ module Krb (   fasIdFromKrb,+  maybeFasIdFromKrb,   krbTicket   ) where @@ -9,7 +10,7 @@  krbTicket :: IO () krbTicket = do-  krb <- words . fromMaybe "" . find ("@FEDORAPROJECT.ORG" `isInfixOf`) . lines <$> cmd "klist" ["-l"]+  krb <- klistEntryFedora   if null krb     then error' "No krb5 ticket found for FEDORAPROJECT.ORG"     else@@ -18,9 +19,21 @@       cmd_ "fkinit" []       putStrLn "" +maybeFasIdFromKrb :: IO (Maybe String)+maybeFasIdFromKrb =+  fmap (removeSuffix "@FEDORAPROJECT.ORG") . find ("@FEDORAPROJECT.ORG" `isSuffixOf`) <$> klistEntryFedora+ fasIdFromKrb :: IO String fasIdFromKrb = do-  mfasid <- (removeSuffix "@FEDORAPROJECT.ORG" <$>) . find ("@FEDORAPROJECT.ORG" `isSuffixOf`) . words <$> cmd "klist" ["-l"]+  mfasid <- maybeFasIdFromKrb   case mfasid of     Nothing -> error' "Could not determine fasid from klist"     Just fasid -> return fasid++klistEntryFedora :: IO [String]+klistEntryFedora = do+  mres <- cmdMaybe "klist" ["-l"]+  return $+    maybe []+    (words . fromMaybe "" . find ("@FEDORAPROJECT.ORG" `isInfixOf`) . lines)+    mres
src/ListReviews.hs view
@@ -30,13 +30,14 @@ listReviewsAll :: Bool -> ReviewStatus -> IO [Bug] listReviewsAll = listReviewsFull False Nothing Nothing +-- FIXME should not require login listReviewsFull :: Bool -> Maybe String -> Maybe String -> Bool                 -> ReviewStatus-> IO [Bug] listReviewsFull assignee muser mpat allopen status = do-  (session,user) <- bzLoginSession+  let session = bzAnonSession   accountid <- do     case muser of-      Nothing -> return user+      Nothing -> getBzUser       Just userid ->         if emailIsValid userid then return $ T.pack userid         else do
src/Main.hs view
@@ -27,7 +27,8 @@ import Cmd.Override import Cmd.Parallel import Cmd.PkgReview-import Cmd.Pull+import Cmd.Prep+import Cmd.PullPush --import Cmd.Repoquery import Cmd.RequestBranch import Cmd.RequestRepo@@ -92,6 +93,7 @@     , Subcommand "parallel" "Parallel build packages in Koji" $       parallelBuildCmd       <$> dryrunOpt+      <*> optionalWith auto 'l' "skip-to-layer" "LAYERNO" "Skip the first N layers [default 0]" 0       <*> optional sidetagTargetOpt       <*> updatetypeOpt       <*> branchesPackages@@ -120,14 +122,20 @@       <*> branchesPackages     , Subcommand "update" "Update package in dist-git to newer version" $       updateCmd-      <$> maybeBranchPackages False+      <$> switchWith 's' "sources-only" "Only update sources"+      <*> switchWith 'f' "force" "Download upstream sources even if they exist locally"+      <*> switchWith 'H' "allow-head" "For updating inside rebase"+      <*> maybeBranchPackages False     , Subcommand "sort" "Sort packages in build dependency order" $       sortCmd-      <$> optional rpmWithOpt+      <$> switchWith 'p' "parallel" "Group dependent packages on separate lines"+      <*> optional rpmWithOpt       <*> maybeBranchPackages True     , Subcommand "prep" "Prep sources" $       prepCmd-      <$> maybeBranchPackages False+      <$> optional prepPreOpts+      <*> switchWith 'v' "verbose" "show rpmbuild output"+      <*> maybeBranchPackages False     , Subcommand "local" "Build locally" $       localCmd       <$> optional forceshortOpt@@ -139,12 +147,14 @@       <*> maybeBranchPackages False     , Subcommand "diff" "Diff local changes" $       diffCmd-      <$> diffSpecOnly+      <$> switchWith 'o' "spec-only" "Only diff spec file"       <*> diffWorkOpt       <*> diffFormatOpt-      <*> diffBranchOpt+      <*> switchWith 'q' "quiet" "Just output package name"+      <*> optional diffFilterOpt+      <*> optional (optionWith anyBranchM 'w' "with-branch" "BRANCH" "branch")       <*> maybeBranchPackages False-    , Subcommand "log" "Show commits between branches" $+    , Subcommand "compare" "Show commits between branches" $       logCmd       <$> switchWith 'l' "long" "show full commit log"       <*> anyBranchArg@@ -152,10 +162,10 @@       <*> manyPackages     , Subcommand "mock" "Local mock build" $       mockCmd-      <$> switchWith 'd' "dry-run" "Do not build (but creates srpm)"-      <*> switchWith 'n' "no-clean" "Do not clean chroot before building a package"+      <$> switchWith 'n' "dry-run" "Do not build (but creates srpm)"+      <*> optional nocleanOpt       <*> switchWith 'w' "network" "Use network during build"-      <*> switchWith 'N' "no-clean-after" "Don't clean  chroot after building a package"+      <*> switchWith 's' "shell" "Enter chroot shell after building"       <*> optional (optionWith branchM 'r' "root" "BRANCH" "Mock config to use")       <*> branchesPackages     , Subcommand "install-deps" "Install package build dependencies" $@@ -179,14 +189,21 @@       <*> manyPackages     , Subcommand "bump" "Bump release for package" $       bumpPkgs-      <$> optional commitOpts+      <$> switchWith 'l' "local" "Use local origin rather than checking latest koji"+      <*> optional commitOpts       <*> branchesPackages     , Subcommand "commit" "Git commit packages" $       commitPkgs       <$> optional commitOpts+      <*> switchWith '1' "first-line" "use first line of changelog"+      <*> switchWith 'u' "unstaged" "include unstaged changes"       <*> manyPackages     , Subcommand "pull" "Git pull packages" $       pullPkgs+      <$> switchWith 'l' "lenient" "Ignore non-git dirs and files"+      <*> branchesPackages+    , Subcommand "push" "Git push packages" $+      pushPkgs       <$> branchesPackages     , Subcommand "create-review" "Create a Package Review request" $       createReview@@ -240,12 +257,15 @@       <$> dryrunOpt       <*> switchWith 'l' "list-chroots" "Show project chroots"       <*> buildByOpt-      <*> many archOpt+      <*> optional archesOpt       <*> pkgArg "PROJECT"       <*> branchesPackages-    , Subcommand "rename-master" "Rename local master branch to rawhide" $+    , Subcommand "rename-rawhide" "Rename local 'master' branch to 'rawhide'" $       renameMasterCmd       <$> manyPackages+    , Subcommand "count" "Count number of living packages" $+      countCmd+      <$> maybeBranchPackages True     , Subcommand "graph" "Output dependency graph" $       graphCmd       <$> switchWith 'o' "output" "Output graph in gv/dot format"@@ -343,6 +363,11 @@             Just req | null brs -> (BranchOpt req, pkgs)                      | otherwise -> error' "cannot have branch option and branch list" +    prepPreOpts :: Parser PrepPre+    prepPreOpts =+      flagWith' PrepClone 'c' "clone" "Try to clone package repo first" <|>+      flagWith' PrepPull 'p' "pull" "Git pull before preping"+     rpmWithOpt :: Parser RpmWith     rpmWithOpt =       RpmWith <$> strOptionWith 'w' "with" "BCOND" "rpmspec --with option" <|>@@ -355,8 +380,10 @@      rebuildSrpmOpt = switchWith 's' "rebuild-srpm" "rebuild srpm in Koji" -    buildOpts = BuildOpts <$> mergeOpt <*> noFailFastOpt <*> mtargetOpt <*> overrideOpt <*> dryrunOpt <*> updatetypeOpt+    buildOpts = BuildOpts <$> mergeOpt <*> noFailFastOpt <*> mtargetOpt <*> overrideOpt <*> waitrepoOpt <*> dryrunOpt <*> updatetypeOpt <*> useChangelogOpt <*> switchWith 'p' "by-package" "Build by each package across brs" +    useChangelogOpt = switchWith 'c' "changelog-notes" "Use spec changelog for Bodhi notes"+ --    yesOpt = switchWith 'y' "yes" "Assume yes for questions"      nopromptOpt = switchWith 'm' "no-prompt" "Merge without prompt"@@ -382,8 +409,12 @@         checkNotRawhide "rawhide" = error' "'rawhide' is not a valid target!"         checkNotRawhide t = t -    overrideOpt = switchWith 'o' "override" "Create a buildroot override and wait-repo"+    overrideOpt = switchWith 'o' "override" "Create a buildroot override: implies --wait-repo" +    waitrepoOpt =+      optional (flagWith' True 'w' "waitrepo" "Waitrepo for each build" <|>+                 flagWith' False 'M' "no-waitrepo" "Do not waitrepo for each build")+     dryrunOpt = switchWith 'n' "dry-run" "Do not write (push, build, post, override)"      updatetypeOpt = flagWith' Nothing 'U' "no-update" "Do not generate a Bodhi update" <|> Just <$> optionalWith auto 'u' "update-type" "TYPE" "security, bugfix, enhancement (default), or newpackage" EnhancementUpdate@@ -396,20 +427,18 @@     diffFormatOpt =       DiffContext <$> optionWith auto 'u' "unified" "CONTEXT" "Lines of context" <|>       flagWith' DiffMinimal 'm' "minimal" "Minimize diff noise" <|>-      flagWith' DiffStats 's' "stats" "Only show diff stats" <|>-      flagWith DiffDefault DiffQuiet 'q' "quiet" "Just output package name"+      flagWith' DiffStatus 'n' "status" "Show diff --name-status" <|>+      flagWith DiffDefault DiffStats 's' "stats" "Show diff --stat" -    diffSpecOnly :: Parser Bool-    diffSpecOnly = switchWith 'o' "spec-only" "Only diff spec file"+    diffFilterOpt :: Parser DiffFilter+    diffFilterOpt =+      DiffMatch <$> strOptionWith 'f' "filter" "PATTERN" "filter diff with pattern" <|> DiffNotMatch <$> strOptionWith 'F' "filter-not" "PATTERN" "negative filter for diff with pattern"      diffWorkOpt :: Parser DiffWork     diffWorkOpt =       flagWith' DiffWorkStaged 'S' "staged" "Diff staged changes (git diff --cached)" <|>       flagWith DiffWorkAll DiffWorkUnstage 'U' "unstaged" "Diff unstaged changes (git diff) [default is 'git diff HEAD']" -    diffBranchOpt :: Parser (Maybe AnyBranch)-    diffBranchOpt = optional (optionWith anyBranchM 'w' "with-branch" "BRANCH" "branch")-     commitOpts :: Parser CommitOpt     commitOpts =       CommitMsg <$> strOptionWith 'm' "message" "COMMITMSG" "commit message" <|>@@ -424,9 +453,7 @@       Target <$> targetOpt <|>       flagWith' SideTag 's' "sidetag" "Use the existing branch side-tag to build or creates one for you (with 'fedpkg request-side-tag --base-tag')" -    packagerOpt = Owner <$> ownerOpt <|> Committer <$> usernameOpt-    usernameOpt = strOptionWith 'u' "username" "USERNAME" "Packages user can commit to"-    ownerOpt = strOptionWith 'o' "owner" "OWNER" "Package owner"+    packagerOpt = Owner <$> strOptionWith 'o' "owner" "OWNER" "Package owner" <|> Committer <$> strOptionWith 'u' "username" "USERNAME" "Packages user can commit to"      bcondOpt = BuildWith <$> strOptionWith 'w' "with" "FEATURE" "Turn on package FEATURE for build" <|>                BuildWithout <$> strOptionWith 'W' "without" "FEATURE" "Turn off package FEATURE for build"@@ -440,3 +467,9 @@     scratchOpt =       ScratchTask <$> optionWith auto 's' "scratch-build" "TASKID" "Existing scratch build taskid" <|>       flagWith ScratchBuild SkipScratch 'S' "no-scratch" "Skip scratch build"++    nocleanOpt :: Parser NoClean+    nocleanOpt =+      flagWith' NoCleanBefore 'c' "no-clean" "Do not clean chroot before building"+      <|> flagWith' NoCleanAfter 'C' "no-clean-after" "Do not clean chroot after building"+      <|> flagWith' NoCleanAll 'A' "no-clean-all" "Do not clean chroot before or after building"
src/Package.hs view
@@ -3,15 +3,17 @@ module Package (   builtRpms,   clonePkg,+  CloneUser(..),   fedpkg,   fedpkg_,   checkForSpecFile,   cleanChangelog,-  getChangeLog,-  getDirectoryName,+  changelogVersions,+  changeLogPrompt,   getPackageName,   getSummaryURL,   findSpecfile,+  maybeFindSpecfile,   localBranchSpecFile,   generateSrpm,   generateSrpm',@@ -26,17 +28,16 @@   putPkgAnyBrnchHdr,   withExistingDirectory,   initialPkgRepo,---  splitBranchesPkgs,---  withBranchByPackages,   withPackageByBranches,---  withPackageByBranches',   withPackagesMaybeBranch,+  withPackagesMaybeBranchNoHeadergit,   LimitBranches(..),   cleanGit,   cleanGitFetch,   cleanGitFetchActive,   dirtyGit,   dirtyGitFetch,+  dirtyGitHEAD,   Package(..),   packageSpec,   pkgNameVerRel,@@ -56,9 +57,11 @@ import Data.Char (isDigit) import Data.Either (partitionEithers) import Data.RPM-import Distribution.Fedora+import Distribution.Fedora hiding (Fedora,EPEL)+import Network.HTTP.Directory (Manager, httpExists, httpManager) import SimpleCmd.Rpm import System.Console.Pretty+import System.Posix.Files  import Branches import Git@@ -79,25 +82,32 @@   have <- doesFileExist spec   unless have $ error' $ spec ++ " not found" -getChangeLog :: Maybe String -> FilePath -> IO String-getChangeLog mcontext spec = do-  clog <- cleanChangelog <$> cmd "rpmspec" ["-q", "--srpm", "--qf", "%{changelogtext}", spec]+changeLogPrompt :: Maybe String -> FilePath -> IO String+changeLogPrompt mcontext spec = do+  clog <- cleanChangelog spec   putStrLn ""   putStrLn "```"   putStrLn clog   putStrLn "```"-  ifM (not <$> isTty)-    (return clog) $-    do-      userlog <- prompt $ "Press Enter to use above or input " ++ fromMaybe "change" mcontext ++ " summary now"-      return $ if null userlog then clog else userlog+  -- FIXME is this actually useful?+  tty <- isTty+  if not tty+    then return clog+    else do+    userlog <- prompt $ "Press Enter to use above or input " ++ fromMaybe "change" mcontext ++ " summary now"+    return $ if null userlog then clog else userlog -cleanChangelog :: String -> String-cleanChangelog [] = error' "empty changelog" -- should not happen-cleanChangelog cs =+changelogVersions :: FilePath -> IO [String]+changelogVersions spec = do+  ns <- cmdLines "rpmspec" ["-q", "--srpm", "--qf", "%{changelogname}", spec]+  return $ map (removePrefix "- " . dropWhile (/= '-')) ns++cleanChangelog :: FilePath -> IO String+cleanChangelog spec = do+  cs <- cmd "rpmspec" ["-q", "--srpm", "--qf", "%{changelogtext}", spec]   let ls = lines cs       no = length $ filter ("- " `isPrefixOf`) ls-  in if no == 1 then removePrefix "- " cs else cs+  return $ if no == 1 then removePrefix "- " cs else cs  getSummaryURL :: FilePath -> IO String getSummaryURL spec = do@@ -124,19 +134,18 @@   mspec <- maybeFindSpecfile   case mspec of     Just spec -> return spec-    Nothing -> error' "No spec file found"+    Nothing -> do+      dir <- getDirectoryName+      error' $ "No spec file found in: " ++ dir +-- adapted from fileWithExtension maybeFindSpecfile :: IO (Maybe FilePath)-maybeFindSpecfile = fileWithExtension ".spec"-  where-    -- looks in dir for a unique file with given extension-    fileWithExtension :: String -> IO (Maybe FilePath)-    fileWithExtension ext = do-      files <- filter (ext `isExtensionOf`) <$> listDirectory "."-      case files of-        [] -> return Nothing-        [spec] -> return $ Just spec-        _ -> error' $ "No unique " ++ ext ++ " file found"+maybeFindSpecfile = do+  files <- filter (".spec" `isExtensionOf`) <$> listDirectory "."+  case files of+    [] -> return Nothing+    [spec] -> return $ Just spec+    _ -> error' $ "More than one .spec file: " ++ unwords files  localBranchSpecFile :: Package -> AnyBranch -> IO FilePath localBranchSpecFile pkg br = do@@ -153,7 +162,7 @@           Just spc -> do             putStrLn $ "Warning: directory name differs from " ++ spc ++ "\n"             return spc-          Nothing -> error' "No spec file"+          Nothing -> error' $ "No spec file for: " ++ unPackage pkg     else findSpecfile  rpmEval :: String -> IO (Maybe String)@@ -161,6 +170,11 @@   res <- cmd "rpm" ["--eval", s]   return $ if null res || res == s then Nothing else Just res +-- rpmEval' :: String -> IO String+-- rpmEval' s = do+--   mres <- rpmEval s+--   fromMaybe (error' (show s ++ " undefined!")) mres+ generateSrpm :: Maybe AnyBranch -> FilePath -> IO FilePath generateSrpm = generateSrpm' False @@ -173,34 +187,24 @@                  dist <- getBranchDist br                  return ["--define", "dist " ++ rpmDistTag dist]   srpmfile <- cmd "rpmspec" $ ["-q", "--srpm"] ++ distopt ++ ["--qf", "%{name}-%{version}-%{release}.src.rpm", spec]-  srcrpmdir <--    ifM isPkgGitRepo-      (return ".") $-      rpmEval "%{_srcrpmdir}" >>= maybe (error' "%_srcrpmdir undefined!") return-  let srpm = srcrpmdir </> srpmfile-      srpmdiropt = if null srcrpmdir then []-                   else ["--define", "_srcrpmdir " ++ srcrpmdir]-  sourcedir <--    ifM isPkgGitRepo-      (return ".") $-      rpmEval "%{_sourcedir}" >>= maybe (error' "%_sourcedir undefined!") return-  let sourcediropt = if null sourcedir then []-                     else ["--define", "_sourcedir " ++ sourcedir]+  cwd <- getCurrentDirectory+  let srpmdiropt = ["--define", "_srcrpmdir " ++ cwd]+      sourcediropt = ["--define", "_sourcedir " ++ cwd]   if force then     buildSrpm (distopt ++ srpmdiropt ++ sourcediropt)     else do-    exists <- doesFileExist srpm+    exists <- doesFileExist srpmfile     if not exists       then buildSrpm (distopt ++ srpmdiropt ++ sourcediropt)       else do-      srpmTime <- getModificationTime srpm+      srpmTime <- getModificationTime srpmfile       fileTimes <- mapM getModificationTime (spec:srcs)       if any (srpmTime <) fileTimes         then buildSrpm (distopt ++ srpmdiropt ++ sourcediropt)         else do         -- pretty print with ~/-        putStrLn $ srpm ++ " is up to date"-        return srpm+        putStrLn $ srpmfile ++ " is up to date"+        return srpmfile   where     buildSrpm opts = do       srpm <- last . words <$> cmd "rpmbuild" (opts ++ ["-bs", spec])@@ -244,7 +248,8 @@         rpmdirs =           [ "--define="++ mcr +-+ cwd | gitDir,             mcr <- ["_builddir", "_rpmdir", "_srcrpmdir", "_sourcedir"]]-        args = rpmdirs ++ ["--define", "dist " ++ rpmDistTag dist] ++ buildopt ++ map show bconds ++ [spec]+        args = rpmdirs ++ ["--define", "dist " ++ rpmDistTag dist] +++               buildopt ++ map show bconds ++ [spec]     ok <-       if not quiet || shortcircuit       then do@@ -266,8 +271,8 @@ installDeps strict spec = do   missingdeps <- nub <$> (buildRequires spec >>= filterM notInstalled)   unless (null missingdeps) $ do-    putStrLn $ "Running dnf builddep " ++ unwords missingdeps-    cmd_ "/usr/bin/sudo" $ "/usr/bin/dnf":"--quiet":"builddep": ["--skip-unavailable" | not strict] ++ ["--assumeyes", spec]+    putStrLn $ "Running 'dnf install' " ++ unwords missingdeps+    cmd_ "/usr/bin/sudo" $ "/usr/bin/dnf":"install": ["--skip-broken" | not strict] ++ ["--assumeyes"] ++ missingdeps  checkSourcesMatch :: FilePath -> IO () checkSourcesMatch spec = do@@ -275,41 +280,81 @@   sourcefiles <- map (takeFileName . last . words) <$> cmdLines "spectool" [spec]   sources <- lines <$> readFile "sources"   gitfiles <- gitLines "ls-files" []-  forM_ sourcefiles $ \ src ->-    unless (isJust (find (src `isInfixOf`) sources) || src `elem` gitfiles) $ do-    prompt_ $ color Red $ src ++ " not in sources, please fix"+  let missing = filter (\src -> isNothing (find (src `isInfixOf`) sources) &&+                                src `notElem` gitfiles)+                sourcefiles+  unless (null missing) $ do+    prompt_ $ color Red $ unwords missing ++ " not in sources, please fix"+    checkOnBranch     checkSourcesMatch spec+  mgr <- httpManager+  let pkg = takeBaseName spec+  mapM_ (checkLookasideCache mgr pkg) sources+  where+    checkLookasideCache :: Manager -> String -> String -> IO ()+    checkLookasideCache mgr pkg source = do+      case words source of+        ("SHA512":('(':fileparen):"=":[hash]) -> do+          let file = dropSuffix ")" fileparen+              url = "https://src.fedoraproject.org/lookaside/pkgs" +/+ pkg +/+ file +/+ "sha512" +/+ hash +/+ file+          unlessM (httpExists mgr url) $ do+            putStrLn $ url ++ " not found"+            putStrLn $ "uploading " ++ file ++ " to lookaside source repo"+            fedpkg_ "upload" [file]+        _ -> error' $ "invalid/unknown source:\n" ++ source  getSources :: FilePath -> IO [FilePath] getSources spec = do   gitDir <- isGitRepo-  srcdir <- getSourceDir gitDir+  cwd <- getCurrentDirectory+  -- FIXME fallback to ~/rpmbuild/SOURCES?+  msrcdir <- do+    msourcedir <- rpmEval "%{_sourcedir}"+    case msourcedir of+      Nothing -> return Nothing+      Just srcdir ->+        if msourcedir == Just cwd+        then return Nothing+        else do+          dir <- doesDirectoryExist srcdir+          if dir+            then return msourcedir+            else return Nothing   (patches,srcs) <- partitionEithers . map sourceFieldFile                     <$> cmdLines "spectool" ["-a", spec]-  unless gitDir $-    unlessM (doesDirectoryExist srcdir) $-    createDirectoryIfMissing True srcdir-  forM_ srcs $ \ src ->-    unlessM (doesFileExist (srcdir </> src)) $ do-    uploaded <--      if gitDir then do-        have_sources <- doesFileExist "sources"-        if have_sources then-          grep_ src "sources"+  forM_ srcs $ \ src -> do+    exists <- doesFileExist src &&^ checkCompression src+    inSrcdir <- doesSourceDirFileExist msrcdir src+    unless exists $ do+      if inSrcdir+        then maybeSourceDir createLink msrcdir src+        else do+        uploaded <-+          if gitDir then do+            have_sources <- doesFileExist "sources"+            if have_sources then+              grep_ src "sources"+              else return False           else return False-      else return False-    mfedpkg <- findExecutable "fedpkg"-    if uploaded && isJust mfedpkg-      then cmd_ "fedpkg" ["sources"]-      else do-      cmd_ "spectool" ["-g", "-S", "-C", srcdir, spec]-      unlessM (doesFileExist (srcdir </> src)) $-        error' $ "download failed: " ++ src+        mfedpkg <- findExecutable "fedpkg"+        if uploaded && isJust mfedpkg+          then cmd_ "fedpkg" ["sources"]+          else do+          cmd_ "spectool" ["-g", "-S", spec]+          unlessM (doesFileExist src) $+            error' $ "download failed: " ++ src+    unless inSrcdir $+      whenJust msrcdir $ \srcdir ->+      createLink src (srcdir </> src)   forM_ patches $ \patch ->-    unlessM (doesFileExist (srcdir </> patch)) $ do-    cmd_ "spectool" ["-g", "-P", "-C", srcdir, spec]-    unlessM (doesFileExist (srcdir </> patch)) $-      error' $ "missing patch: " ++ patch+    unlessM (doesFileExist patch) $ do+    inSrcdir <- doesSourceDirFileExist msrcdir patch+    if inSrcdir+      then maybeSourceDir copyFile msrcdir patch+      else do+      cmd_ "spectool" ["-g", "-P", spec]+      unlessM (doesFileExist patch) $+        error' $ "missing patch: " ++ patch   return $ srcs ++ patches   where     sourceFieldFile :: String -> Either FilePath FilePath@@ -324,12 +369,32 @@              _ -> error' $! "illegal field: " ++ f)           $ takeFileName v -    getSourceDir :: Bool -> IO FilePath-    getSourceDir gitDir =-      if gitDir-        then getCurrentDirectory-        else fromJust <$> rpmEval "%{_sourcedir}"+    checkCompression :: FilePath -> IO Bool+    checkCompression file =+      case+        case takeExtension file of+          ".gz" -> Just "gzip"+          ".tgz" -> Just "gzip"+          ".bz2" -> Just "bzip2"+          ".xz" -> Just "xz"+          ".lz" -> Just "lzip"+          ".zstd" -> Just "zstd"+          _ -> Nothing+      of+        Just prog -> cmdBool prog ["-t", file]+        Nothing -> return True +    maybeSourceDir :: (FilePath -> FilePath -> IO ())+                   -> Maybe FilePath -> FilePath -> IO ()+    maybeSourceDir act mdir file =+      whenJust mdir $ \dir ->+      act (dir </> file) file++    doesSourceDirFileExist :: Maybe FilePath -> FilePath -> IO Bool+    doesSourceDirFileExist Nothing _ = return False+    doesSourceDirFileExist (Just srcdir) file =+      doesFileExist (srcdir </> file)+ withExistingDirectory :: FilePath -> IO a -> IO a withExistingDirectory dir act =   ifM (doesDirectoryExist dir)@@ -426,41 +491,21 @@   { gitOptClean :: Bool   , gitOptFetch :: Bool   , gitOptActive :: Bool+  , gitOptHEAD :: Bool -- allow detached head/rebase state   } -cleanGit, cleanGitFetch, cleanGitFetchActive, dirtyGit, dirtyGitFetch :: Maybe GitOpts---                                   clean fetch active-cleanGit =            Just $ GitOpts True  False False-cleanGitFetch =       Just $ GitOpts True  True  False-cleanGitFetchActive = Just $ GitOpts True  True  True-dirtyGit =            Just $ GitOpts False False False-dirtyGitFetch =       Just $ GitOpts False True  False+cleanGit, cleanGitFetch, cleanGitFetchActive, dirtyGit, dirtyGitFetch, dirtyGitHEAD :: Maybe GitOpts+--                                   clean fetch active HEAD+cleanGit =            Just $ GitOpts True  False False  False+cleanGitFetch =       Just $ GitOpts True  True  False  False+cleanGitFetchActive = Just $ GitOpts True  True  True   False+dirtyGit =            Just $ GitOpts False False False  False+dirtyGitFetch =       Just $ GitOpts False True  False  False+dirtyGitHEAD =        Just $ GitOpts False False False  True  data LimitBranches = AnyNumber | Zero | ZeroOrOne | ExactlyOne   deriving Eq --- do package over branches--- withPackageByBranches :: Maybe Bool---                       -> Maybe GitOpts---                       -> Maybe BranchOpts---                       -> Bool---                       -> LimitBranches---                       -> (Package -> AnyBranch -> IO ())---                       -> [String]---                       -> IO ()--- withPackageByBranches mheader mgitopts mbrnchopts exists limitBranches action args = do---   (brs,pkgs) <- splitBranchesPkgs (have gitOptActive) mbrnchopts exists args---   let mheader' =---         case mheader of---           Nothing -> Nothing---           Just _ | length pkgs < 2 && length brs < 2 && isNothing mbrnchopts -> Nothing---           _ -> mheader---   withPackageByBranches' mheader' mgitopts mbrnchopts limitBranches action (brs,pkgs)---   where---     have :: (GitOpts -> Bool) -> Bool---     have opt = maybe False opt mgitopts-- -- FIXME rename to withPackages* -- FIXME countdown packages withPackageByBranches :: Maybe Bool@@ -504,9 +549,18 @@         haveGit <- isPkgGitRepo         when (isJust mgitopts && not haveGit) $           error' $ "Not a pkg git dir: " ++ unPackage pkg-        mcurrentbranch <- if haveGit then Just <$> gitCurrentBranch-                          else return Nothing-        brs <- listOfAnyBranches haveGit (have gitOptActive) breq+        mcurrentbranch <-+          if haveGit+          then+            if have gitOptHEAD+            then do+              cur <- gitCurrentBranch'+              if cur == OtherBranch "HEAD"+                then warning "detached HEAD" >> return Nothing+                else return $ Just cur+            else Just <$> gitCurrentBranch+          else return Nothing+        brs <- listOfAnyBranches (haveGit && not (have gitOptHEAD)) (have gitOptActive) breq         case limitBranches of           ZeroOrOne | length brs > 1 ->             -- FIXME: could be handled better (testcase: run long list of packages in wrong directory)@@ -523,9 +577,9 @@             _ -> when (fetch || isJust mheader) $ putPkgHdr pkg         when haveGit $           when (have gitOptClean) checkWorkingDirClean-        when fetch $ gitFetchSilent >> putStrLn ""+        when fetch gitFetchSilent         -- FIXME!! no branch restriction-        when (breq == BranchOpt AllBranches) $+        when (breq `elem` map BranchOpt [AllBranches,AllFedora,AllEPEL]) $           putStrLn $ "Branches: " ++ unwords (map show brs) ++ "\n"         -- FIXME add newline at end?         let action' p b = do@@ -547,41 +601,51 @@ withPackagesMaybeBranch mheader mgitopts limitBranches action (mbr, pkgs) =   withPackageByBranches mheader mgitopts limitBranches action (Branches (maybeToList mbr),pkgs) --- -- do branch over packages--- withBranchByPackages :: (Branch -> [String] -> IO ()) -> (Branches,[String]) -> IO ()--- withBranchByPackages action (brs,pkgs) = do---   when (null brs) $---     error' "Please specify at least one branch"---   when (null pkgs) $---     error' "Please give at least one package"---   forM_ brs $ \ br ->---     -- forM_ (map packagePath pkgs) $ \ (dir,pkg) ->---     -- withExistingDirectory dir $ do---     -- void $ setupGit False pkg True---     action br pkgs+withPackagesMaybeBranchNoHeadergit :: LimitBranches+                                       -> (Package -> AnyBranch -> IO ())+                                       -> (Maybe Branch,[String])+                                       -> IO ()+withPackagesMaybeBranchNoHeadergit =+  withPackagesMaybeBranch Nothing Nothing -clonePkg :: Bool -> Maybe Branch -> String -> IO ()-clonePkg quiet mbr pkg =-  ifM (doesDirectoryExist pkg)-    {-then-} (putStrLn $ pkg ++ "/ already exists") $-    {-else-} do-      let mbranch = case mbr of-            Nothing -> []-            Just br -> ["--branch", show br]-      fasid <- fasIdFromKrb-      putStr $-        if quiet-        then "cloning..."-        else "Cloning: " ++ pkg-      git_ "clone" $ ["--quiet"] ++ mbranch ++ ["ssh://" ++ fasid ++ "@pkgs.fedoraproject.org/rpms/" ++ pkg]-      putStrLn ""+data CloneUser = AnonClone | UserClone +clonePkg :: Bool -> CloneUser -> Maybe Branch -> String -> IO ()+clonePkg quiet cloneuser mbr pkg = do+  exists <- doesDirectoryExist pkg+  if exists+    then putStrLn $ pkg ++ "/ already exists"+    else do+    let mbranch = case mbr of+          Nothing -> []+          Just br -> ["--branch", show br]+    case cloneuser of+      AnonClone -> do+        msgout+        git_ "clone" $ ["--quiet"] ++ mbranch ++ ["https://src.fedoraproject.org/rpms/" ++ pkg <.> "git"]+      UserClone -> do+        fasid <- fasIdFromKrb+        msgout+        git_ "clone" $ ["--quiet"] ++ mbranch ++ ["ssh://" ++ fasid ++ "@pkgs.fedoraproject.org/rpms/" ++ pkg <.> "git"]+    putStrLn ""+  where+    msgout =+      putStr $ if quiet then "cloning..." else "Cloning: " ++ pkg+ pkgNameVerRel :: Branch -> FilePath -> IO (Maybe String) pkgNameVerRel br spec = do-  dist <- branchDist br+  disttag <- rpmDistTag <$> branchDist br   -- workaround dist with bootstrap   hostdist <- cmd "rpm" ["--eval", "%{dist}"]-  fmap (replace hostdist (rpmDistTag dist)) . listToMaybe <$> rpmspec ["--srpm"] (Just "%{name}-%{version}-%{release}") spec+  -- FIXME more precise regexp with "Release:"+  autorelease <- grep_ " %autorelease" spec+  fmap (replace hostdist disttag) . listToMaybe <$>+    if autorelease+    then do+      -- FIXME use  ?+      autorel <- last . words <$> cmd "rpmautospec" ["calculate-release", spec]+      rpmspec ["--srpm"] (Just ("%{name}-%{version}-" ++ autorel ++ disttag)) spec+    else rpmspec ["--srpm"] (Just "%{name}-%{version}-%{release}") spec  pkgNameVerRel' :: Branch -> FilePath -> IO String pkgNameVerRel' br spec = do@@ -593,7 +657,12 @@ builtRpms :: AnyBranch -> FilePath -> IO [FilePath] builtRpms br spec = do   dist <- getBranchDist br-  rpms <- rpmspec ["--builtrpms", "--define", "dist " ++ rpmDistTag dist] (Just "%{arch}/%{name}-%{version}-%{release}.%{arch}.rpm") spec+  rpmdir <- do+    pkggit <- isPkgGitRepo+    if pkggit+    then return ""+    else fromMaybe "" <$> rpmEval "%{_rpmdir}"+  rpms <- rpmspec ["--builtrpms", "--define", "dist " ++ rpmDistTag dist] (Just (rpmdir </>  "%{arch}/%{name}-%{version}-%{release}.%{arch}.rpm")) spec   if null rpms     then error' $ spec ++ " does not seem to create any rpms"     else return rpms@@ -604,9 +673,24 @@  -- from fedora-haskell-tools buildRequires :: FilePath -> IO [String]-buildRequires spec =-  -- FIXME should resolve meta-  map (head . words) <$> rpmspec ["--buildrequires"] Nothing spec+buildRequires spec = do+  dynbr <- grep_ "^%generate_buildrequires" spec+  mapMaybe primary <$>+    if dynbr+    then do+      out <- cmdIgnoreErr "rpmbuild" ["-br", "--nodeps", spec] ""+      -- Wrote: /current/dir/SRPMS/name-version-release.buildreqs.nosrc.rpm+      cmdLines "rpm" ["-qp", "--requires", last (words out)]+    else+      -- FIXME should resolve meta+      rpmspec ["--buildrequires"] Nothing spec+  where+    primary dep =+      case (head . words) dep of+        '(':rest -> Just rest+        d -> if "rpmlib(" `isPrefixOf` d+             then Nothing+             else Just d  notInstalled :: String -> IO Bool notInstalled pkg =@@ -620,9 +704,20 @@ pkgInstalled pkg =   cmdBool "rpm" ["--quiet", "-q", pkg] -repoquery :: Branch -> [String] -> IO String-repoquery br args =-  cmd "dnf" (["repoquery", "--quiet", "--releasever=" ++ branchVersion br] ++ args)+repoquery :: Branch -> Branch -> [String] -> IO String+repoquery sysbr br args = do+  let brOpts =+        if sysbr == br+        then []+        else+          case br of+            Rawhide -> ["--disablerepo=*", "--enablerepo=rawhide"]+            Fedora _ -> ["--disablerepo=*", "--enablerepo=fedora",+                         "--enablerepo=updates",+                         "--releasever=" ++ branchVersion br]+            EPEL _ -> ["--disablerepo=*", "--enablerepo=epel",+                         "--releasever=" ++ branchVersion br]+  cmd "dnf" (["repoquery", "--quiet"] ++ brOpts ++ args)  -- FIXME should be more strict about dist tag (eg .fcNN only) equivNVR :: String -> String -> Bool@@ -646,12 +741,6 @@ nameOfNVR = removeSeg . removeSeg   where     removeSeg = init . dropWhileEnd (/= '-')--#if !MIN_VERSION_filepath(1,4,2)-isExtensionOf :: String -> FilePath -> Bool-isExtensionOf ext@('.':_) = isSuffixOf ext . takeExtensions-isExtensionOf ext         = isSuffixOf ('.':ext) . takeExtensions-#endif  -- FIXME: drop when rpm-nvr has nvrVerRel showNVRVerRel :: NVR -> String
src/Prompt.hs view
@@ -33,9 +33,10 @@       then return $ Just (Just ref)       else refPrompt commits txt +-- FIXME also include branch conflictPrompt :: [String] -> String -> IO (Maybe String) conflictPrompt commits txt = do-  let commitrefs = tail $ map (head . words) commits+  let commitrefs = map (head . words) commits   ref <- prompt txt   if null ref then return Nothing     else if ref `elem` commitrefs
+ src/Types.hs view
@@ -0,0 +1,6 @@+module Types (+  Archs(..)+  )+where++data Archs = Archs [String] | ExcludedArchs [String]