Skip to content

Commit 1e54b12

Browse files
committed
Added repository management
1 parent a7bf7da commit 1e54b12

17 files changed

+608
-0
lines changed

repos.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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+
"path/filepath"
27+
"regexp"
28+
"strings"
29+
)
30+
31+
// Repository is a repository installed in the system
32+
type Repository struct {
33+
Enabled bool
34+
SourceRepo bool
35+
Options string
36+
URI string
37+
Distribution string
38+
Components string
39+
Comment string
40+
}
41+
42+
// APTConfigLine returns the source.list config line for the Repository
43+
func (r *Repository) APTConfigLine() string {
44+
res := ""
45+
if !r.Enabled {
46+
res = "# "
47+
}
48+
if r.SourceRepo {
49+
res += "deb-src "
50+
} else {
51+
res += "deb "
52+
}
53+
if strings.TrimSpace(r.Options) != "" {
54+
res += "[" + r.Options + "]"
55+
}
56+
res += r.URI + " " + r.Distribution + " " + r.Components
57+
if strings.TrimSpace(r.Comment) != "" {
58+
res += " # " + r.Comment
59+
}
60+
return res
61+
}
62+
63+
var aptConfigLineRegexp = regexp.MustCompile(`^(# )?(deb|deb-src)(?: \[(.*)\])? ([^ ]+) ([^ ]+) ([^#\n]+)(?: +# *(.*))?$`)
64+
65+
func parseAPTConfigLine(line string) *Repository {
66+
match := aptConfigLineRegexp.FindAllStringSubmatch(line, -1)
67+
if len(match) == 0 || len(match[0]) < 6 {
68+
return nil
69+
}
70+
fields := match[0]
71+
//fmt.Printf("%+v\n", fields)
72+
return &Repository{
73+
Enabled: fields[1] != "# ",
74+
SourceRepo: fields[2] == "deb-src",
75+
Options: fields[3],
76+
URI: fields[4],
77+
Distribution: fields[5],
78+
Components: fields[6],
79+
Comment: fields[7],
80+
}
81+
}
82+
83+
func parseAPTConfigFile(configPath string) ([]*Repository, error) {
84+
data, err := ioutil.ReadFile(configPath)
85+
if err != nil {
86+
return nil, fmt.Errorf("Reading %s: %s", configPath, err)
87+
}
88+
scanner := bufio.NewScanner(bytes.NewReader(data))
89+
90+
res := []*Repository{}
91+
for scanner.Scan() {
92+
line := scanner.Text()
93+
repo := parseAPTConfigLine(line)
94+
//fmt.Printf("%+v\n", repo)
95+
if repo != nil {
96+
res = append(res, repo)
97+
}
98+
}
99+
return res, nil
100+
}
101+
102+
// ParseAPTConfigFolder scans an APT config folder (usually /etc/apt) to
103+
// get information about configured repositories
104+
func ParseAPTConfigFolder(folderPath string) ([]*Repository, error) {
105+
sources := []string{filepath.Join(folderPath, "sources.list")}
106+
107+
sourcesFolder := filepath.Join(folderPath, "sources.list.d")
108+
list, err := ioutil.ReadDir(sourcesFolder)
109+
if err != nil {
110+
return nil, fmt.Errorf("Reading %s folder: %s", sourcesFolder, err)
111+
}
112+
for _, l := range list {
113+
if strings.HasSuffix(l.Name(), ".list") {
114+
sources = append(sources, filepath.Join(sourcesFolder, l.Name()))
115+
}
116+
}
117+
118+
res := []*Repository{}
119+
for _, source := range sources {
120+
repos, err := parseAPTConfigFile(source)
121+
if err != nil {
122+
return nil, fmt.Errorf("Parsing %s: %s", source, err)
123+
}
124+
res = append(res, repos...)
125+
}
126+
return res, nil
127+
}

repos_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
"testing"
25+
26+
"github.com/stretchr/testify/require"
27+
)
28+
29+
func TestParseAPTConfigFolder(t *testing.T) {
30+
repos, err := ParseAPTConfigFolder("testdata/apt")
31+
require.NoError(t, err, "running List command")
32+
33+
expectedData, err := ioutil.ReadFile("testdata/TestParseAPTConfigFolder.json")
34+
require.NoError(t, err, "Reading test data")
35+
expected := []*Repository{}
36+
err = json.Unmarshal(expectedData, &expected)
37+
require.NoError(t, err, "Decoding expected data")
38+
39+
for i, repo := range repos {
40+
require.EqualValues(t, expected[i], repo, "Comparing element %d", i)
41+
}
42+
}

0 commit comments

Comments
 (0)