Skip to content

Commit

Permalink
Add source code
Browse files Browse the repository at this point in the history
  • Loading branch information
cristim committed Dec 7, 2016
1 parent f1c4d62 commit 2c90875
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 24 deletions.
25 changes: 1 addition & 24 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof
kernel-update
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
This is a tiny utility that can ease the process of updating kernels on Ubuntu.

It is automatically installing the latest build from the kernel-ppa/mainline PPA
[repository](http://kernel.ubuntu.com/~kernel-ppa/mainline/).

It supports installing both 'generic' and 'lowlatency' kernel flavors.

# Installation #

go get github.com/cristim/kernel-update

# Usage #

Assuming `$GOPATH/bin` is in your `PATH`, this should work out of the box:

kernel-update -flavor lowlatency

186 changes: 186 additions & 0 deletions kernel-update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
//usr/bin/go run $0 $@ ; exit
package main

import (
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
"runtime"
"strings"

"golang.org/x/net/html"
)

const kernelURLBase = "http://kernel.ubuntu.com/~kernel-ppa/mainline/"

var logger *log.Logger

type fileURLs struct {
allHeaders string
currentArchHeaders string
currentArchImage string
}

func main() {
logger = log.New(os.Stdout, "", log.Lshortfile)

var imageFlavor string
flag.StringVar(&imageFlavor, "flavor", "generic", "Kernel flavor: lowlatency|generic.")
flag.Parse()

htmlBodyReader := httpGet(kernelURLBase)

defer htmlBodyReader.Close()

latestVersion := parseLatestKernelVersion(htmlBodyReader)
logger.Println(latestVersion)

dir, err := ioutil.TempDir("", "")
if err != nil {
logger.Fatalln(err.Error)
}
os.Chdir(dir)

logger.Println("Using temporary directory", dir)

downloadPackages(kernelURLBase, latestVersion, imageFlavor)

if err := printInstallPackagesCommand(dir); err != nil {

logger.Println(err.Error())
os.RemoveAll(dir)
}

}

func printInstallPackagesCommand(dir string) error {

_, err := filepath.Glob("*.deb")

if err != nil {

logger.Println(err.Error())
return err
}

fmt.Println("Execute the following commands in order to update your kernel:")
fmt.Println("################# BEGIN #################")
fmt.Printf("cd %s \nsudo dpkg -i *.deb \nrm -rf %s\n", dir, dir)
fmt.Println("################## END ##################")

return err
}

func httpGet(kernelURL string) io.ReadCloser {
resp, err := http.Get(kernelURL)
if err != nil {
log.Fatalln("Failed to perform request")
}
return resp.Body
}

func parseLatestKernelVersion(reader io.Reader) string {
var latestVersion string
doc, err := html.Parse(reader)
if err != nil {
log.Fatal(err)
}

walkKernelVersionsTree(doc, &latestVersion)
return latestVersion
}

// always sets the latestVersion global variable to the last a href
func walkKernelVersionsTree(n *html.Node, latestVersion *string) {

if n.Type == html.ElementNode && n.Data == "a" {
*latestVersion = n.Attr[0].Val
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
walkKernelVersionsTree(c, latestVersion)
}

}

func downloadPackages(kernelURLBase, latestVersion, flavor string) {
files := getPackageFiles(kernelURLBase, latestVersion, flavor)
downloadFromUrl(kernelURLBase + latestVersion + files.allHeaders)
downloadFromUrl(kernelURLBase + latestVersion + files.currentArchHeaders)
downloadFromUrl(kernelURLBase + latestVersion + files.currentArchImage)
}

func downloadFromUrl(url string) {
tokens := strings.Split(url, "/")
fileName := tokens[len(tokens)-1]
fmt.Println("Downloading", url, "to", fileName)

// TODO: check file existence first with io.IsExist
output, err := os.Create(fileName)
if err != nil {
fmt.Println("Error while creating", fileName, "-", err)
return
}
defer output.Close()

response, err := http.Get(url)
if err != nil {
fmt.Println("Error while downloading", url, "-", err)
return
}
defer response.Body.Close()

n, err := io.Copy(output, response.Body)
if err != nil {
fmt.Println("Error while downloading", url, "-", err)
return
}

fmt.Println(n, "bytes downloaded.")
}

func getPackageFiles(kernelURLBase, latestVersion, flavor string) fileURLs {
var fileList fileURLs

htmlBodyReader := httpGet(kernelURLBase + latestVersion)

doc, err := html.Parse(htmlBodyReader)
if err != nil {
log.Fatal(err)
}

walkBuildsTree(doc, &fileList, flavor)

return fileList
}

// always sets the latestVersion global variable to the last a href
func walkBuildsTree(n *html.Node, urls *fileURLs, flavor string) {

if n.Type == html.ElementNode && n.Data == "a" {
file := n.Attr[0].Val

if strings.Contains(file, "headers") &&
strings.Contains(file, "all") {
urls.allHeaders = file
}
if strings.Contains(file, runtime.GOARCH) &&
strings.Contains(file, flavor) {
if strings.Contains(file, "headers") {
urls.currentArchHeaders = file
}
if strings.Contains(file, "image") {
urls.currentArchImage = file
}
}
}

for c := n.FirstChild; c != nil; c = c.NextSibling {
walkBuildsTree(c, urls, flavor)
}

}

0 comments on commit 2c90875

Please sign in to comment.