Skip to content

Commit ea10189

Browse files
author
Michel Casabianca
committed
Release 1.0.0: First release
2 parents 0b8c816 + f8696c4 commit ea10189

File tree

4 files changed

+84
-22
lines changed

4 files changed

+84
-22
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/

Diff for: CHANGELOG.yml

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
- version: 1.0.0
44
date: 2015-07-28
55
summary: First release
6+
note:
7+
- "This first release can serve packages but may not accept some."

Diff for: README.md

+13
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,17 @@ There are binaries for following platforms:
2424
Usage
2525
-----
2626

27+
To run the server, type on command line :
28+
29+
cheeseshop -port 8000 -path simple -root . -shop http://pypi.python.org
30+
31+
Options on command line :
32+
33+
- *-port* to set the port the server is litening (default to *8000*).
34+
- *-path* to set the URL path (defaults to *simple*).
35+
- *-root* to set the directory where packages are living (defaults to current directory).
36+
- *-shop* to set the URL of the shop for packages that are not found.
37+
38+
The server outputs logs on the terminal. To get help on the console, type `cheeseshop -help`.
39+
2740
*Enjoy!*

Diff for: cheeseshop.go

+68-22
Original file line numberDiff line numberDiff line change
@@ -19,58 +19,104 @@ const (
1919
)
2020

2121
var port = flag.Int("port", 8000, "The port CheeseShop is listening")
22-
var path = flag.String("path", "/simple/", "The URL path")
22+
var path = flag.String("path", "simple", "The URL path")
2323
var root = flag.String("root", ".", "The root directory for packages")
24-
var shop = flag.String("shop", "http://pypi.python.org", "Shop to redirect to when not found")
24+
var shop = flag.String("shop", "http://pypi.python.org", "Redirection when not found")
25+
26+
func listRoot(w http.ResponseWriter, r *http.Request) {
27+
log.Printf("Listing root %s", *root)
28+
files, err := ioutil.ReadDir(*root)
29+
if err != nil {
30+
http.Error(w, fmt.Sprintf("Error listing root directory %s", *root), 500)
31+
return
32+
}
33+
w.Write([]byte(fmt.Sprintf(LIST_HEAD, "root", "root")))
34+
for _, file := range files {
35+
if file.Mode().IsDir() {
36+
w.Write([]byte(fmt.Sprintf(LIST_ELEMENT, *path+file.Name(), file.Name())))
37+
}
38+
}
39+
w.Write([]byte(LIST_TAIL))
40+
}
2541

2642
func listDirectory(dir string, w http.ResponseWriter, r *http.Request) {
27-
files, err := ioutil.ReadDir(dir)
43+
directory := filepath.Join(*root, dir)
44+
if _, err := os.Stat(directory); os.IsNotExist(err) {
45+
url := *shop + *path + dir
46+
log.Printf("Redirecting to %s", url)
47+
http.Redirect(w, r, url, 302)
48+
return
49+
}
50+
log.Printf("Listing directory %s", directory)
51+
files, err := ioutil.ReadDir(directory)
2852
if err != nil {
2953
http.Error(w, fmt.Sprintf("Error listing directory %s", dir), 500)
54+
return
3055
}
31-
pkg := dir[strings.LastIndex(dir, "/")+1:]
32-
w.Write([]byte(fmt.Sprintf(LIST_HEAD, pkg, pkg)))
56+
w.Write([]byte(fmt.Sprintf(LIST_HEAD, dir, dir)))
3357
for _, file := range files {
34-
w.Write([]byte(fmt.Sprintf(LIST_ELEMENT, *path+pkg+"/"+file.Name(), file.Name())))
58+
w.Write([]byte(fmt.Sprintf(LIST_ELEMENT, *path+dir+"/"+file.Name(), file.Name())))
3559
}
3660
w.Write([]byte(LIST_TAIL))
3761
}
3862

39-
func servePackage(filename string, w http.ResponseWriter, r *http.Request) {
63+
func servePackage(dir, file string, w http.ResponseWriter, r *http.Request) {
64+
filename := filepath.Join(*root, dir, file)
65+
if _, err := os.Stat(filename); os.IsNotExist(err) {
66+
url := *shop + *path + dir + "/" + file
67+
log.Printf("Redirecting to %s", url)
68+
http.Redirect(w, r, url, 302)
69+
return
70+
}
71+
log.Printf("Serving file %s", filename)
4072
http.ServeFile(w, r, filename)
4173
}
4274

4375
func handler(w http.ResponseWriter, r *http.Request) {
44-
filename := filepath.Join(*root, r.URL.Path[1:])
45-
if info, err := os.Stat(filename); err != nil {
46-
url := *shop + r.URL.Path
47-
log.Print("Redirecting to ", url)
48-
http.Redirect(w, r, url, 302)
76+
parts := strings.Split(r.URL.Path[len(*path):], "/")
77+
if len(parts) > 2 {
78+
http.Error(w, fmt.Sprintf("%s is not a valid path", r.URL.Path), 404)
79+
return
80+
} else if len(parts) == 1 && parts[0] == "" {
81+
listRoot(w, r)
82+
} else if len(parts) == 1 {
83+
listDirectory(parts[0], w, r)
4984
} else {
50-
switch mode := info.Mode(); {
51-
case mode.IsDir():
52-
log.Print("Listing directory ", filename)
53-
listDirectory(filename, w, r)
54-
case mode.IsRegular():
55-
log.Print("Serving package ", filename)
56-
servePackage(filename, w, r)
57-
}
85+
servePackage(parts[0], parts[1], w, r)
5886
}
5987
}
6088

6189
func parseCommandLine() {
6290
flag.Parse()
6391
absroot, err := filepath.Abs(*root)
6492
if err != nil {
65-
panic("Error building root directory")
93+
log.Fatal("Error building root directory")
6694
}
6795
root = &absroot
96+
info, err := os.Stat(*root)
97+
if err != nil {
98+
log.Fatalf("Root directory %s not found", *root)
99+
}
100+
if !info.Mode().IsDir() {
101+
log.Fatalf("Root %s is not a directory", *root)
102+
}
103+
if !strings.HasPrefix(*path, "/") {
104+
p := "/" + *path
105+
path = &p
106+
}
107+
if !strings.HasSuffix(*path, "/") {
108+
p := *path + "/"
109+
path = &p
110+
}
111+
if *port > 65535 || *port < 0 {
112+
log.Fatalf("Bad port number %d", *port)
113+
}
68114
}
69115

70116
func main() {
71117
parseCommandLine()
72118
http.HandleFunc(*path, handler)
73-
log.Print("Starting CheeseShop version ", VERSION)
119+
log.Print("Starting CheeseShop (version: ", VERSION, ", path: ", *path, ", port: ", *port, ", root: ", *root, ")")
74120
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
75121
log.Print("Stopping CheeseShop")
76122
}

0 commit comments

Comments
 (0)