Skip to content

Commit 2c90875

Browse files
committed
Add source code
1 parent f1c4d62 commit 2c90875

File tree

3 files changed

+204
-24
lines changed

3 files changed

+204
-24
lines changed

.gitignore

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1 @@
1-
# Compiled Object files, Static and Dynamic libs (Shared Objects)
2-
*.o
3-
*.a
4-
*.so
5-
6-
# Folders
7-
_obj
8-
_test
9-
10-
# Architecture specific extensions/prefixes
11-
*.[568vq]
12-
[568vq].out
13-
14-
*.cgo1.go
15-
*.cgo2.c
16-
_cgo_defun.c
17-
_cgo_gotypes.go
18-
_cgo_export.*
19-
20-
_testmain.go
21-
22-
*.exe
23-
*.test
24-
*.prof
1+
kernel-update

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
This is a tiny utility that can ease the process of updating kernels on Ubuntu.
2+
3+
It is automatically installing the latest build from the kernel-ppa/mainline PPA
4+
[repository](http://kernel.ubuntu.com/~kernel-ppa/mainline/).
5+
6+
It supports installing both 'generic' and 'lowlatency' kernel flavors.
7+
8+
# Installation #
9+
10+
go get github.com/cristim/kernel-update
11+
12+
# Usage #
13+
14+
Assuming `$GOPATH/bin` is in your `PATH`, this should work out of the box:
15+
16+
kernel-update -flavor lowlatency
17+

kernel-update.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
//usr/bin/go run $0 $@ ; exit
2+
package main
3+
4+
import (
5+
"flag"
6+
"fmt"
7+
"io"
8+
"io/ioutil"
9+
"log"
10+
"net/http"
11+
"os"
12+
"path/filepath"
13+
"runtime"
14+
"strings"
15+
16+
"golang.org/x/net/html"
17+
)
18+
19+
const kernelURLBase = "http://kernel.ubuntu.com/~kernel-ppa/mainline/"
20+
21+
var logger *log.Logger
22+
23+
type fileURLs struct {
24+
allHeaders string
25+
currentArchHeaders string
26+
currentArchImage string
27+
}
28+
29+
func main() {
30+
logger = log.New(os.Stdout, "", log.Lshortfile)
31+
32+
var imageFlavor string
33+
flag.StringVar(&imageFlavor, "flavor", "generic", "Kernel flavor: lowlatency|generic.")
34+
flag.Parse()
35+
36+
htmlBodyReader := httpGet(kernelURLBase)
37+
38+
defer htmlBodyReader.Close()
39+
40+
latestVersion := parseLatestKernelVersion(htmlBodyReader)
41+
logger.Println(latestVersion)
42+
43+
dir, err := ioutil.TempDir("", "")
44+
if err != nil {
45+
logger.Fatalln(err.Error)
46+
}
47+
os.Chdir(dir)
48+
49+
logger.Println("Using temporary directory", dir)
50+
51+
downloadPackages(kernelURLBase, latestVersion, imageFlavor)
52+
53+
if err := printInstallPackagesCommand(dir); err != nil {
54+
55+
logger.Println(err.Error())
56+
os.RemoveAll(dir)
57+
}
58+
59+
}
60+
61+
func printInstallPackagesCommand(dir string) error {
62+
63+
_, err := filepath.Glob("*.deb")
64+
65+
if err != nil {
66+
67+
logger.Println(err.Error())
68+
return err
69+
}
70+
71+
fmt.Println("Execute the following commands in order to update your kernel:")
72+
fmt.Println("################# BEGIN #################")
73+
fmt.Printf("cd %s \nsudo dpkg -i *.deb \nrm -rf %s\n", dir, dir)
74+
fmt.Println("################## END ##################")
75+
76+
return err
77+
}
78+
79+
func httpGet(kernelURL string) io.ReadCloser {
80+
resp, err := http.Get(kernelURL)
81+
if err != nil {
82+
log.Fatalln("Failed to perform request")
83+
}
84+
return resp.Body
85+
}
86+
87+
func parseLatestKernelVersion(reader io.Reader) string {
88+
var latestVersion string
89+
doc, err := html.Parse(reader)
90+
if err != nil {
91+
log.Fatal(err)
92+
}
93+
94+
walkKernelVersionsTree(doc, &latestVersion)
95+
return latestVersion
96+
}
97+
98+
// always sets the latestVersion global variable to the last a href
99+
func walkKernelVersionsTree(n *html.Node, latestVersion *string) {
100+
101+
if n.Type == html.ElementNode && n.Data == "a" {
102+
*latestVersion = n.Attr[0].Val
103+
}
104+
for c := n.FirstChild; c != nil; c = c.NextSibling {
105+
walkKernelVersionsTree(c, latestVersion)
106+
}
107+
108+
}
109+
110+
func downloadPackages(kernelURLBase, latestVersion, flavor string) {
111+
files := getPackageFiles(kernelURLBase, latestVersion, flavor)
112+
downloadFromUrl(kernelURLBase + latestVersion + files.allHeaders)
113+
downloadFromUrl(kernelURLBase + latestVersion + files.currentArchHeaders)
114+
downloadFromUrl(kernelURLBase + latestVersion + files.currentArchImage)
115+
}
116+
117+
func downloadFromUrl(url string) {
118+
tokens := strings.Split(url, "/")
119+
fileName := tokens[len(tokens)-1]
120+
fmt.Println("Downloading", url, "to", fileName)
121+
122+
// TODO: check file existence first with io.IsExist
123+
output, err := os.Create(fileName)
124+
if err != nil {
125+
fmt.Println("Error while creating", fileName, "-", err)
126+
return
127+
}
128+
defer output.Close()
129+
130+
response, err := http.Get(url)
131+
if err != nil {
132+
fmt.Println("Error while downloading", url, "-", err)
133+
return
134+
}
135+
defer response.Body.Close()
136+
137+
n, err := io.Copy(output, response.Body)
138+
if err != nil {
139+
fmt.Println("Error while downloading", url, "-", err)
140+
return
141+
}
142+
143+
fmt.Println(n, "bytes downloaded.")
144+
}
145+
146+
func getPackageFiles(kernelURLBase, latestVersion, flavor string) fileURLs {
147+
var fileList fileURLs
148+
149+
htmlBodyReader := httpGet(kernelURLBase + latestVersion)
150+
151+
doc, err := html.Parse(htmlBodyReader)
152+
if err != nil {
153+
log.Fatal(err)
154+
}
155+
156+
walkBuildsTree(doc, &fileList, flavor)
157+
158+
return fileList
159+
}
160+
161+
// always sets the latestVersion global variable to the last a href
162+
func walkBuildsTree(n *html.Node, urls *fileURLs, flavor string) {
163+
164+
if n.Type == html.ElementNode && n.Data == "a" {
165+
file := n.Attr[0].Val
166+
167+
if strings.Contains(file, "headers") &&
168+
strings.Contains(file, "all") {
169+
urls.allHeaders = file
170+
}
171+
if strings.Contains(file, runtime.GOARCH) &&
172+
strings.Contains(file, flavor) {
173+
if strings.Contains(file, "headers") {
174+
urls.currentArchHeaders = file
175+
}
176+
if strings.Contains(file, "image") {
177+
urls.currentArchImage = file
178+
}
179+
}
180+
}
181+
182+
for c := n.FirstChild; c != nil; c = c.NextSibling {
183+
walkBuildsTree(c, urls, flavor)
184+
}
185+
186+
}

0 commit comments

Comments
 (0)