Skip to content

Commit a13496d

Browse files
authored
Merge pull request #7 from composer-version-manager/cache-tags-plus-docs
Cache tags, Update README, polish stdout
2 parents c0966a1 + af238c0 commit a13496d

File tree

8 files changed

+138
-28
lines changed

8 files changed

+138
-28
lines changed

README.md

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,84 @@
11
# Composer Version Manager
22

33
[Composer 2](https://getcomposer.org/upgrade/UPGRADE-2.0.md) is here. It's time for a one stop shop for switching between major (and minor
4-
👶) composer versions.
4+
👶) composer versions. Erase "using the right composer version" from your workflow.
55

66
> But wait, what about `composer self-update --1` and `--2`?
77
88
Well I'm glad you've asked!
99

10-
There are some added benefits this CLI will bring to you:
10+
There are some added benefits this CLI and shell hook will bring to you:
1111

1212
1. Cached `composer.phar` for faster version toggling.
13-
1. Per-directory automated and configurable context switching.
14-
1. Production and pipeline friendly installation via [Docker](https://hub.docker.com/).
15-
1. It's as simple as `cvm 1` and `cvm 2`.
13+
1. Per-directory smart composer environments. It's as simple as `cd my-project` and the right composer version will be used.
1614

17-
## Author
15+
## Installation
1816

19-
My name is Morgan Wowk and I am a Software Developer from the wintery lands of Canada 🇨🇦🍁. You can primarily find me on [LinkedIn](https://www.linkedin.com/in/morganwowk/), writing open source or building apps to help [tens of thousands of ecommerce stores](https://boldcommerce.com/).
17+
Choose one of the options below to install cvm.
2018

21-
## Usage
19+
### Homebrew (MacOS)
2220

21+
```bash
22+
brew update
23+
brew install composer-version-manager/cvm
2324
```
24-
# All the commands below will install the missing
25-
# version if it is not yet installed.
2625

27-
cvm 1 # Use the latest, stable composer 1
28-
cvm 2 # Use the latest, stable composer 2
29-
cvm 1.0.0-alpha7 # Use a specific release
26+
### Chocolatey (Windows)
27+
28+
*TODO*
29+
30+
### Download binary and update PATH
31+
32+
*TODO*
33+
34+
## Hook onto your shell
35+
36+
Hooking onto your shell enables cvm [Smart usage](#smart-usage) for per-directory automated composer verrsioning.
37+
38+
Find the instructions for your shell below. If your shell is not listed please feel free to [submit a feature request](https://github.com/composer-version-manager/cvm/issues/new) issue and we will try and make it happen.
39+
40+
### **BASH**
41+
42+
Add the following line to the end of your `~/.bashrc`
43+
44+
```bash
45+
eval "$(cvm hook bash)"
3046
```
3147

48+
### **ZSH**
49+
50+
Add the following line to the end of your `~/.zshrc`
51+
52+
```bash
53+
eval "$(cvm hook zsh)"
54+
```
55+
56+
## Smart usage
57+
58+
Create a `.cvm_config` in any directory specifying the composer version you would like to use. Navigating to that directory or any nested directory will automatically enable that composer version in your current workspace.
59+
60+
```bash
61+
cd my-project
62+
echo '2.0.11' > .cvm_config
63+
```
64+
65+
This file can be committed to your source control.
66+
67+
## Global composer version
68+
69+
You can configure a global composer version. Which will be the default when no parent directory has a `.cvm_config`.
70+
71+
```
72+
cvm list # List available tags
73+
cvm use 2.0.11 # Globally use a specific composer version
74+
```
75+
76+
## Authors
77+
78+
### Morgan Wowk
79+
80+
Morgan is a Software Developer from the wintery lands of Canada 🇨🇦🍁. You can primarily find him on [LinkedIn](https://www.linkedin.com/in/morganwowk/), writing open source or building apps to help [tens of thousands of ecommerce stores](https://boldcommerce.com/).
81+
82+
### Bhavek Budhia
83+
84+
Likewise, Bhavek resides in the frosty country of Canada ☃️. An avid developer 👨‍💻 with fortified experience in Python that has helped us develop a clean and extendable codebase.

cvm/cli.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from argparse_color_formatter import ColorRawTextHelpFormatter
77
from colorama import Fore
88

9+
from cvm.commands.cache_command import CacheCommand
910
from cvm.commands.command import Command
1011
from cvm.commands.hook_command import HookCommand
1112
from cvm.commands.list_command import ListCommand
@@ -15,14 +16,15 @@
1516
from cvm.services.cache_service import CacheService
1617

1718
COMMAND_NAME = 'cvm'
18-
COMMAND_DESC = 'Composer Version Manager\n' + colored_fore(Fore.WHITE, 'Author: @game-of-morgan (Morgan Wowk)')
19+
COMMAND_DESC = 'Composer Version Manager\n' + colored_fore(Fore.WHITE, 'Authors: @game-of-morgan (Morgan Wowk), @ubaniak (Bhavek Budhia)')
1920
COMMAND_EPILOG = 'https://github.com/game-of-morgan/cvm\n\nSupport this project by giving it a GitHub star ⭐️'
2021

2122
COMMANDS = {
2223
UseCommand.NAME: UseCommand,
2324
ScanCommand.NAME: ScanCommand,
2425
ListCommand.NAME: ListCommand,
25-
HookCommand.NAME: HookCommand
26+
HookCommand.NAME: HookCommand,
27+
CacheCommand.NAME: CacheCommand
2628
}
2729

2830

cvm/commands/cache_command.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from argparse import Action, Namespace
2+
3+
from cvm.commands.command import Command
4+
from cvm.helpers.cli import info, warning
5+
from cvm.services.cache_service import CacheService
6+
from cvm.services.composer_service import ComposerService
7+
from cvm.services.github_service import GitHubService
8+
9+
10+
class CacheCommand(Command):
11+
NAME = 'cache:clear'
12+
DESCRIPTION = 'Cleared cached composer tags.'
13+
14+
def exec(self, args: Namespace):
15+
try:
16+
GitHubService.TAGS_FILE_PATH.unlink(missing_ok=True)
17+
except OSError:
18+
print(warning("Failed to clear cached tags."))
19+
return
20+
21+
print(info("Cached tags successfully cleared."))
22+
23+
@staticmethod
24+
def define_signature(parser: Action):
25+
parser.add_parser(CacheCommand.NAME, help=CacheCommand.DESCRIPTION)

cvm/commands/scan_command.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from colorama import Fore
55
from cvm.commands.command import Command
6-
from cvm.helpers.cli import warning
6+
from cvm.helpers.cli import info, warning
77
from cvm.helpers.fs import find_file_in_parent
88
from cvm.services.application_service import ApplicationService
99
from cvm.services.composer_service import ComposerService
@@ -31,7 +31,12 @@ def exec(self, args: Namespace):
3131
composer_service = ComposerService(github_service)
3232
updated_path = composer_service.use_version(version, False)
3333

34-
print(f"export PATH=\"{updated_path}\"; echo Updated path.;")
34+
if not updated_path:
35+
return
36+
37+
msg = info(f"Using composer version {version}")
38+
39+
print(f"export PATH=\"{updated_path}\"; echo \"{msg}\";")
3540

3641
def _check_local(self, config_file: str) -> Optional[str]:
3742
data = ConfigService.read(config_file)

cvm/commands/use_command.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
from argparse import Action, Namespace
44

55
from cvm.commands.command import Command
6+
from cvm.helpers.cli import info
67
from cvm.services.composer_service import ComposerService
78
from cvm.services.config_service import ConfigService
89
from cvm.services.github_service import GitHubService
9-
from cvm.helpers.cli import info
10-
from colorama import Fore
1110

1211

1312
class UseCommand(Command):
@@ -22,7 +21,7 @@ def exec(self, args: Namespace):
2221

2322
composer_service.use_version(version, True)
2423

25-
print(f"Global composer version updated to {version}.")
24+
print(info(f"Global composer version updated to {version}."))
2625

2726
@staticmethod
2827
def define_signature(parser: Action):

cvm/helpers/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ def colored_fore(color: AnsiFore, text: str, default: str = Fore.LIGHTWHITE_EX)
66
return color + text + default
77

88
def warning(text: str, default: str = Fore.LIGHTWHITE_EX) -> str:
9-
return colored_fore(Fore.LIGHTRED_EX, text)
9+
return colored_fore(Fore.LIGHTRED_EX, f"cvm: {text}")
1010

1111
def info(text: str, default: str = Fore.LIGHTWHITE_EX) -> str:
12-
return colored_fore(Fore.LIGHTYELLOW_EX, text)
12+
return colored_fore(Fore.LIGHTYELLOW_EX, f"cvm: {text}")

cvm/services/composer_service.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
import pathlib
33
import subprocess
44
import sys
5+
from typing import Optional
56

67
import requests
7-
8+
from cvm.services.application_service import ApplicationService, ComposerSource
89
from cvm.services.cache_service import CacheService
910
from cvm.services.github_service import GitHubService
10-
from cvm.services.application_service import ApplicationService, ComposerSource
1111

1212

1313
class ComposerService:
@@ -69,10 +69,15 @@ def install_version(self, tag_name: str, quiet=False) -> str:
6969

7070
return str(cache_path)
7171

72-
def use_version(self, tag_name: str, is_global: bool) -> str:
72+
def use_version(self, tag_name: str, is_global: bool) -> Optional[str]:
73+
application_service = ApplicationService()
74+
7375
bin_path = self.install_version(tag_name, quiet=True)
76+
current_tag_name = application_service.get('current')
77+
78+
if not is_global and current_tag_name == tag_name:
79+
return None
7480

75-
application_service = ApplicationService()
7681
application_service.set('current', tag_name)
7782

7883
if is_global:

cvm/services/github_service.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1+
import json
12
import logging
23
import sys
34
from typing import Generator
45

56
import requests
7+
from cvm.services.application_service import ApplicationService
68

79

810
class GitHubService:
11+
TAGS_FILE_PATH = ApplicationService.APP_DIR / 'tags.json'
12+
913
def __init__(self, owner_id: str, repo_id: str):
1014
self.owner_id = owner_id
1115
self.repo_id = repo_id
1216

13-
def list_tags(self) -> Generator[object]:
14-
17+
def _fetch_tags(self) -> Generator[object, None, None]:
1518
page = 1
1619
headers = {'Accept': 'application/vnd.github.v3+json'}
20+
1721
while True:
1822

1923
url = f"https://api.github.com/repos/{self.owner_id}/{self.repo_id}/tags?page={page}"
@@ -31,3 +35,20 @@ def list_tags(self) -> Generator[object]:
3135
yield i
3236
page += 1
3337

38+
def list_tags(self) -> Generator[object, None, None]:
39+
if GitHubService.TAGS_FILE_PATH.exists():
40+
cache = json.load(GitHubService.TAGS_FILE_PATH.open('r'))
41+
tags = cache["tags"]
42+
43+
for tag in tags:
44+
yield tag
45+
else:
46+
tags = []
47+
for tag in self._fetch_tags():
48+
tags.append(tag)
49+
yield tag
50+
51+
cache = {
52+
"tags": tags
53+
}
54+
GitHubService.TAGS_FILE_PATH.write_text(json.dumps(cache))

0 commit comments

Comments
 (0)