├── LICENSE ├── README.md ├── apt.go ├── apt_test.go ├── repos.go ├── repos_test.go └── testdata ├── TestParseAPTConfigFolder.json ├── apt ├── sources.list └── sources.list.d │ ├── docker.list │ ├── google-chrome.list │ ├── js-reynaud-ubuntu-kicad-4-xenial.list │ ├── kdenlive-ubuntu-kdenlive-stable-xenial.list │ ├── kivy-team-kivy-saucy.list │ ├── mixxx-ubuntu-mixxx-xenial.list │ ├── oab.list │ ├── private-ppa.launchpad.net_commercial-ppa-uploaders_portal-slingshot_ubuntu.list │ ├── rethinkdb.list │ ├── skype-stable.list │ ├── virtualbox.list │ ├── vscode.list │ └── webupd8team-ubuntu-java-zesty.list ├── apt2 └── sources.list ├── dpkg-query-output-1-result.json └── dpkg-query-output-1.txt /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang apt client 2 | 3 | This is a golang client library for Debian APT Package Manager (`dpkg` and `apt`). 4 | 5 | ## License 6 | 7 | Copyright (C) 2017 Arduino AG (http://www.arduino.cc/) 8 | 9 | Licensed under the Apache License, Version 2.0 (the "License"); 10 | you may not use this file except in compliance with the License. 11 | You may obtain a copy of the License at 12 | 13 | http://www.apache.org/licenses/LICENSE-2.0 14 | 15 | Unless required by applicable law or agreed to in writing, software 16 | distributed under the License is distributed on an "AS IS" BASIS, 17 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | See the License for the specific language governing permissions and 19 | limitations under the License. 20 | 21 | -------------------------------------------------------------------------------- /apt.go: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of go-apt-client library 3 | // 4 | // Copyright (C) 2017 Arduino AG (http://www.arduino.cc/) 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | 19 | package apt 20 | 21 | import ( 22 | "bufio" 23 | "bytes" 24 | "fmt" 25 | "os/exec" 26 | "regexp" 27 | "strconv" 28 | "strings" 29 | ) 30 | 31 | // Package is a package available in the APT system 32 | type Package struct { 33 | Name string 34 | Status string 35 | Architecture string 36 | Version string 37 | ShortDescription string 38 | InstalledSizeKB int 39 | } 40 | 41 | // List returns a list of packages available in the system with their 42 | // respective status. 43 | func List() ([]*Package, error) { 44 | return Search("*") 45 | } 46 | 47 | // Search list packages available in the system that match the search 48 | // pattern 49 | func Search(pattern string) ([]*Package, error) { 50 | cmd := exec.Command("dpkg-query", "-W", "-f=${Package}\t${Architecture}\t${db:Status-Status}\t${Version}\t${Installed-Size}\t${Binary:summary}\n", pattern) 51 | 52 | out, err := cmd.CombinedOutput() 53 | if err != nil { 54 | // Avoid returning an error if the list is empty 55 | if bytes.Contains(out, []byte("no packages found matching")) { 56 | return []*Package{}, nil 57 | } 58 | return nil, fmt.Errorf("running dpkg-query: %s - %s", err, out) 59 | } 60 | 61 | return parseDpkgQueryOutput(out), nil 62 | } 63 | 64 | func parseDpkgQueryOutput(out []byte) []*Package { 65 | res := []*Package{} 66 | scanner := bufio.NewScanner(bytes.NewReader(out)) 67 | for scanner.Scan() { 68 | data := strings.Split(scanner.Text(), "\t") 69 | size, err := strconv.Atoi(data[4]) 70 | if err != nil { 71 | // Ignore error 72 | size = 0 73 | } 74 | res = append(res, &Package{ 75 | Name: data[0], 76 | Architecture: data[1], 77 | Status: data[2], 78 | Version: data[3], 79 | InstalledSizeKB: size, 80 | ShortDescription: data[5], 81 | }) 82 | } 83 | return res 84 | } 85 | 86 | // CheckForUpdates runs an apt update to retrieve new packages available 87 | // from the repositories 88 | func CheckForUpdates() (output []byte, err error) { 89 | cmd := exec.Command("apt-get", "update", "-q") 90 | return cmd.CombinedOutput() 91 | } 92 | 93 | // ListUpgradable return all the upgradable packages and the version that 94 | // is going to be installed if an UpgradeAll is performed 95 | func ListUpgradable() ([]*Package, error) { 96 | cmd := exec.Command("apt", "list", "--upgradable") 97 | out, err := cmd.Output() 98 | if err != nil { 99 | return nil, fmt.Errorf("running apt list: %s", err) 100 | } 101 | re := regexp.MustCompile(`^([^ ]+) ([^ ]+) ([^ ]+)( \[upgradable from: [^\[\]]*\])?`) 102 | 103 | res := []*Package{} 104 | scanner := bufio.NewScanner(bytes.NewReader(out)) 105 | for scanner.Scan() { 106 | matches := re.FindAllStringSubmatch(scanner.Text(), -1) 107 | if len(matches) == 0 { 108 | continue 109 | } 110 | 111 | // Remove repository information in name 112 | // example: "libgweather-common/zesty-updates,zesty-updates" 113 | // -> "libgweather-common" 114 | name := strings.Split(matches[0][1], "/")[0] 115 | 116 | res = append(res, &Package{ 117 | Name: name, 118 | Status: "upgradable", 119 | Version: matches[0][2], 120 | Architecture: matches[0][3], 121 | }) 122 | } 123 | return res, nil 124 | } 125 | 126 | // Upgrade runs the upgrade for a set of packages 127 | func Upgrade(packs ...*Package) (output []byte, err error) { 128 | args := []string{"upgrade", "-y"} 129 | for _, pack := range packs { 130 | if pack == nil || pack.Name == "" { 131 | return nil, fmt.Errorf("apt.Upgrade: Invalid package with empty Name") 132 | } 133 | args = append(args, pack.Name) 134 | } 135 | cmd := exec.Command("apt-get", args...) 136 | return cmd.CombinedOutput() 137 | } 138 | 139 | // UpgradeAll upgrade all upgradable packages 140 | func UpgradeAll() (output []byte, err error) { 141 | cmd := exec.Command("apt-get", "upgrade", "-y") 142 | return cmd.CombinedOutput() 143 | } 144 | 145 | // DistUpgrade upgrades all upgradable packages, it may remove older versions to install newer ones. 146 | func DistUpgrade() (output []byte, err error) { 147 | cmd := exec.Command("apt-get", "dist-upgrade", "-y") 148 | return cmd.CombinedOutput() 149 | } 150 | 151 | // Remove removes a set of packages 152 | func Remove(packs ...*Package) (output []byte, err error) { 153 | args := []string{"remove", "-y"} 154 | for _, pack := range packs { 155 | if pack == nil || pack.Name == "" { 156 | return nil, fmt.Errorf("apt.Remove: Invalid package with empty Name") 157 | } 158 | args = append(args, pack.Name) 159 | } 160 | cmd := exec.Command("apt-get", args...) 161 | return cmd.CombinedOutput() 162 | } 163 | 164 | // Install installs a set of packages 165 | func Install(packs ...*Package) (output []byte, err error) { 166 | args := []string{"install", "-y"} 167 | for _, pack := range packs { 168 | if pack == nil || pack.Name == "" { 169 | return nil, fmt.Errorf("apt.Install: Invalid package with empty Name") 170 | } 171 | args = append(args, pack.Name) 172 | } 173 | cmd := exec.Command("apt-get", args...) 174 | return cmd.CombinedOutput() 175 | } 176 | -------------------------------------------------------------------------------- /apt_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of go-apt-client library 3 | // 4 | // Copyright (C) 2017 Arduino AG (http://www.arduino.cc/) 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | 19 | package apt 20 | 21 | import ( 22 | "encoding/json" 23 | "fmt" 24 | "io/ioutil" 25 | "testing" 26 | 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | func TestList(t *testing.T) { 31 | out, err := ioutil.ReadFile("testdata/dpkg-query-output-1.txt") 32 | require.NoError(t, err, "Reading test input data") 33 | list := parseDpkgQueryOutput(out) 34 | 35 | // Check list with expected output 36 | data, err := ioutil.ReadFile("testdata/dpkg-query-output-1-result.json") 37 | require.NoError(t, err, "Reading test result data") 38 | var expected []*Package 39 | err = json.Unmarshal(data, &expected) 40 | require.NoError(t, err, "Unmarshaling test result data") 41 | require.Equal(t, len(expected), len(list), "Length of result") 42 | for i := range expected { 43 | require.Equal(t, expected[i], list[i], "Element", i, "of the result") 44 | } 45 | } 46 | 47 | func TestSearch(t *testing.T) { 48 | list, err := Search("nonexisting") 49 | require.NoError(t, err, "running Search command") 50 | require.Empty(t, list, "Search command result") 51 | 52 | list, err = Search("header") 53 | require.NoError(t, err, "running Search command") 54 | require.NotEmpty(t, list, "Search command result") 55 | } 56 | 57 | func TestListUpgradable(t *testing.T) { 58 | list, err := ListUpgradable() 59 | for _, p := range list { 60 | fmt.Printf("%+v\n", p) 61 | } 62 | require.NoError(t, err, "running List command") 63 | } 64 | 65 | func TestCheckForUpdates(t *testing.T) { 66 | out, err := CheckForUpdates() 67 | require.NoError(t, err, "running CheckForUpdate command") 68 | fmt.Printf(">>>\n%s\n<<<\n", string(out)) 69 | fmt.Println("ERR:", err) 70 | } 71 | -------------------------------------------------------------------------------- /repos.go: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of go-apt-client library 3 | // 4 | // Copyright (C) 2017 Arduino AG (http://www.arduino.cc/) 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | 19 | package apt 20 | 21 | import ( 22 | "bufio" 23 | "bytes" 24 | "fmt" 25 | "io/ioutil" 26 | "os" 27 | "path/filepath" 28 | "regexp" 29 | "strings" 30 | ) 31 | 32 | // RepositoryList is an array of Repository definitions 33 | type RepositoryList []*Repository 34 | 35 | // Contains checks if a repository definition is contained 36 | // in the RepositoryList 37 | func (r RepositoryList) Contains(repo *Repository) bool { 38 | return r.Find(repo) != nil 39 | } 40 | 41 | // Find search in the RepositoryList a repo that has the same 42 | // metadata as the one passed as parameter 43 | func (r RepositoryList) Find(repoToFind *Repository) *Repository { 44 | for _, repo := range r { 45 | if repoToFind.Equals(repo) { 46 | return repo 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | // Repository contains metadata about a repository installed in the system 53 | type Repository struct { 54 | Enabled bool 55 | SourceRepo bool 56 | Options string 57 | URI string 58 | Distribution string 59 | Components string 60 | Comment string 61 | 62 | configFile string 63 | } 64 | 65 | // Equals check if the Repository metadata are equivalent to the 66 | // one provided as parameter. Two Repository are equivalent if all 67 | // metadata matches with the exception of Enabled and Comment. 68 | func (r *Repository) Equals(repo *Repository) bool { 69 | if r.Components != repo.Components { 70 | return false 71 | } 72 | if r.Distribution != repo.Distribution { 73 | return false 74 | } 75 | if r.URI != repo.URI { 76 | return false 77 | } 78 | if r.SourceRepo != repo.SourceRepo { 79 | return false 80 | } 81 | if r.Options != repo.Options { 82 | return false 83 | } 84 | return true 85 | } 86 | 87 | // APTConfigLine returns the "deb" or "deb-src" config line to put in 88 | // source.list to install the Repository 89 | func (r *Repository) APTConfigLine() string { 90 | res := "" 91 | if !r.Enabled { 92 | res = "# " 93 | } 94 | if r.SourceRepo { 95 | res += "deb-src " 96 | } else { 97 | res += "deb " 98 | } 99 | if strings.TrimSpace(r.Options) != "" { 100 | res += "[" + r.Options + "]" 101 | } 102 | res += r.URI + " " + r.Distribution + " " + r.Components 103 | if strings.TrimSpace(r.Comment) != "" { 104 | res += " # " + r.Comment 105 | } 106 | return res 107 | } 108 | 109 | var aptConfigLineRegexp = regexp.MustCompile(`^(# )?(deb|deb-src)(?: \[(.*)\])? ([^ ]+) ([^ ]+) ([^#\n]+)(?: +# *(.*))?$`) 110 | 111 | func parseAPTConfigLine(line string) *Repository { 112 | match := aptConfigLineRegexp.FindAllStringSubmatch(line, -1) 113 | if len(match) == 0 || len(match[0]) < 6 { 114 | return nil 115 | } 116 | fields := match[0] 117 | //fmt.Printf("%+v\n", fields) 118 | return &Repository{ 119 | Enabled: fields[1] != "# ", 120 | SourceRepo: fields[2] == "deb-src", 121 | Options: fields[3], 122 | URI: fields[4], 123 | Distribution: fields[5], 124 | Components: fields[6], 125 | Comment: fields[7], 126 | } 127 | } 128 | 129 | func parseAPTConfigFile(configPath string) (RepositoryList, error) { 130 | data, err := ioutil.ReadFile(configPath) 131 | if err != nil { 132 | return nil, fmt.Errorf("Reading %s: %s", configPath, err) 133 | } 134 | scanner := bufio.NewScanner(bytes.NewReader(data)) 135 | 136 | res := RepositoryList{} 137 | for scanner.Scan() { 138 | line := scanner.Text() 139 | repo := parseAPTConfigLine(line) 140 | //fmt.Printf("%+v\n", repo) 141 | if repo != nil { 142 | repo.configFile = configPath 143 | res = append(res, repo) 144 | } 145 | } 146 | return res, nil 147 | } 148 | 149 | // ParseAPTConfigFolder scans an APT config folder (usually /etc/apt) to 150 | // get information about all configured repositories, it scans also 151 | // "source.list.d" subfolder to find all the "*.list" files. 152 | func ParseAPTConfigFolder(folderPath string) (RepositoryList, error) { 153 | sources := []string{filepath.Join(folderPath, "sources.list")} 154 | 155 | sourcesFolder := filepath.Join(folderPath, "sources.list.d") 156 | list, err := ioutil.ReadDir(sourcesFolder) 157 | if err != nil { 158 | return nil, fmt.Errorf("Reading %s folder: %s", sourcesFolder, err) 159 | } 160 | for _, l := range list { 161 | if strings.HasSuffix(l.Name(), ".list") { 162 | sources = append(sources, filepath.Join(sourcesFolder, l.Name())) 163 | } 164 | } 165 | 166 | res := RepositoryList{} 167 | for _, source := range sources { 168 | repos, err := parseAPTConfigFile(source) 169 | if err != nil { 170 | return nil, fmt.Errorf("Parsing %s: %s", source, err) 171 | } 172 | res = append(res, repos...) 173 | } 174 | return res, nil 175 | } 176 | 177 | // AddRepository adds the specified repository by changing the specified APT 178 | // config folder (usually /etc/apt). The new repository is saved into 179 | // a file named "managed.list" 180 | func AddRepository(repo *Repository, configFolderPath string) error { 181 | repos, err := ParseAPTConfigFolder(configFolderPath) 182 | if err != nil { 183 | return fmt.Errorf("parsing APT config: %s", err) 184 | } 185 | if repos.Contains(repo) { 186 | return fmt.Errorf("The repository is already configured") 187 | } 188 | 189 | // Add to the "managed.list" file 190 | managedPath := filepath.Join(configFolderPath, "sources.list.d", "managed.list") 191 | f, err := os.OpenFile(managedPath, os.O_APPEND|os.O_WRONLY, 0644) 192 | if os.IsNotExist(err) { 193 | f, err = os.OpenFile(managedPath, os.O_CREATE|os.O_WRONLY, 0644) 194 | } 195 | if err != nil { 196 | return fmt.Errorf("Opening %s: %s", managedPath, err) 197 | } 198 | defer f.Close() 199 | if _, err = f.WriteString(repo.APTConfigLine() + "\n"); err != nil { 200 | return fmt.Errorf("Writing repo data to config file %s: %s", managedPath, err) 201 | } 202 | return nil 203 | } 204 | 205 | // RemoveRepository removes a repository from the repository list files 206 | // found in the specified APT config folder (usually /etc/apt) 207 | func RemoveRepository(repo *Repository, configFolderPath string) error { 208 | // Read all repos configurations 209 | repos, err := ParseAPTConfigFolder(configFolderPath) 210 | if err != nil { 211 | return fmt.Errorf("parsing APT config: %s", err) 212 | } 213 | 214 | // Find the repo to remove 215 | repoToRemove := repos.Find(repo) 216 | if repoToRemove == nil { 217 | return fmt.Errorf("Repository already removed") 218 | } 219 | 220 | // Read the config file that contains the repo config to remove 221 | fileToFilter := repoToRemove.configFile 222 | data, err := ioutil.ReadFile(fileToFilter) 223 | if err != nil { 224 | return fmt.Errorf("Reading config file %s: %s", fileToFilter, err) 225 | } 226 | 227 | // Create the new version of the file 228 | scanner := bufio.NewScanner(bytes.NewReader(data)) 229 | newContent := "" 230 | for scanner.Scan() { 231 | line := scanner.Text() 232 | r := parseAPTConfigLine(line) 233 | if r!= nil && r.Equals(repo) { 234 | // Filter repo configs that match the repo to be removed 235 | continue 236 | } 237 | newContent += line + "\n" 238 | } 239 | 240 | err = replaceFile(fileToFilter, []byte(newContent)) 241 | if err != nil { 242 | return fmt.Errorf("Writing of new config: %s", err) 243 | } 244 | 245 | return nil 246 | } 247 | 248 | // EditRepository replace an old repo configuration with a new repo 249 | // configuration in the specified APT config folder (usually /etc/apt). 250 | func EditRepository(old *Repository, new *Repository, configFolderPath string) error { 251 | // Read all repos configurations 252 | repos, err := ParseAPTConfigFolder(configFolderPath) 253 | if err != nil { 254 | return fmt.Errorf("parsing APT config: %s", err) 255 | } 256 | 257 | // Find the repo to edit 258 | repoToEdit := repos.Find(old) 259 | if repoToEdit == nil { 260 | return fmt.Errorf("Repository doesn't exist") 261 | } 262 | 263 | // Read the config file that contains the repo configuration to edit 264 | fileToEdit := repoToEdit.configFile 265 | data, err := ioutil.ReadFile(fileToEdit) 266 | if err != nil { 267 | return fmt.Errorf("Reading config file %s: %s", fileToEdit, err) 268 | } 269 | 270 | // Create the new version of the file 271 | scanner := bufio.NewScanner(bytes.NewReader(data)) 272 | newContent := "" 273 | for scanner.Scan() { 274 | line := scanner.Text() 275 | r := parseAPTConfigLine(line) 276 | if r.Equals(old) { 277 | // Write the new config to replace the old one 278 | newContent += new.APTConfigLine() + "\n" 279 | continue 280 | } 281 | newContent += line + "\n" 282 | } 283 | 284 | err = replaceFile(fileToEdit, []byte(newContent)) 285 | if err != nil { 286 | return fmt.Errorf("Writing of new config: %s", err) 287 | } 288 | 289 | return nil 290 | } 291 | 292 | func replaceFile(path string, newContent []byte) error { 293 | newPath := path + ".new" 294 | backupPath := path + ".save" 295 | 296 | // Create the new version of the file 297 | err := ioutil.WriteFile(newPath, newContent, 0644) 298 | if err != nil { 299 | return fmt.Errorf("Creating replacement file for %s: %s", newPath, err) 300 | } 301 | 302 | // Only in case of error clean-up the new copy (otherwise ignore the error...) 303 | defer os.Remove(newPath) 304 | 305 | // Make a backup copy 306 | err = os.Rename(path, backupPath) 307 | if err != nil { 308 | return fmt.Errorf("Making backup copy of %s: %s", path, err) 309 | } 310 | 311 | // Rename the new copy to the final path 312 | err = os.Rename(newPath, path) 313 | if err != nil { 314 | // Something went wrong... try to rollback the backup 315 | os.Rename(backupPath, path) 316 | return fmt.Errorf("Renaming %s to %s: %s", newPath, path, err) 317 | } 318 | 319 | return nil 320 | } 321 | -------------------------------------------------------------------------------- /repos_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // This file is part of go-apt-client library 3 | // 4 | // Copyright (C) 2017 Arduino AG (http://www.arduino.cc/) 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | // 18 | 19 | package apt 20 | 21 | import ( 22 | "encoding/json" 23 | "io/ioutil" 24 | "os" 25 | "testing" 26 | 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | func TestParseAPTConfigFolder(t *testing.T) { 31 | repos, err := ParseAPTConfigFolder("testdata/apt") 32 | require.NoError(t, err, "running List command") 33 | 34 | expectedData, err := ioutil.ReadFile("testdata/TestParseAPTConfigFolder.json") 35 | require.NoError(t, err, "Reading test data") 36 | expected := []*Repository{} 37 | err = json.Unmarshal(expectedData, &expected) 38 | require.NoError(t, err, "Decoding expected data") 39 | 40 | for i, repo := range repos { 41 | require.EqualValues(t, expected[i], repo, "Comparing element %d", i) 42 | } 43 | } 44 | 45 | func TestAddAndRemoveRepository(t *testing.T) { 46 | // test cleanup 47 | defer os.Remove("testdata/apt2/sources.list.d/managed.list") 48 | defer os.Remove("testdata/apt2/sources.list.d/managed.list.save") 49 | defer os.Remove("testdata/apt2/sources.list.d/managed.list.new") 50 | 51 | repo1 := &Repository{ 52 | Enabled: true, 53 | SourceRepo: false, 54 | URI: "http://ppa.launchpad.net/webupd8team/java/ubuntu", 55 | Distribution: "zesty", 56 | Components: "main", 57 | Comment: "", 58 | } 59 | repo2 := &Repository{ 60 | Enabled: false, 61 | SourceRepo: true, 62 | URI: "http://ppa.launchpad.net/webupd8team/java/ubuntu", 63 | Distribution: "zesty", 64 | Components: "main", 65 | Comment: "", 66 | } 67 | err := AddRepository(repo1, "testdata/apt2") 68 | require.NoError(t, err, "Adding repository") 69 | err = AddRepository(repo2, "testdata/apt2") 70 | require.NoError(t, err, "Adding repository") 71 | 72 | // check that we have repo1 and repo2 added 73 | repos, err := ParseAPTConfigFolder("testdata/apt2") 74 | require.NoError(t, err, "running List command") 75 | require.True(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 76 | require.True(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 77 | 78 | err = AddRepository(repo2, "testdata/apt2") 79 | require.Error(t, err, "Adding repository again") 80 | 81 | // no changes should have happened 82 | repos, err = ParseAPTConfigFolder("testdata/apt2") 83 | require.NoError(t, err, "running List command") 84 | require.True(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 85 | require.True(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 86 | 87 | err = RemoveRepository(repo2, "testdata/apt2") 88 | require.NoError(t, err, "Removing repository") 89 | 90 | // repo2 should be removed 91 | repos, err = ParseAPTConfigFolder("testdata/apt2") 92 | require.NoError(t, err, "running List command") 93 | require.True(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 94 | require.False(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 95 | 96 | err = RemoveRepository(repo2, "testdata/apt2") 97 | require.Error(t, err, "Removing repository again") 98 | 99 | // no changes should have happened 100 | repos, err = ParseAPTConfigFolder("testdata/apt2") 101 | require.NoError(t, err, "running List command") 102 | require.True(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 103 | require.False(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 104 | 105 | err = EditRepository(repo1, repo2, "testdata/apt2") 106 | require.NoError(t, err, "editing repository %#V -> %#V", repo1, repo2) 107 | 108 | // repo2 should be changed to repo1 109 | repos, err = ParseAPTConfigFolder("testdata/apt2") 110 | require.NoError(t, err, "running List command") 111 | require.False(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 112 | require.True(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 113 | 114 | err = EditRepository(repo1, repo2, "testdata/apt2") 115 | require.Error(t, err, "editing again repository %#v -> %#v", repo1, repo2) 116 | 117 | // no changes should have happened 118 | repos, err = ParseAPTConfigFolder("testdata/apt2") 119 | require.NoError(t, err, "running List command") 120 | require.False(t, repos.Contains(repo1), "Configuration contains: %#v", repo1) 121 | require.True(t, repos.Contains(repo2), "Configuration contains: %#v", repo2) 122 | } 123 | -------------------------------------------------------------------------------- /testdata/TestParseAPTConfigFolder.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Enabled": true, 4 | "SourceRepo": false, 5 | "Options": "", 6 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 7 | "Distribution": "zesty", 8 | "Components": "main restricted", 9 | "Comment": "" 10 | }, 11 | { 12 | "Enabled": true, 13 | "SourceRepo": true, 14 | "Options": "", 15 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 16 | "Distribution": "zesty", 17 | "Components": "main restricted", 18 | "Comment": "" 19 | }, 20 | { 21 | "Enabled": true, 22 | "SourceRepo": false, 23 | "Options": "", 24 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 25 | "Distribution": "zesty-updates", 26 | "Components": "main restricted", 27 | "Comment": "" 28 | }, 29 | { 30 | "Enabled": false, 31 | "SourceRepo": true, 32 | "Options": "", 33 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 34 | "Distribution": "trusty-updates", 35 | "Components": "main restricted", 36 | "Comment": "" 37 | }, 38 | { 39 | "Enabled": true, 40 | "SourceRepo": false, 41 | "Options": "", 42 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 43 | "Distribution": "zesty", 44 | "Components": "universe", 45 | "Comment": "" 46 | }, 47 | { 48 | "Enabled": true, 49 | "SourceRepo": true, 50 | "Options": "", 51 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 52 | "Distribution": "zesty", 53 | "Components": "universe", 54 | "Comment": "" 55 | }, 56 | { 57 | "Enabled": true, 58 | "SourceRepo": false, 59 | "Options": "", 60 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 61 | "Distribution": "zesty-updates", 62 | "Components": "universe", 63 | "Comment": "" 64 | }, 65 | { 66 | "Enabled": true, 67 | "SourceRepo": true, 68 | "Options": "", 69 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 70 | "Distribution": "zesty-updates", 71 | "Components": "universe", 72 | "Comment": "" 73 | }, 74 | { 75 | "Enabled": true, 76 | "SourceRepo": false, 77 | "Options": "", 78 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 79 | "Distribution": "zesty", 80 | "Components": "multiverse", 81 | "Comment": "" 82 | }, 83 | { 84 | "Enabled": true, 85 | "SourceRepo": true, 86 | "Options": "", 87 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 88 | "Distribution": "zesty", 89 | "Components": "multiverse", 90 | "Comment": "" 91 | }, 92 | { 93 | "Enabled": true, 94 | "SourceRepo": false, 95 | "Options": "", 96 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 97 | "Distribution": "zesty-updates", 98 | "Components": "multiverse", 99 | "Comment": "" 100 | }, 101 | { 102 | "Enabled": true, 103 | "SourceRepo": true, 104 | "Options": "", 105 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 106 | "Distribution": "zesty-updates", 107 | "Components": "multiverse", 108 | "Comment": "" 109 | }, 110 | { 111 | "Enabled": true, 112 | "SourceRepo": false, 113 | "Options": "", 114 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 115 | "Distribution": "zesty-backports", 116 | "Components": "main restricted universe multiverse", 117 | "Comment": "" 118 | }, 119 | { 120 | "Enabled": true, 121 | "SourceRepo": true, 122 | "Options": "", 123 | "URI": "http://it.archive.ubuntu.com/ubuntu/", 124 | "Distribution": "zesty-backports", 125 | "Components": "main restricted universe multiverse", 126 | "Comment": "" 127 | }, 128 | { 129 | "Enabled": true, 130 | "SourceRepo": false, 131 | "Options": "", 132 | "URI": "http://security.ubuntu.com/ubuntu", 133 | "Distribution": "zesty-security", 134 | "Components": "main restricted", 135 | "Comment": "" 136 | }, 137 | { 138 | "Enabled": true, 139 | "SourceRepo": true, 140 | "Options": "", 141 | "URI": "http://security.ubuntu.com/ubuntu", 142 | "Distribution": "zesty-security", 143 | "Components": "main restricted", 144 | "Comment": "" 145 | }, 146 | { 147 | "Enabled": true, 148 | "SourceRepo": false, 149 | "Options": "", 150 | "URI": "http://security.ubuntu.com/ubuntu", 151 | "Distribution": "zesty-security", 152 | "Components": "universe", 153 | "Comment": "" 154 | }, 155 | { 156 | "Enabled": true, 157 | "SourceRepo": true, 158 | "Options": "", 159 | "URI": "http://security.ubuntu.com/ubuntu", 160 | "Distribution": "zesty-security", 161 | "Components": "universe", 162 | "Comment": "" 163 | }, 164 | { 165 | "Enabled": true, 166 | "SourceRepo": false, 167 | "Options": "", 168 | "URI": "http://security.ubuntu.com/ubuntu", 169 | "Distribution": "zesty-security", 170 | "Components": "multiverse", 171 | "Comment": "" 172 | }, 173 | { 174 | "Enabled": true, 175 | "SourceRepo": true, 176 | "Options": "", 177 | "URI": "http://security.ubuntu.com/ubuntu", 178 | "Distribution": "zesty-security", 179 | "Components": "multiverse", 180 | "Comment": "" 181 | }, 182 | { 183 | "Enabled": false, 184 | "SourceRepo": false, 185 | "Options": "", 186 | "URI": "http://archive.canonical.com/ubuntu", 187 | "Distribution": "precise", 188 | "Components": "partner", 189 | "Comment": "" 190 | }, 191 | { 192 | "Enabled": false, 193 | "SourceRepo": true, 194 | "Options": "", 195 | "URI": "http://archive.canonical.com/ubuntu", 196 | "Distribution": "precise", 197 | "Components": "partner", 198 | "Comment": "" 199 | }, 200 | { 201 | "Enabled": false, 202 | "SourceRepo": false, 203 | "Options": "", 204 | "URI": "http://download.ebz.epson.net/dsc/op/stable/debian/", 205 | "Distribution": "lsb3.2", 206 | "Components": "main", 207 | "Comment": "disabled on upgrade to trusty disabled on upgrade to utopic" 208 | }, 209 | { 210 | "Enabled": false, 211 | "SourceRepo": false, 212 | "Options": "arch=amd64", 213 | "URI": "https://apt.dockerproject.org/repo", 214 | "Distribution": "ubuntu-xenial", 215 | "Components": "main", 216 | "Comment": "disabled on upgrade to yakkety" 217 | }, 218 | { 219 | "Enabled": true, 220 | "SourceRepo": false, 221 | "Options": "arch=amd64", 222 | "URI": "http://dl.google.com/linux/chrome/deb/", 223 | "Distribution": "stable", 224 | "Components": "main", 225 | "Comment": "" 226 | }, 227 | { 228 | "Enabled": false, 229 | "SourceRepo": false, 230 | "Options": "", 231 | "URI": "http://ppa.launchpad.net/js-reynaud/kicad-4/ubuntu", 232 | "Distribution": "yakkety", 233 | "Components": "main", 234 | "Comment": "disabled on upgrade to yakkety" 235 | }, 236 | { 237 | "Enabled": false, 238 | "SourceRepo": true, 239 | "Options": "", 240 | "URI": "http://ppa.launchpad.net/js-reynaud/kicad-4/ubuntu", 241 | "Distribution": "xenial", 242 | "Components": "main", 243 | "Comment": "" 244 | }, 245 | { 246 | "Enabled": false, 247 | "SourceRepo": false, 248 | "Options": "", 249 | "URI": "http://ppa.launchpad.net/kdenlive/kdenlive-stable/ubuntu", 250 | "Distribution": "yakkety", 251 | "Components": "main", 252 | "Comment": "disabled on upgrade to yakkety" 253 | }, 254 | { 255 | "Enabled": true, 256 | "SourceRepo": true, 257 | "Options": "", 258 | "URI": "http://ppa.launchpad.net/kdenlive/kdenlive-stable/ubuntu", 259 | "Distribution": "xenial", 260 | "Components": "main", 261 | "Comment": "" 262 | }, 263 | { 264 | "Enabled": false, 265 | "SourceRepo": false, 266 | "Options": "", 267 | "URI": "http://ppa.launchpad.net/kivy-team/kivy/ubuntu", 268 | "Distribution": "trusty", 269 | "Components": "main", 270 | "Comment": "disabled on upgrade to trusty" 271 | }, 272 | { 273 | "Enabled": false, 274 | "SourceRepo": true, 275 | "Options": "", 276 | "URI": "http://ppa.launchpad.net/kivy-team/kivy/ubuntu", 277 | "Distribution": "saucy", 278 | "Components": "main", 279 | "Comment": "" 280 | }, 281 | { 282 | "Enabled": false, 283 | "SourceRepo": false, 284 | "Options": "", 285 | "URI": "http://ppa.launchpad.net/mixxx/mixxx/ubuntu", 286 | "Distribution": "yakkety", 287 | "Components": "main", 288 | "Comment": "disabled on upgrade to yakkety" 289 | }, 290 | { 291 | "Enabled": true, 292 | "SourceRepo": true, 293 | "Options": "", 294 | "URI": "http://ppa.launchpad.net/mixxx/mixxx/ubuntu", 295 | "Distribution": "xenial", 296 | "Components": "main", 297 | "Comment": "" 298 | }, 299 | { 300 | "Enabled": false, 301 | "SourceRepo": false, 302 | "Options": "", 303 | "URI": "https://private-ppa.launchpad.net/commercial-ppa-uploaders/portal-slingshot/ubuntu", 304 | "Distribution": "quantal", 305 | "Components": "main", 306 | "Comment": "Added by software-center; credentials stored in /etc/apt/auth.conf disabled on upgrade to quantal" 307 | }, 308 | { 309 | "Enabled": false, 310 | "SourceRepo": false, 311 | "Options": "", 312 | "URI": "http://download.rethinkdb.com/apt", 313 | "Distribution": "yakkety", 314 | "Components": "main", 315 | "Comment": "disabled on upgrade to yakkety" 316 | }, 317 | { 318 | "Enabled": true, 319 | "SourceRepo": false, 320 | "Options": "arch=amd64", 321 | "URI": "https://repo.skype.com/deb", 322 | "Distribution": "stable", 323 | "Components": "main", 324 | "Comment": "" 325 | }, 326 | { 327 | "Enabled": false, 328 | "SourceRepo": false, 329 | "Options": "", 330 | "URI": "http://download.virtualbox.org/virtualbox/debian", 331 | "Distribution": "trusty", 332 | "Components": "contrib", 333 | "Comment": "disabled on upgrade to trusty" 334 | }, 335 | { 336 | "Enabled": true, 337 | "SourceRepo": false, 338 | "Options": "arch=amd64", 339 | "URI": "http://packages.microsoft.com/repos/vscode", 340 | "Distribution": "stable", 341 | "Components": "main", 342 | "Comment": "" 343 | }, 344 | { 345 | "Enabled": true, 346 | "SourceRepo": false, 347 | "Options": "", 348 | "URI": "http://ppa.launchpad.net/webupd8team/java/ubuntu", 349 | "Distribution": "zesty", 350 | "Components": "main", 351 | "Comment": "" 352 | }, 353 | { 354 | "Enabled": false, 355 | "SourceRepo": true, 356 | "Options": "", 357 | "URI": "http://ppa.launchpad.net/webupd8team/java/ubuntu", 358 | "Distribution": "zesty", 359 | "Components": "main", 360 | "Comment": "" 361 | } 362 | ] -------------------------------------------------------------------------------- /testdata/apt/sources.list: -------------------------------------------------------------------------------- 1 | 2 | 3 | # See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to 4 | # newer versions of the distribution. 5 | deb http://it.archive.ubuntu.com/ubuntu/ zesty main restricted 6 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty main restricted 7 | 8 | ## Major bug fix updates produced after the final release of the 9 | ## distribution. 10 | deb http://it.archive.ubuntu.com/ubuntu/ zesty-updates main restricted 11 | # deb-src http://it.archive.ubuntu.com/ubuntu/ trusty-updates main restricted 12 | 13 | ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu 14 | ## team. Also, please note that software in universe WILL NOT receive any 15 | ## review or updates from the Ubuntu security team. 16 | deb http://it.archive.ubuntu.com/ubuntu/ zesty universe 17 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty universe 18 | deb http://it.archive.ubuntu.com/ubuntu/ zesty-updates universe 19 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty-updates universe 20 | 21 | ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu 22 | ## team, and may not be under a free licence. Please satisfy yourself as to 23 | ## your rights to use the software. Also, please note that software in 24 | ## multiverse WILL NOT receive any review or updates from the Ubuntu 25 | ## security team. 26 | deb http://it.archive.ubuntu.com/ubuntu/ zesty multiverse 27 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty multiverse 28 | deb http://it.archive.ubuntu.com/ubuntu/ zesty-updates multiverse 29 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty-updates multiverse 30 | 31 | ## N.B. software from this repository may not have been tested as 32 | ## extensively as that contained in the main release, although it includes 33 | ## newer versions of some applications which may provide useful features. 34 | ## Also, please note that software in backports WILL NOT receive any review 35 | ## or updates from the Ubuntu security team. 36 | deb http://it.archive.ubuntu.com/ubuntu/ zesty-backports main restricted universe multiverse 37 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty-backports main restricted universe multiverse 38 | 39 | deb http://security.ubuntu.com/ubuntu zesty-security main restricted 40 | deb-src http://security.ubuntu.com/ubuntu zesty-security main restricted 41 | deb http://security.ubuntu.com/ubuntu zesty-security universe 42 | deb-src http://security.ubuntu.com/ubuntu zesty-security universe 43 | deb http://security.ubuntu.com/ubuntu zesty-security multiverse 44 | deb-src http://security.ubuntu.com/ubuntu zesty-security multiverse 45 | 46 | ## Uncomment the following two lines to add software from Canonical's 47 | ## 'partner' repository. 48 | ## This software is not part of Ubuntu, but is offered by Canonical and the 49 | ## respective vendors as a service to Ubuntu users. 50 | # deb http://archive.canonical.com/ubuntu precise partner 51 | # deb-src http://archive.canonical.com/ubuntu precise partner 52 | 53 | # deb http://download.ebz.epson.net/dsc/op/stable/debian/ lsb3.2 main # disabled on upgrade to trusty disabled on upgrade to utopic 54 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/docker.list: -------------------------------------------------------------------------------- 1 | # deb [arch=amd64] https://apt.dockerproject.org/repo ubuntu-xenial main # disabled on upgrade to yakkety 2 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/google-chrome.list: -------------------------------------------------------------------------------- 1 | ### THIS FILE IS AUTOMATICALLY CONFIGURED ### 2 | # You may comment out this entry, but any other modifications may be lost. 3 | deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main 4 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/js-reynaud-ubuntu-kicad-4-xenial.list: -------------------------------------------------------------------------------- 1 | # deb http://ppa.launchpad.net/js-reynaud/kicad-4/ubuntu yakkety main # disabled on upgrade to yakkety 2 | # deb-src http://ppa.launchpad.net/js-reynaud/kicad-4/ubuntu xenial main 3 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/kdenlive-ubuntu-kdenlive-stable-xenial.list: -------------------------------------------------------------------------------- 1 | # deb http://ppa.launchpad.net/kdenlive/kdenlive-stable/ubuntu yakkety main # disabled on upgrade to yakkety 2 | deb-src http://ppa.launchpad.net/kdenlive/kdenlive-stable/ubuntu xenial main 3 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/kivy-team-kivy-saucy.list: -------------------------------------------------------------------------------- 1 | # deb http://ppa.launchpad.net/kivy-team/kivy/ubuntu trusty main # disabled on upgrade to trusty 2 | # deb-src http://ppa.launchpad.net/kivy-team/kivy/ubuntu saucy main 3 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/mixxx-ubuntu-mixxx-xenial.list: -------------------------------------------------------------------------------- 1 | # deb http://ppa.launchpad.net/mixxx/mixxx/ubuntu yakkety main # disabled on upgrade to yakkety 2 | deb-src http://ppa.launchpad.net/mixxx/mixxx/ubuntu xenial main 3 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/oab.list: -------------------------------------------------------------------------------- 1 | # deb file:///var/local/oab/deb / #Local Java - https://github.com/flexiondotorg/oab-java6 disabled on upgrade to raring 2 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/private-ppa.launchpad.net_commercial-ppa-uploaders_portal-slingshot_ubuntu.list: -------------------------------------------------------------------------------- 1 | # deb https://private-ppa.launchpad.net/commercial-ppa-uploaders/portal-slingshot/ubuntu quantal main #Added by software-center; credentials stored in /etc/apt/auth.conf disabled on upgrade to quantal 2 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/rethinkdb.list: -------------------------------------------------------------------------------- 1 | # deb http://download.rethinkdb.com/apt yakkety main # disabled on upgrade to yakkety 2 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/skype-stable.list: -------------------------------------------------------------------------------- 1 | deb [arch=amd64] https://repo.skype.com/deb stable main 2 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/virtualbox.list: -------------------------------------------------------------------------------- 1 | 2 | # deb http://download.virtualbox.org/virtualbox/debian trusty contrib # disabled on upgrade to trusty 3 | 4 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/vscode.list: -------------------------------------------------------------------------------- 1 | ### THIS FILE IS AUTOMATICALLY CONFIGURED ### 2 | # You may comment out this entry, but any other modifications may be lost. 3 | deb [arch=amd64] http://packages.microsoft.com/repos/vscode stable main 4 | -------------------------------------------------------------------------------- /testdata/apt/sources.list.d/webupd8team-ubuntu-java-zesty.list: -------------------------------------------------------------------------------- 1 | deb http://ppa.launchpad.net/webupd8team/java/ubuntu zesty main 2 | # deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu zesty main 3 | -------------------------------------------------------------------------------- /testdata/apt2/sources.list: -------------------------------------------------------------------------------- 1 | deb http://it.archive.ubuntu.com/ubuntu/ zesty main restricted 2 | deb-src http://it.archive.ubuntu.com/ubuntu/ zesty main restricted 3 | 4 | --------------------------------------------------------------------------------