PageRenderTime 29ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/mk.go

https://code.google.com/p/godag/
Go | 1248 lines | 937 code | 236 blank | 75 comment | 168 complexity | 48afffa838c747304a9f67be0f92677d MD5 | raw file
Possible License(s): GPL-3.0
  1. /* Built : 2012-04-07 18:06:02.276189 +0000 UTC */
  2. //-------------------------------------------------------------------
  3. // Auto generated code, but you are encouraged to modify it รข˜?
  4. // Manual: http://godag.googlecode.com
  5. //-------------------------------------------------------------------
  6. package main
  7. import(
  8. "bytes"
  9. "compress/gzip"
  10. "flag"
  11. "fmt"
  12. "io"
  13. "log"
  14. "os"
  15. "os/exec"
  16. "path/filepath"
  17. "regexp"
  18. "strings"
  19. "time"
  20. "runtime"
  21. )
  22. //-------------------------------------------------------------------
  23. // User defined targets: flexible pure go way to control build
  24. //-------------------------------------------------------------------
  25. type Target struct {
  26. desc string // description of target
  27. first func() // this is called prior to building
  28. last func() // this is called after building
  29. }
  30. /********************************************************************
  31. Code inside playground is NOT auto generated, each time you run
  32. this command:
  33. gd -gdmk=somefilename.go
  34. this happens:
  35. if (somefilename.go already exists) {
  36. transfer playground from somefilename.go to new version
  37. of somefilename.go, i.e. you never loose the targets you
  38. create inside the playground..
  39. }else{
  40. write somefilename.go with example targets
  41. }
  42. ********************************************************************/
  43. // PLAYGROUND START
  44. var targets = map[string]*Target{
  45. "clean": &Target{
  46. desc: "rm -rf _obj/",
  47. first: cleanDoFirst,
  48. last: nil,
  49. },
  50. "uninstall": &Target{
  51. desc: "target:clean + rm -f $HOME/bin/gd $GOBIN/gd",
  52. first: uninstallDoFirst,
  53. last: nil,
  54. },
  55. "install": &Target{
  56. desc: "target:build + mv 'gd' $HOME/bin || $GOBIN",
  57. first: installDoFirst,
  58. last: nil,
  59. },
  60. "build": &Target{
  61. desc: "compile and link 'gd' (alias for -o=gd)",
  62. first: buildDoFirst,
  63. last: nil,
  64. },
  65. "stdlib": &Target{
  66. desc: "copy pure go part of standard library",
  67. first: stdlibDoFirst,
  68. last: nil,
  69. },
  70. "testok": &Target{
  71. desc: "copy pure go testable part of standard library",
  72. first: testokDoFirst,
  73. last: nil,
  74. },
  75. "release": &Target{
  76. desc: "update golang to latest release if necessary",
  77. first: releaseDoFirst,
  78. last: nil,
  79. },
  80. "debian": &Target{
  81. desc: "create a debian package of godag",
  82. first: debianDoFirst,
  83. last: debianDoLast,
  84. },
  85. }
  86. // debian target
  87. func debianDoFirst() {
  88. // see if required executables can be found
  89. debianSanity()
  90. // normail build first, i.e. build 'gd'
  91. buildDoFirst()
  92. }
  93. var debianCopyright = `Name: godag
  94. Maintainer: bjarne holen <bjarneh@ifi.uio.no>
  95. Source: https://godag.googlecode.com/hg
  96. Files: *
  97. Copyright: 2011, bjarne holen <bjarneh@ifi.uio.no>
  98. License: GPL-3
  99. License: GPL-3
  100. On Debian systems, the complete text of the GNU General Public License
  101. version 3 can be found in '/usr/share/common-licenses/GPL-3'.
  102. `
  103. var debianChangelog = `godag (0.3.0) devel; urgency=low
  104. * The actual changelog can be found in changelog...
  105. -- Bjarne Holen <bjarneh@ifi.uio.no> Thu, 05 May 2011 14:07:28 -0400
  106. `
  107. var debianControl = `Package: godag
  108. Version: 0.3
  109. Section: devel
  110. Priority: optional
  111. Architecture: %s
  112. Depends:
  113. Suggests: gccgo,golang
  114. Conflicts:
  115. Replaces:
  116. Installed-Size: %d
  117. Maintainer: Bjarne Holen <bjarneh@ifi.uio.no>
  118. Description: Golang/Go compiler front-end.
  119. Godag automatically builds projects written in golang,
  120. by inspecting source-code imports to calculate compile order.
  121. Unit-testing, formatting and installation of external
  122. libraries are also automated. The default back-end is gc,
  123. other back-ends have partial support: gccgo, express.
  124. `
  125. func debianDoLast() {
  126. var debArch string
  127. var dirs []string
  128. goarch := os.Getenv("GOARCH")
  129. if goarch == "" {
  130. goarch = runtime.GOARCH
  131. }
  132. switch goarch {
  133. case "386":
  134. debArch = "i386"
  135. case "":
  136. log.Fatalf("[ERROR] GOARCH == ''\n")
  137. default:
  138. debArch = os.Getenv("GOARCH")
  139. }
  140. dirs = []string{"debian/DEBIAN",
  141. "debian/usr/bin",
  142. "debian/usr/share/man/man1",
  143. "debian/usr/share/doc/godag",
  144. "debian/etc/bash_completion.d"}
  145. say.Println("debian : make structure")
  146. for i := 0; i < len(dirs); i++ {
  147. e := os.MkdirAll(dirs[i], 0755)
  148. quitter(e)
  149. }
  150. e := os.Rename("gd", "debian/usr/bin/gd")
  151. quitter(e)
  152. say.Println("debian : copy files")
  153. // copyGzip( from, to, gzipfile )
  154. copyGzip("util/gd-completion.sh", "debian/etc/bash_completion.d/gd", false)
  155. copyGzip("util/gd.1", "debian/usr/share/man/man1/gd.1.gz", true)
  156. copyGzip("util/gd.1", "debian/usr/share/man/man1/godag.1.gz", true)
  157. copyGzipStringBuffer(debianCopyright, "debian/usr/share/doc/godag/copyright", false)
  158. copyGzipStringBuffer(debianChangelog, "debian/usr/share/doc/godag/changelog.Debian.gz", true)
  159. copyGzipStringBuffer("/etc/bash_completion.d/gd\n", "debian/DEBIAN/conffiles", false)
  160. if isDir(".hg") {
  161. hglog, e := exec.Command("hg", "log").CombinedOutput()
  162. quitter(e)
  163. copyGzipByteBuffer(hglog, "debian/usr/share/doc/godag/changelog.gz", true)
  164. } else { // git
  165. gitlog, e := exec.Command("git", "log").CombinedOutput()
  166. quitter(e)
  167. copyGzipByteBuffer(gitlog, "debian/usr/share/doc/godag/changelog.gz", true)
  168. }
  169. // find size of debian package
  170. var totalSize int64 = int64(len(debianControl))
  171. fn := func(s string) bool { return true }
  172. files := PathWalk("debian", fn)
  173. for i := 0; i < len(files); i++ {
  174. finfo, e := os.Stat(files[i])
  175. quitter(e)
  176. totalSize += finfo.Size()
  177. }
  178. tmpBuf := fmt.Sprintf(debianControl, debArch, totalSize)
  179. copyGzipStringBuffer(tmpBuf, "debian/DEBIAN/control", false)
  180. // satisfy lintian
  181. say.Println("debian : chmod files in debian")
  182. var fileModes = map[string]uint32{
  183. "debian/usr/bin/gd": 0755,
  184. "debian/DEBIAN/conffiles": 0644,
  185. "debian/etc/bash_completion.d/gd": 0755,
  186. "debian/usr/share/man/man1/gd.1.gz": 0644,
  187. "debian/usr/share/man/man1/godag.1.gz": 0644,
  188. "debian/usr/share/doc/godag/copyright": 0644,
  189. "debian/usr/share/doc/godag/changelog.Debian.gz": 0644,
  190. "debian/usr/share/doc/godag/changelog.gz": 0644,
  191. }
  192. for k, v := range fileModes {
  193. e = os.Chmod(k, os.FileMode(v))
  194. quitter(e)
  195. }
  196. run([]string{"fakeroot", "dpkg-deb", "--build", "debian"})
  197. e = os.Rename("debian.deb", "godag_0.3-0_"+debArch+".deb")
  198. quitter(e)
  199. say.Println("debian : rm -rf ./debian")
  200. e = os.RemoveAll("debian")
  201. quitter(e)
  202. }
  203. func debianSanity() {
  204. executables := []string{"dpkg-deb", "fakeroot"}
  205. if isDir(".hg") {
  206. executables = append(executables, "hg")
  207. } else if isDir(".git") {
  208. executables = append(executables, "git")
  209. } else {
  210. log.Fatalf("[ERROR] neither .hg or .git was found (needed for changelog)\n")
  211. }
  212. for i := 0; i < len(executables); i++ {
  213. _, e := exec.LookPath(executables[i])
  214. if e != nil {
  215. log.Fatalf("[ERROR] missing: %s\n", executables[i])
  216. }
  217. }
  218. }
  219. // build target
  220. func buildDoFirst() {
  221. clean = false // just in case
  222. output = "gd"
  223. }
  224. // install target
  225. func installDoFirst() {
  226. var tmp, name, home, gobin string
  227. home = os.Getenv("HOME")
  228. if home == "" {
  229. home = os.Getenv("USERDIR")
  230. }
  231. if home != "" {
  232. tmp = filepath.Join(home, "bin")
  233. if isDir(tmp) {
  234. name = filepath.Join(tmp, "gd")
  235. }
  236. }
  237. if name == "" {
  238. gobin = os.Getenv("GOBIN")
  239. if gobin == "" {
  240. name = filepath.Join(runtime.GOROOT(),"bin","gd")
  241. }else{
  242. name = filepath.Join(gobin,"gd")
  243. }
  244. }
  245. output = name
  246. }
  247. // needed for stdlib, testok targets
  248. var golibs = []string{
  249. "archive",
  250. "compress",
  251. "container",
  252. "flag",
  253. "html",
  254. "http",
  255. "image",
  256. "patch",
  257. "rpc",
  258. "strconv",
  259. "tabwriter",
  260. "template",
  261. "io",
  262. "text",
  263. "regexp",
  264. // packages above this line cannot be tested without modification
  265. "asn1",
  266. "bufio",
  267. "cmath",
  268. "csv",
  269. "ebnf",
  270. "expvar",
  271. "fmt",
  272. "gob",
  273. "index",
  274. "json",
  275. "log",
  276. "mail",
  277. "netchan",
  278. "rand",
  279. "reflect",
  280. "scanner",
  281. "smtp",
  282. "sort",
  283. "syslog",
  284. "testing",
  285. "try",
  286. "unicode",
  287. "unsafe",
  288. "utf16",
  289. "utf8",
  290. "websocket",
  291. "xml",
  292. }
  293. // testok target
  294. func testokDoFirst() {
  295. say.Printf("[ testok ] ")
  296. goroot := os.Getenv("GOROOT")
  297. if goroot == "" {
  298. goroot = runtime.GOROOT()
  299. }
  300. dirReq := func(s string) bool { return true }
  301. fileReq := func(s string) bool {
  302. return strings.HasSuffix(s, ".go")
  303. }
  304. from := filepath.Join(goroot, "src", "pkg")
  305. to := fmt.Sprintf("tmp-pkgroot-%d", time.Now().Unix())
  306. say.Printf("testable part of stdlib -> %s\n", to)
  307. testable := golibs[15:]
  308. for i := 0; i < len(testable); i++ {
  309. recCopyStrip(filepath.Join(from, testable[i]),
  310. filepath.Join(to, testable[i]),
  311. fileReq, dirReq)
  312. }
  313. os.Exit(0)
  314. }
  315. // stdlib target
  316. func stdlibDoFirst() {
  317. say.Printf("[ stdlib ] ")
  318. goroot := os.Getenv("GOROOT")
  319. if goroot == "" {
  320. goroot = runtime.GOROOT()
  321. }
  322. dirReq := func(s string) bool {
  323. return s != "testdata"
  324. }
  325. fileReq := func(s string) bool {
  326. return strings.HasSuffix(s, ".go") && !strings.HasSuffix(s, "_test.go")
  327. }
  328. from := filepath.Join(goroot, "src", "pkg")
  329. to := fmt.Sprintf("tmp-pkgroot-%d", time.Now().Unix())
  330. say.Printf("pure go part of stdlib -> %s\n", to)
  331. for i := 0; i < len(golibs); i++ {
  332. recCopyStrip(filepath.Join(from, golibs[i]),
  333. filepath.Join(to, golibs[i]),
  334. fileReq, dirReq)
  335. }
  336. os.Exit(0)
  337. }
  338. // recursive copy that strips away main packages + testdata
  339. func recCopyStrip(from, to string, fileReq, dirReq func(s string) bool) {
  340. if !isDir(from) {
  341. return
  342. }
  343. if !isDir(to) {
  344. e := os.MkdirAll(to, 0777)
  345. quitter(e)
  346. }
  347. fromFile, e := os.Open(from)
  348. quitter(e)
  349. defer fromFile.Close()
  350. dirnames, e := fromFile.Readdirnames(-1)
  351. quitter(e)
  352. for i := 0; i < len(dirnames); i++ {
  353. next := filepath.Join(from, dirnames[i])
  354. if isFile(next) && fileReq(next) {
  355. copyGzip(next, filepath.Join(to, dirnames[i]), false)
  356. }
  357. if isDir(next) && dirReq(dirnames[i]) {
  358. recCopyStrip(next, filepath.Join(to, dirnames[i]), fileReq, dirReq)
  359. }
  360. }
  361. }
  362. // clean target
  363. func cleanDoFirst() {
  364. delete(packages)
  365. os.Exit(0)
  366. }
  367. // uninstall target
  368. func uninstallDoFirst() {
  369. delete(packages)
  370. p1 := filepath.Join(os.Getenv("GOBIN"), "gd")
  371. if isFile(p1) {
  372. say.Printf("rm: %s\n", p1)
  373. e := os.Remove(p1)
  374. quitter(e)
  375. }
  376. p2 := filepath.Join(os.Getenv("HOME"), "bin", "gd")
  377. if isFile(p2) {
  378. say.Printf("rm: %s\n", p2)
  379. e := os.Remove(p2)
  380. quitter(e)
  381. }
  382. os.Exit(0)
  383. }
  384. // hgup
  385. func releaseDoFirst() {
  386. goroot := os.Getenv("GOROOT")
  387. if goroot == "" {
  388. goroot = runtime.GOROOT()
  389. }
  390. srcdir := filepath.Join(goroot, "src")
  391. say.Printf("> \u001B[32mcd $GOROOT/src\u001B[0m\n")
  392. e := os.Chdir(srcdir)
  393. quitter(e)
  394. current, e := exec.Command("hg", "id", "-i").CombinedOutput()
  395. quitter(e)
  396. say.Println("> \u001B[32mhg pull\u001B[0m")
  397. run([]string{"hg", "pull"})
  398. say.Println("> \u001B[32mhg update release\u001B[0m")
  399. run([]string{"hg", "update", "release"})
  400. updated, e := exec.Command("hg", "id", "-i").CombinedOutput()
  401. if e != nil {
  402. log.Fatalf("[ERROR] %s\n", e)
  403. }
  404. if string(current) != string(updated) {
  405. say.Println("> \u001B[32mbash make.bash\u001B[0m")
  406. run([]string{"bash", "make.bash"})
  407. } else {
  408. say.Println("[\u001B[32m already at release version\u001B[0m ]")
  409. }
  410. os.Exit(0)
  411. }
  412. // PLAYGROUND STOP
  413. //-------------------------------------------------------------------
  414. // Execute user defined targets
  415. //-------------------------------------------------------------------
  416. func doFirst() {
  417. args := flag.Args()
  418. for i := 0; i < len(args); i++ {
  419. target, ok := targets[args[i]]
  420. if ok && target.first != nil {
  421. target.first()
  422. }
  423. }
  424. }
  425. func doLast() {
  426. args := flag.Args()
  427. for i := 0; i < len(args); i++ {
  428. target, ok := targets[args[i]]
  429. if ok && target.last != nil {
  430. target.last()
  431. }
  432. }
  433. }
  434. //-------------------------------------------------------------------
  435. // Simple way to turn print statements on/off
  436. //-------------------------------------------------------------------
  437. type Say bool
  438. func (s Say) Printf(frmt string, args ...interface{}) {
  439. if bool(s) {
  440. fmt.Printf(frmt, args...)
  441. }
  442. }
  443. func (s Say) Println(args ...interface{}) {
  444. if bool(s) {
  445. fmt.Println(args...)
  446. }
  447. }
  448. //-------------------------------------------------------------------
  449. // Initialize variables, flags and so on
  450. //-------------------------------------------------------------------
  451. var (
  452. compiler = ""
  453. linker = ""
  454. suffix = ""
  455. backend = ""
  456. root = ""
  457. output = ""
  458. match = ""
  459. help = false
  460. list = false
  461. quiet = false
  462. external = false
  463. clean = false
  464. oldPkgFound = false
  465. )
  466. var includeDir = "_obj"
  467. var say = Say(true)
  468. func init() {
  469. flag.StringVar(&backend, "backend", "gc", "select from [gc,gccgo,express]")
  470. flag.StringVar(&backend, "B", "gc", "alias for --backend option")
  471. flag.StringVar(&root, "I", "", "import package directory")
  472. flag.StringVar(&match, "M", "", "regex to match main package")
  473. flag.StringVar(&match, "main", "", "regex to match main package")
  474. flag.StringVar(&output, "o", "", "link main package -> output")
  475. flag.StringVar(&output, "output", "", "link main package -> output")
  476. flag.BoolVar(&external, "external", false, "external dependencies")
  477. flag.BoolVar(&external, "e", false, "external dependencies")
  478. flag.BoolVar(&quiet, "q", false, "don't print anything but errors")
  479. flag.BoolVar(&quiet, "quiet", false, "don't print anything but errors")
  480. flag.BoolVar(&help, "h", false, "help message")
  481. flag.BoolVar(&help, "help", false, "help message")
  482. flag.BoolVar(&clean, "clean", false, "delete objects")
  483. flag.BoolVar(&clean, "c", false, "delete objects")
  484. flag.BoolVar(&list, "list", false, "list targets for bash autocomplete")
  485. flag.Usage = func() {
  486. fmt.Println("\n mk.go - makefile in pure go\n")
  487. fmt.Println(" usage: go run mk.go [OPTIONS] [TARGET]\n")
  488. fmt.Println(" options:\n")
  489. fmt.Println(" -h --help print this menu and exit")
  490. fmt.Println(" -B --backend choose backend [gc,gccgo,express]")
  491. fmt.Println(" -o --output link main package -> output")
  492. fmt.Println(" -M --main regex to match main package")
  493. fmt.Println(" -c --clean delete object files")
  494. fmt.Println(" -q --quiet quiet unless errors occur")
  495. fmt.Println(" -e --external go install external dependencies")
  496. fmt.Println(" -I import package directory\n")
  497. if len(targets) > 0 {
  498. fmt.Println(" targets:\n")
  499. for k, v := range targets {
  500. fmt.Printf(" %-11s => %s\n", k, v.desc)
  501. }
  502. fmt.Println("")
  503. }
  504. }
  505. }
  506. func initBackend() {
  507. switch backend {
  508. case "gc":
  509. n := archNum()
  510. compiler, linker, suffix = n+"g", n+"l", "."+n
  511. case "gccgo", "gcc":
  512. compiler, linker, suffix = "gccgo", "gccgo", ".o"
  513. backend = "gccgo"
  514. case "express":
  515. compiler, linker, suffix = "vmgc", "vmld", ".vmo"
  516. default:
  517. log.Fatalf("[ERROR] unknown backend: %s\n", backend)
  518. }
  519. if backend == "gc" {
  520. goroot := GOROOT()
  521. goos := GOOS()
  522. goarch := GOARCH()
  523. stub := goos + "_" + goarch
  524. compiler = filepath.Join(goroot,"pkg","tool", stub ,compiler)
  525. linker = filepath.Join(goroot,"pkg","tool", stub ,linker)
  526. }
  527. }
  528. func archNum() (n string) {
  529. goarch := os.Getenv("GOARCH")
  530. if goarch == "" {
  531. goarch = runtime.GOARCH
  532. }
  533. switch goarch {
  534. case "386":
  535. n = "8"
  536. case "arm":
  537. n = "5"
  538. case "amd64":
  539. n = "6"
  540. default:
  541. log.Fatalf("[ERROR] unknown GOARCH: %s\n", goarch)
  542. }
  543. return
  544. }
  545. //-------------------------------------------------------------------
  546. // External dependencies
  547. //-------------------------------------------------------------------
  548. var alien = []string{}
  549. //-------------------------------------------------------------------
  550. // Functions to build/delete project
  551. //-------------------------------------------------------------------
  552. func osify(pkgs []*Package) {
  553. for j := 0; j < len(pkgs); j++ {
  554. if pkgs[j].osified {
  555. break
  556. }
  557. pkgs[j].osified = true
  558. pkgs[j].output = filepath.FromSlash(pkgs[j].output) + suffix
  559. for i := 0; i < len(pkgs[j].files); i++ {
  560. pkgs[j].files[i] = filepath.FromSlash(pkgs[j].files[i])
  561. }
  562. }
  563. }
  564. func mkdirs(pkgs []*Package) {
  565. for i := 0; i < len(pkgs); i++ {
  566. d, _ := filepath.Split(pkgs[i].output)
  567. if d != "" && !isDir(d) {
  568. e := os.MkdirAll(d, 0777)
  569. if e != nil {
  570. log.Fatalf("[ERROR] %s\n", e)
  571. }
  572. }
  573. }
  574. }
  575. func compile(pkgs []*Package) {
  576. osify(pkgs)
  577. mkdirs(pkgs)
  578. for i := 0; i < len(pkgs); i++ {
  579. if oldPkgFound || !pkgs[i].up2date() {
  580. say.Printf("compiling: %s\n", pkgs[i].full)
  581. pkgs[i].compile()
  582. oldPkgFound = true
  583. } else {
  584. say.Printf("up 2 date: %s\n", pkgs[i].full)
  585. }
  586. }
  587. }
  588. func delete(pkgs []*Package) {
  589. osify(pkgs)
  590. for j := 0; j < len(pkgs); j++ {
  591. if isFile(pkgs[j].output) {
  592. say.Printf("rm: %s\n", pkgs[j].output)
  593. e := os.Remove(pkgs[j].output)
  594. if e != nil {
  595. log.Fatalf("[ERROR] failed to remove: %s\n", pkgs[j].output)
  596. }
  597. }
  598. }
  599. if emptyDir(includeDir){
  600. say.Printf("rm: %s\n", includeDir)
  601. e := os.RemoveAll(includeDir)
  602. if e != nil {
  603. log.Fatalf("[ERROR] failed to remove: %s\n", includeDir)
  604. }
  605. }
  606. }
  607. func link(pkgs []*Package) {
  608. if output == "" {
  609. return
  610. }
  611. var mainPackage *Package
  612. var mainPkgs = make([]*Package, 0)
  613. for i := 0; i < len(pkgs); i++ {
  614. if pkgs[i].name == "main" {
  615. mainPkgs = append(mainPkgs, pkgs[i])
  616. mainPackage = pkgs[i]
  617. }
  618. }
  619. switch len(mainPkgs) {
  620. case 0:
  621. log.Fatalf("[ERROR] no main package found\n")
  622. case 1: // do nothing... this is good
  623. default:
  624. mainPackage = mainChoice(mainPkgs)
  625. }
  626. if !oldPkgFound && isFile(output) {
  627. pkgLastTs, _ := timestamp(pkgs[len(pkgs)-1].output)
  628. outputTs, ok := timestamp(output)
  629. if ok && outputTs > pkgLastTs {
  630. say.Printf("up 2 date: %s\n", output)
  631. return
  632. }
  633. }
  634. say.Printf("linking : %s\n", output)
  635. argv := make([]string, 0)
  636. argv = append(argv, linker)
  637. if backend != "gccgo" {
  638. argv = append(argv, "-L")
  639. argv = append(argv, includeDir)
  640. if root != "" {
  641. argv = append(argv, "-L")
  642. argv = append(argv, root)
  643. }
  644. // GOPATH
  645. gopathInc := gopathDirs()
  646. if len(gopathInc) > 0 {
  647. for i := 0; i < len(gopathInc); i++ {
  648. argv = append(argv, "-L")
  649. argv = append(argv, gopathInc[i])
  650. }
  651. }
  652. }
  653. argv = append(argv, "-o")
  654. argv = append(argv, output)
  655. if backend == "gccgo" {
  656. for i := 0; i < len(pkgs); i++ {
  657. argv = append(argv, pkgs[i].output)
  658. }
  659. if root != "" {
  660. filter := func(s string) bool {
  661. return strings.HasSuffix(s, ".o")
  662. }
  663. files := PathWalk(root, filter)
  664. for i := 0; i < len(files); i++ {
  665. argv = append(argv, files[i])
  666. }
  667. }
  668. }else{
  669. argv = append(argv, mainPackage.output)
  670. }
  671. run(argv)
  672. }
  673. func mainChoice(pkgs []*Package) *Package {
  674. var cnt, choice int
  675. for i := 0; i < len(pkgs); i++ {
  676. ok, _ := regexp.MatchString(match, pkgs[i].full)
  677. if ok {
  678. cnt++
  679. choice = i
  680. }
  681. }
  682. if cnt == 1 {
  683. return pkgs[choice]
  684. }
  685. fmt.Println("\n More than one main package found\n")
  686. for i := 0; i < len(pkgs); i++ {
  687. fmt.Printf(" type %2d for: %s\n", i, pkgs[i].full)
  688. }
  689. fmt.Printf("\n type your choice: ")
  690. n, e := fmt.Scanf("%d", &choice)
  691. if e != nil {
  692. log.Fatalf("%s\n", e)
  693. }
  694. if n != 1 {
  695. log.Fatal("failed to read input\n")
  696. }
  697. if choice >= len(pkgs) || choice < 0 {
  698. log.Fatalf(" bad choice: %d\n", choice)
  699. }
  700. fmt.Printf(" chosen main-package: %s\n\n", pkgs[choice].full)
  701. return pkgs[choice]
  702. }
  703. func goinstall() {
  704. argv := make([]string, 5)
  705. argv[0] = "go"
  706. argv[1] = "get"
  707. argv[2] = "-u"
  708. argv[3] = "-a"
  709. for i := 0; i < len(alien); i++ {
  710. say.Printf("go get: %s\n", alien[i])
  711. argv[4] = alien[i]
  712. run(argv)
  713. }
  714. }
  715. //-------------------------------------------------------------------
  716. // Utility types and functions
  717. //-------------------------------------------------------------------
  718. func PathWalk(root string, ok func(s string)bool) (files []string) {
  719. fn := func(p string, d os.FileInfo, e error) error{
  720. if !d.IsDir() && ok(p) {
  721. files = append(files, p)
  722. }
  723. return e
  724. }
  725. filepath.Walk(root, fn)
  726. return files
  727. }
  728. func emptyDir(pathname string) bool {
  729. if ! isDir(pathname) {
  730. return false
  731. }
  732. fn := func(s string)bool{ return true }
  733. return len(PathWalk(pathname, fn)) == 0
  734. }
  735. func isDir(pathname string) bool {
  736. fileInfo, err := os.Stat(pathname)
  737. if err == nil && fileInfo.IsDir() {
  738. return true
  739. }
  740. return false
  741. }
  742. func timestamp(s string) (int64, bool) {
  743. fileInfo, e := os.Stat(s)
  744. if e == nil {
  745. return fileInfo.ModTime().UnixNano(), true
  746. }
  747. return 0, false
  748. }
  749. func run(argv []string) {
  750. cmd := exec.Command(argv[0], argv[1:]...)
  751. // pass-through
  752. cmd.Stdout = os.Stdout
  753. cmd.Stderr = os.Stderr
  754. cmd.Stdin = os.Stdin
  755. err := cmd.Start()
  756. if err != nil {
  757. log.Fatalf("[ERROR] %s\n", err)
  758. }
  759. err = cmd.Wait()
  760. if err != nil {
  761. log.Fatalf("[ERROR] %s\n", err)
  762. }
  763. }
  764. func isFile(pathname string) bool {
  765. fileInfo, err := os.Stat(pathname)
  766. if err == nil {
  767. if fileInfo.Mode() & os.ModeType != 0 {
  768. return false
  769. }
  770. return true
  771. }
  772. return false
  773. }
  774. func quitter(e error) {
  775. if e != nil {
  776. log.Fatalf("[ERROR] %s\n", e)
  777. }
  778. }
  779. func copyGzipStringBuffer(from string, to string, gzipFile bool) {
  780. buf := bytes.NewBufferString(from)
  781. copyGzipReader(buf, to, gzipFile)
  782. }
  783. func copyGzipByteBuffer(from []byte, to string, gzipFile bool){
  784. buf := bytes.NewBuffer(from)
  785. copyGzipReader(buf, to, gzipFile)
  786. }
  787. func copyGzip(from, to string, gzipFile bool) {
  788. var err error
  789. var fromFile *os.File
  790. fromFile, err = os.Open(from)
  791. quitter(err)
  792. defer fromFile.Close()
  793. copyGzipReader(fromFile, to, gzipFile)
  794. }
  795. func copyGzipReader(fromReader io.Reader, to string, gzipFile bool) {
  796. var err error
  797. var toFile io.WriteCloser
  798. toFile, err = os.Create(to)
  799. quitter(err)
  800. if gzipFile {
  801. toFile, err = gzip.NewWriterLevel(toFile, gzip.BestCompression)
  802. quitter(err)
  803. }
  804. defer toFile.Close()
  805. _, err = io.Copy(toFile, fromReader)
  806. quitter(err)
  807. }
  808. func gopathDirs() (paths []string) {
  809. var(
  810. stub string
  811. gopath []string
  812. )
  813. gopath = GOPATH()
  814. if len(gopath) > 0 {
  815. if backend == "gc" {
  816. stub = GOOS() + "_" + GOARCH()
  817. }else{
  818. stub = "gccgo"
  819. }// should do something for express later perhaps
  820. for _, gp := range gopath {
  821. paths = append(paths, filepath.Join(gp, "pkg", stub))
  822. }
  823. }
  824. return
  825. }
  826. func GOPATH() (gp []string) {
  827. p := os.Getenv("GOPATH")
  828. if p != "" {
  829. gp = strings.Split(p, string(os.PathListSeparator))
  830. }
  831. return
  832. }
  833. func GOROOT() (r string) {
  834. r = os.Getenv("GOROOT")
  835. if r == "" {
  836. r = runtime.GOROOT()
  837. }
  838. return
  839. }
  840. func GOARCH() (a string) {
  841. a = os.Getenv("GOARCH")
  842. if a == "" {
  843. a = runtime.GOARCH
  844. }
  845. return
  846. }
  847. func GOOS() (o string) {
  848. o = os.Getenv("GOOS")
  849. if o == "" {
  850. o = runtime.GOOS
  851. }
  852. return
  853. }
  854. //-------------------------------------------------------------------
  855. // Package definition
  856. //-------------------------------------------------------------------
  857. type Package struct {
  858. name, full, output string
  859. osified bool
  860. files []string
  861. }
  862. func (p *Package) up2date() bool {
  863. mtime, ok := timestamp(p.output)
  864. if !ok {
  865. return false
  866. }
  867. for i := 0; i < len(p.files); i++ {
  868. fmtime, ok := timestamp(p.files[i])
  869. if !ok {
  870. log.Fatalf("file missing: %s\n", p.files[i])
  871. }
  872. if fmtime > mtime {
  873. return false
  874. }
  875. }
  876. return true
  877. }
  878. func (p *Package) compile() {
  879. argv := make([]string, 0)
  880. argv = append(argv, compiler)
  881. argv = append(argv, "-I")
  882. argv = append(argv, includeDir)
  883. // GOPATH
  884. gopathInc := gopathDirs()
  885. if len(gopathInc) > 0 {
  886. for i := 0; i < len(gopathInc); i++ {
  887. argv = append(argv, "-I")
  888. argv = append(argv, gopathInc[i])
  889. }
  890. }
  891. if root != "" {
  892. argv = append(argv, "-I")
  893. argv = append(argv, root)
  894. }
  895. if backend == "gccgo" {
  896. argv = append(argv, "-c")
  897. }
  898. argv = append(argv, "-o")
  899. argv = append(argv, p.output)
  900. argv = append(argv, p.files...)
  901. run(argv)
  902. }
  903. //-------------------------------------------------------------------
  904. // Package info collected by godag
  905. //-------------------------------------------------------------------
  906. var packages = []*Package{
  907. &Package{
  908. name: "stringbuffer",
  909. full: "utilz/stringbuffer",
  910. output: "_obj/utilz/stringbuffer",
  911. files: []string{"src/utilz/stringbuffer.go"},
  912. },
  913. &Package{
  914. name: "walker",
  915. full: "utilz/walker",
  916. output: "_obj/utilz/walker",
  917. files: []string{"src/utilz/walker.go"},
  918. },
  919. &Package{
  920. name: "stringset",
  921. full: "utilz/stringset",
  922. output: "_obj/utilz/stringset",
  923. files: []string{"src/utilz/stringset.go"},
  924. },
  925. &Package{
  926. name: "global",
  927. full: "utilz/global",
  928. output: "_obj/utilz/global",
  929. files: []string{"src/utilz/global.go"},
  930. },
  931. &Package{
  932. name: "handy",
  933. full: "utilz/handy",
  934. output: "_obj/utilz/handy",
  935. files: []string{"src/utilz/handy.go"},
  936. },
  937. &Package{
  938. name: "say",
  939. full: "utilz/say",
  940. output: "_obj/utilz/say",
  941. files: []string{"src/utilz/say.go"},
  942. },
  943. &Package{
  944. name: "timer",
  945. full: "utilz/timer",
  946. output: "_obj/utilz/timer",
  947. files: []string{"src/utilz/timer.go"},
  948. },
  949. &Package{
  950. name: "gopt",
  951. full: "parse/gopt",
  952. output: "_obj/parse/gopt",
  953. files: []string{"src/parse/gopt.go","src/parse/option.go"},
  954. },
  955. &Package{
  956. name: "dag",
  957. full: "cmplr/dag",
  958. output: "_obj/cmplr/dag",
  959. files: []string{"src/cmplr/dag.go"},
  960. },
  961. &Package{
  962. name: "gdmake",
  963. full: "cmplr/gdmake",
  964. output: "_obj/cmplr/gdmake",
  965. files: []string{"src/cmplr/gdmake.go"},
  966. },
  967. &Package{
  968. name: "compiler",
  969. full: "cmplr/compiler",
  970. output: "_obj/cmplr/compiler",
  971. files: []string{"src/cmplr/compiler.go"},
  972. },
  973. &Package{
  974. name: "main",
  975. full: "start/main",
  976. output: "_obj/start/main",
  977. files: []string{"src/start/main.go"},
  978. },
  979. }
  980. //-------------------------------------------------------------------
  981. // Main - note flags are parsed before we doFirst, i.e. command line
  982. // options/arguments can be overridden in doFirst targets
  983. //-------------------------------------------------------------------
  984. func main() {
  985. flag.Parse()
  986. initBackend() // gc/gcc/express
  987. if quiet {
  988. say = Say(false)
  989. }
  990. doFirst()
  991. defer doLast()
  992. switch {
  993. case help:
  994. flag.Usage()
  995. case clean:
  996. delete(packages)
  997. case external:
  998. goinstall()
  999. default:
  1000. compile(packages)
  1001. link(packages)
  1002. }
  1003. }