Example #1
0
func TestAllTheThings(t *testing.T) {
	perm := os.FileMode(0777)
	workingDir, err := ioutil.TempDir("", "butler-tests")
	mist(t, err)
	defer os.RemoveAll(workingDir)

	sample := path.Join(workingDir, "sample")
	mist(t, os.MkdirAll(sample, perm))
	mist(t, ioutil.WriteFile(path.Join(sample, "hello.txt"), []byte("hello!"), perm))

	sample2 := path.Join(workingDir, "sample2")
	mist(t, os.MkdirAll(sample2, perm))
	for i := 0; i < 5; i++ {
		if i == 3 {
			// e.g. .gitkeep
			putfile(t, sample2, i, []byte{})
		} else {
			putfile(t, sample2, i, bytes.Repeat([]byte{0x42, 0x69}, i*200+1))
		}
	}

	sample3 := path.Join(workingDir, "sample3")
	mist(t, os.MkdirAll(sample3, perm))
	for i := 0; i < 60; i++ {
		putfile(t, sample3, i, bytes.Repeat([]byte{0x42, 0x69}, i*300+1))
	}

	sample4 := path.Join(workingDir, "sample4")
	mist(t, os.MkdirAll(sample4, perm))
	for i := 0; i < 120; i++ {
		putfile(t, sample4, i, bytes.Repeat([]byte{0x42, 0x69}, i*150+1))
	}

	sample5 := path.Join(workingDir, "sample5")
	mist(t, os.MkdirAll(sample5, perm))
	rg := rand.New(rand.NewSource(0x239487))

	for i := 0; i < 25; i++ {
		l := 1024 * (i + 2)
		// our own little twist on fizzbuzz to look out for 1-off errors
		if i%5 == 0 {
			l = int(pwr.BlockSize)
		} else if i%3 == 0 {
			l = 0
		}

		buf := make([]byte, l)
		_, err := io.CopyN(bytes.NewBuffer(buf), rg, int64(l))
		mist(t, err)
		putfile(t, sample5, i, buf)
	}

	files := map[string]string{
		"hello":     sample,
		"80-fixed":  sample2,
		"60-fixed":  sample3,
		"120-fixed": sample4,
		"random":    sample5,
		"null":      "/dev/null",
	}

	patch := path.Join(workingDir, "patch.pwr")

	comm.Configure(true, true, false, false, false, false, false)

	for _, q := range []int{1, 9} {
		t.Logf("============ Quality %d ============", q)
		compression := pwr.CompressionSettings{
			Algorithm: pwr.CompressionAlgorithm_BROTLI,
			Quality:   int32(q),
		}

		for lhs := range files {
			for rhs := range files {
				mist(t, doDiff(files[lhs], files[rhs], patch, compression))
				stat, err := os.Lstat(patch)
				mist(t, err)
				t.Logf("%10s -> %10s = %s", lhs, rhs, humanize.IBytes(uint64(stat.Size())))
			}
		}
	}

	compression := pwr.CompressionSettings{
		Algorithm: pwr.CompressionAlgorithm_BROTLI,
		Quality:   1,
	}

	for _, filepath := range files {
		t.Logf("Signing %s\n", filepath)

		sigPath := path.Join(workingDir, "signature.pwr.sig")
		mist(t, doSign(filepath, sigPath, compression, false))

		sigReader, err := eos.Open(sigPath)
		mist(t, err)

		signature, err := pwr.ReadSignature(sigReader)
		mist(t, err)

		mist(t, sigReader.Close())

		validator := &pwr.ValidatorContext{
			FailFast: true,
		}

		mist(t, validator.Validate(filepath, signature))
	}

	// K windows you just sit this one out we'll catch you on the flip side
	if runtime.GOOS != "windows" {
		// In-place preserve permissions tests
		t.Logf("In-place patching should preserve permissions")

		eperm := os.FileMode(0750)

		samplePerm1 := path.Join(workingDir, "samplePerm1")
		mist(t, os.MkdirAll(samplePerm1, perm))
		putfileEx(t, samplePerm1, 1, bytes.Repeat([]byte{0x42, 0x69}, 8192), eperm)

		assert.Equal(t, octal(eperm), octal(permFor(t, path.Join(samplePerm1, "dummy1.dat"))))

		samplePerm2 := path.Join(workingDir, "samplePerm2")
		mist(t, os.MkdirAll(samplePerm2, perm))
		putfileEx(t, samplePerm2, 1, bytes.Repeat([]byte{0x69, 0x42}, 16384), eperm)

		assert.Equal(t, octal(eperm), octal(permFor(t, path.Join(samplePerm2, "dummy1.dat"))))

		mist(t, doDiff(samplePerm1, samplePerm2, patch, compression))
		_, err := os.Lstat(patch)
		mist(t, err)

		cave := path.Join(workingDir, "cave")
		ditto(samplePerm1, cave)

		mist(t, doApply(patch, cave, cave, true, "", ""))
		assert.Equal(t, octal(eperm|pwr.ModeMask), octal(permFor(t, path.Join(cave, "dummy1.dat"))))
	}
}
Example #2
0
func main() {
	app.UsageTemplate(kingpin.CompactUsageTemplate)
	app.Flag("ignore", "Glob patterns of files to ignore when diffing").StringsVar(&ignoredPaths)

	app.HelpFlag.Short('h')
	if builtAt != "" {
		epoch, err := strconv.ParseInt(builtAt, 10, 64)
		must(err)
		versionString = fmt.Sprintf("%s, built on %s", version, time.Unix(epoch, 0).Format("Jan _2 2006 @ 15:04:05"))
	} else {
		versionString = fmt.Sprintf("%s, no build date", version)
	}
	if commit != "" {
		versionString = fmt.Sprintf("%s, ref %s", versionString, commit)
	}
	app.Version(versionString)
	app.VersionFlag.Short('V')
	app.Author("Amos Wenger <*****@*****.**>")

	cmd, err := app.Parse(os.Args[1:])
	if err != nil {
		ctx, _ := app.ParseContext(os.Args[1:])
		app.FatalUsageContext(ctx, "%s\n", err.Error())
	}

	if *appArgs.timestamps {
		log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
	} else {
		log.SetFlags(0)
	}
	log.SetOutput(os.Stdout)

	eos.RegisterHandler(&itchfs.ItchFS{
		ItchServer: *appArgs.address,
	})

	if *appArgs.quiet {
		*appArgs.noProgress = true
		*appArgs.verbose = false
	}

	if !isTerminal() {
		*appArgs.noProgress = true
	}
	comm.Configure(*appArgs.noProgress, *appArgs.quiet, *appArgs.verbose, *appArgs.json, *appArgs.panic, *appArgs.assumeYes, *appArgs.beeps4Life)
	if !isTerminal() {
		comm.Debug("Not a terminal, disabling progress indicator")
	}

	setupHTTPDebug()

	if *appArgs.cpuprofile != "" {
		f, err := os.Create(*appArgs.cpuprofile)
		if err != nil {
			log.Fatal(err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	switch kingpin.MustParse(cmd, err) {
	case dlCmd.FullCommand():
		dl(*dlArgs.url, *dlArgs.dest)

	case cpCmd.FullCommand():
		cp(*cpArgs.src, *cpArgs.dest, *cpArgs.resume)

	case loginCmd.FullCommand():
		login()

	case logoutCmd.FullCommand():
		logout()

	case pushCmd.FullCommand():
		{
			userVersion := *pushArgs.userVersion
			if userVersion == "" && *pushArgs.userVersionFile != "" {
				buf, err := ioutil.ReadFile(*pushArgs.userVersionFile)
				must(err)
				userVersion = strings.TrimSpace(string(buf))
				if strings.ContainsAny(userVersion, "\r\n") {
					must(fmt.Errorf("%s contains line breaks, refusing to use as userversion", *pushArgs.userVersionFile))
				}
			}
			push(*pushArgs.src, *pushArgs.target, userVersion, *pushArgs.fixPerms)
		}

	case fetchCmd.FullCommand():
		fetch(*fetchArgs.target, *fetchArgs.out)

	case statusCmd.FullCommand():
		status(*statusArgs.target)

	case untarCmd.FullCommand():
		untar(*untarArgs.file, *untarArgs.dir)

	case unzipCmd.FullCommand():
		unzip(*unzipArgs.file, *unzipArgs.dir, *unzipArgs.resumeFile)

	case wipeCmd.FullCommand():
		wipe(*wipeArgs.path)

	case mkdirCmd.FullCommand():
		mkdir(*mkdirArgs.path)

	case dittoCmd.FullCommand():
		ditto(*dittoArgs.src, *dittoArgs.dst)

	case sizeofCmd.FullCommand():
		sizeof(*sizeofArgs.path)

	case diffCmd.FullCommand():
		diff(*diffArgs.old, *diffArgs.new, *diffArgs.patch, butlerCompressionSettings())

	case applyCmd.FullCommand():
		apply(*applyArgs.patch, *applyArgs.old, *applyArgs.dir, *applyArgs.inplace, *applyArgs.signature, *applyArgs.wounds)

	case verifyCmd.FullCommand():
		verify(*verifyArgs.signature, *verifyArgs.dir, *verifyArgs.wounds, *verifyArgs.heal)

	case signCmd.FullCommand():
		sign(*signArgs.output, *signArgs.signature, butlerCompressionSettings(), *signArgs.fixPerms)

	case healCmd.FullCommand():
		heal(*healArgs.dir, *healArgs.wounds, *healArgs.spec)

	case probeCmd.FullCommand():
		probe(*probeArgs.patch)

	case bsdiffCmd.FullCommand():
		cmdBsdiff(*bsdiffArgs.target, *bsdiffArgs.source, *bsdiffArgs.patch, *bsdiffArgs.concurrency, *bsdiffArgs.measureOverhead)

	case bspatchCmd.FullCommand():
		bspatch(*bspatchArgs.patch, *bspatchArgs.target, *bspatchArgs.output)

	case whichCmd.FullCommand():
		which()

	case versionCmd.FullCommand():
		log.Println(versionString)
		os.Exit(0)

	case fileCmd.FullCommand():
		file(*fileArgs.file)

	case lsCmd.FullCommand():
		ls(*lsArgs.file)

	case upgradeCmd.FullCommand():
		upgrade(*upgradeArgs.head)

	case ugpradeCmd.FullCommand():
		upgrade(*upgradeArgs.head)

	case updateCmd.FullCommand():
		upgrade(*updateArgs.head)
	}
}