Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ jobs:
- name: Package binaries
run: 'make package'
- name: Create GitHub Release
run: gh release create "v$(grep -v '#' ./VERSION)" --generate-notes --verify-tag --latest ./dist/zipped/*
run: gh release create "v$(grep -v '#' ./VERSION)" --draft --generate-notes --verify-tag --latest ./dist/compressed/*
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
*.log
*.out
*cache*
!internal/archive/cache
!internal/archive/cache/**
build/
deps/
16 changes: 11 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ all: ci package package-debian

ci: clean
@bash ./scripts/ci.sh
@make -s clean

# test is just an alias for ci
test: ci
Expand Down Expand Up @@ -38,15 +39,14 @@ clean:
*cache* \
.*cache* \
./build/ \
./dist/zipped/*.tar.gz \
./dist/zipped/*.zip \
./dist/compressed/*.tar.gz \
./dist/compressed/*.zip \
./dist/debian/vdm.deb \
*.out
@sudo rm -rf ./dist/debian/vdm/usr
# TODO: until I sort out the tests to write test data consistently, these deps/
# directories etc. can kind of show up anywhere
# TODO: until I (maybe) sort out the tests to write test data consistently,
# these deps/ directories etc. can kind of show up anywhere
@find . -type d -name '*deps*' -exec rm -rf {} +
@find . -type f -name '*VDMMETA*' -delete

bump-versions: clean
@bash ./scripts/bump-versions.sh "$${old_version:-}"
Expand All @@ -63,3 +63,9 @@ add-local-symlinks:
@mkdir -p "$${HOME}"/.local/bin
@ln -fs $$(realpath build/$$(go env GOOS)-$$(go env GOARCH)/$(BINNAME)) "$${HOME}"/.local/bin/$(BINNAME)
@printf 'Symlinked vdm to %s\n' "$${HOME}"/.local/bin/$(BINNAME)

install:
@go install ./...

docs:
@go run golang.org/x/pkgsite/cmd/pkgsite@latest -open .
58 changes: 25 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ retrieve them whenever you need them.
### Installation

`vdm` can be installed from [its GitHub Releases
page](https://github.com/opensourcecorp/vdm/releases). There is a zipped binary
for major platforms & architectures, and those are indicated in the Asset file
name. For example, if you have an M2 macOS laptop, you would download the
page](https://github.com/opensourcecorp/vdm/releases). There is a compressed
binary for major platforms & architectures, and those are indicated in the Asset
file name. For example, if you have an M2 macOS laptop, you would download the
`vdm_darwin-arm64.tar.gz` file, and extract it to somewhere on your `$PATH`.

If you have a recent version of the Go toolchain available, you can also install
Expand All @@ -43,50 +43,52 @@ go run github.com/opensourcecorp/vdm@<vX.Y.Z|latest> ...

### Usage

To get started, you'll need a `vdm` spec file, which is just a YAML (or JSON)
To get started, you'll need a `vdm` specfile, which is just a YAML (or JSON)
file specifying all your external dependencies along with (usually) their
revisions & where you want them to live on your filesystem:

```yaml
remotes:

- type: "git" # the default, and so can be omitted if desired
remote: "https://github.com/opensourcecorp/go-common" # can specify as 'git@...' to use SSH instead
local_path: "./deps/go-common"
version: "v0.2.0" # tag example; can also be a branch, commit hash, or the word 'latest'
- type: "git"
source: "https://github.com/opensourcecorp/vdm" # can specify the protocol in any way that you would usually run 'git clone'
version: "v0.2.0" # tag example; can also be a branch, a commit hash, or anything else supported by 'git checkout'
destination: "./deps/" # git types are themselves directories, so to prevent duplicating their top-level names you probably want to just specify the root destination

- type: "file" # the 'file' type assumes the version is in the remote field itself somehow, so 'version' can be omitted
remote: "https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto"
local_path: "./deps/proto/http/http.proto"
- type: "git"
source: "https://github.com/opensourcecorp/osc-infra"
version: "main"
destination: "./deps/"
```

You can have as many dependency specifications in that array as you want, and
they can be stored wherever you want. By default, this spec file is called
they can be stored wherever you want. By default, this specfile is called
`vdm.yaml` and lives at the calling location (which is probably your repo's
root), but you can call it whatever you want and point to it using the
`--spec-file` flag to `vdm`.
`--specfile|-f` flag to `vdm`.

Once you have a spec file, just run:
Once you have a specfile, just run:

```sh
vdm sync
```

and `vdm` will process the spec file, retrieve your dependencies as specified,
and put them where you told them to go. By default, `vdm sync` also removes the
local `.git` directories for each `git` remote, so as to not upset your local
Git tree. If you want to change the version/revision of a remote, just update
your spec file and run `vdm sync` again.
and `vdm` will process the specfile, retrieve your dependencies as specified,
and put them where you told them to go. `vdm sync` also removes the local `.git`
directories for each `git` remote, so as to not upset your local Git tree. If
you want to change the version/revision of a remote, just update your specfile
and run `vdm sync` again.

After running `vdm sync` with the above example spec file, your directory tree
After running `vdm sync` with the above example specfile, your directory tree
would look something like this:

```txt
./vdm.yaml
./deps/
go-common/
vdm/
<stuff in that repo>
osc-infra/
<stuff in that repo>
http.proto
```

## Dependencies
Expand All @@ -99,18 +101,8 @@ types. `vdm` will fail with an informative error if it can't find `git` on your

## A note about auth

`vdm` has zero goals to be an authN/authZ manager. If a remote in your spec file
`vdm` has zero goals to be an authN/authZ manager. If a remote in your specfile
depends on a certain auth setup (an SSH key, something for HTTP basic auth like
a `.netrc` file, an `.npmrc` config file, etc.), that setup is out of `vdm`'s
scope. If required, you will need to ensure proper auth is configured before
running `vdm` commands.

## Future work

- Make the sync mechanism more robust, such that if your spec file changes to
remove remotes, they'll get cleaned up automatically.

- Add `--keep-git-dir` flag so that `git` remote types don't wipe the `.git`
directory at clone-time.

- Support more than just `git` and `file` types, and make `file` better
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Version number used as an anchor for listed versions in various files in the
# tree, orchestrated by scripts/bump-versions.sh
0.2.1
0.3.0
4 changes: 1 addition & 3 deletions cmd/doc.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
/*
Package cmd calls the implementation logic for vdm.
*/
// Package cmd calls the implementation logic for vdm.
package cmd
9 changes: 5 additions & 4 deletions cmd/flagsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@ package cmd
import (
"os"

"github.com/opensourcecorp/vdm/cmd/vars"
"github.com/opensourcecorp/vdm/internal/message"
"github.com/spf13/viper"
)

// MaybeSetDebug sets the DEBUG environment variable if it was set as a flag by
// maybeSetDebug sets the DEBUG environment variable if it was set as a flag by
// the caller.
func MaybeSetDebug() {
func maybeSetDebug() {
if viper.GetBool(debugFlagKey) {
err := os.Setenv("DEBUG", "true")
err := os.Setenv(vars.Debug, "true")
if err != nil {
message.Fatalf("internal error: unable to set environment variable DEBUG")
message.Fatalf("internal error: unable to set environment variable %s", vars.Debug)
}
}
}
78 changes: 46 additions & 32 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -1,72 +1,86 @@
package cmd

import (
"errors"
"fmt"
"os"

"github.com/opensourcecorp/vdm/internal/message"
"github.com/opensourcecorp/vdm/internal/vdminit"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

// !!! DO NOT TOUCH, the version-bumper script handles updating this !!!
const vdmVersion string = "v0.2.1"

var rootCmd = cobra.Command{
Use: "vdm",
Short: "vdm -- a Versioned-Dependency Manager",
Long: "vdm is used to manage arbitrary remote dependencies",
TraverseChildren: true,
Version: vdmVersion,
Run: func(cmd *cobra.Command, args []string) {
MaybeSetDebug()
if len(args) == 0 {
err := cmd.Help()
if err != nil {
message.Fatalf("failed to print help message, somehow")
}
os.Exit(0)
}
},
}
const vdmVersion string = "v0.3.0"

// rootFlags defines the CLI flags for the root command.
type rootFlags struct {
SpecFilePath string
Debug bool
}

// RootFlagValues contains an initalized [rootFlags] struct with populated
// rootFlagValues contains an initalized [rootFlags] struct with populated
// values.
var RootFlagValues rootFlags
var rootFlagValues rootFlags

// Flag name keys
const (
specFilePathFlagKey string = "specfile-path"
specFilePathFlagKey string = "specfile"
debugFlagKey string = "debug"
)

func init() {
func newRootCommand() *cobra.Command {
var err error
cmd := &cobra.Command{
Use: "vdm",
Short: "vdm -- a Versioned-Dependency Manager",
Long: "vdm is used to manage retrieval of arbitrary remote dependencies",
TraverseChildren: true,
Version: vdmVersion,
SilenceUsage: true,
SilenceErrors: true,
RunE: executeRootCommand,
}

cmd.PersistentFlags().StringVarP(&rootFlagValues.SpecFilePath, specFilePathFlagKey, "f", "./vdm.yaml", "Path to vdm specfile")
err = viper.BindPFlag(specFilePathFlagKey, cmd.PersistentFlags().Lookup(specFilePathFlagKey))
if err != nil {
message.Fatalf("internal error: unable to bind state of flag --%s: %v", specFilePathFlagKey, err)
}

rootCmd.PersistentFlags().StringVar(&RootFlagValues.SpecFilePath, specFilePathFlagKey, "./vdm.yaml", "Path to vdm specfile")
err = viper.BindPFlag(specFilePathFlagKey, rootCmd.PersistentFlags().Lookup(specFilePathFlagKey))
cmd.PersistentFlags().BoolVar(&rootFlagValues.Debug, debugFlagKey, false, "Show debug messages during runtime")
err = viper.BindPFlag(debugFlagKey, cmd.PersistentFlags().Lookup(debugFlagKey))
if err != nil {
message.Fatalf("internal error: unable to bind state of flag --%s", specFilePathFlagKey)
message.Fatalf("internal error: unable to bind state of flag --%s: %v", debugFlagKey, err)
}

cmd.AddCommand(newSyncCommand())

return cmd
}

func executeRootCommand(cmd *cobra.Command, args []string) error {
maybeSetDebug()
if len(args) == 0 {
err := cmd.Help()
if err != nil {
return errors.New("failed to print help message, somehow")
}
}

rootCmd.PersistentFlags().BoolVar(&RootFlagValues.Debug, debugFlagKey, false, "Show debug messages during runtime")
err = viper.BindPFlag(debugFlagKey, rootCmd.PersistentFlags().Lookup(debugFlagKey))
err := vdminit.Paths()
if err != nil {
message.Fatalf("internal error: unable to bind state of flag --%s", debugFlagKey)
return fmt.Errorf("initializing vdm: %w", err)
}

rootCmd.AddCommand(syncCmd)
return errors.New("you must provide a subcommand to vdm")
}

// Execute wraps the primary execution logic for vdm's root command, and returns
// any errors encountered to the caller.
func Execute() error {
if err := rootCmd.Execute(); err != nil {
cmd := newRootCommand()
if err := cmd.Execute(); err != nil {
return fmt.Errorf("executing root command: %w", err)
}

Expand Down
Loading