Skip to content

Commit

Permalink
Merge pull request #53 from launchrctl/51-simplify-package-state-pinp…
Browse files Browse the repository at this point in the history
…ointing-key-in-plasma-composeyaml

#60: Composing with outdated cache and #51: Simplify package state pi…
  • Loading branch information
davidferlay authored Nov 28, 2024
2 parents d8ba5ff + eef34b5 commit d693d89
Show file tree
Hide file tree
Showing 9 changed files with 387 additions and 126 deletions.
80 changes: 46 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
## Composition Tool Specification

The composition tool is a command-line tool that helps developers manage
dependencies for their projects. It allows developers to specify the dependencies for
a project in a "plasma-compose.yaml" file, and then fetches and installs those dependencies
Expand All @@ -8,28 +9,39 @@ The tool works by recursively fetching and processing the "plasma-compose.yaml"
and its dependencies, and then merging the resulting filesystems into a single filesystem.

### CLI

The composition tool is invoked from the command line with the following syntax:
launchr compose [options]
Where options are:

* -w, --working-dir : The directory where temporary files should be stored during the
composition process. Default is the .compose/packages
* -s, --skip-not-versioned : Skip not versioned files from source directory (git only)
* --conflicts-verbosity: Log files conflicts in format "[curent-package] - path to file > Selectef from [domain, other package or current-package]"
* --conflicts-verbosity: Log files conflicts in format "[current-package] - path to file > Selected
from [domain, other package or current-package]"
* --interactive: Interactive mode allows to submit user credentials during action (default: true)

Example usage - `launchr compose -w=./folder/something -s=1 or -s=true --conflicts-verbosity`

It's important to note that: if same file is present locally and also brought by a package, default strategy is that local file will be taken and package file ignored. [Different strategies](https://github.com/launchrctl/compose/blob/main/example/compose.example.yaml#L18-L35) can be difined to customize this behavior to your needs.

It's important to note that: if same file is present locally and also brought by a package, default strategy is that
local file will be taken and package file
ignored. [Different strategies](https://github.com/launchrctl/compose/blob/main/example/compose.example.yaml#L18-L35)
can be difined to customize this behavior to your needs.

### `plasma-compose.yaml` File Format
The "plasma-compose.yaml" file is a text file that specifies the dependencies for a package, along with any necessary metadata and sources for those dependencies.

The "plasma-compose.yaml" file is a text file that specifies the dependencies for a package, along with any necessary
metadata and sources for those dependencies.
The file format includes the following elements:

- name: The name of the package.
- version: The version number of the package.
- source: The source for the package, including the type of source (Git, HTTP), URL or file path, merge strategy and other metadata.
- source: The source for the package, including the type of source (Git, HTTP), URL or file path, merge strategy and
other metadata.
- dependencies: A list of required dependencies.

List of strategies:

- overwrite-local-file
- remove-extra-local-files
- ignore-extra-package-files
Expand All @@ -38,40 +50,43 @@ List of strategies:
Example:

```yaml
name: myproject
version: 1.0.0
name: example
dependencies:
- name: compose-example
source:
type: git
ref: master
tag: 0.0.1
url: https://github.com/example/compose-example.git
strategy:
- name: remove-extra-local-files
path:
- path/to/remove-extra-local-files
- name: ignore-extra-package-files
path:
- library/inventories/platform_nodes/configuration/dev.yaml
- library/inventories/platform_nodes/configuration/prod.yaml
- library/inventories/platform_nodes/configuration/whatever.yaml
- name: compose-example
source:
type: git
ref: master # branch or tag name
url: https://github.com/example/compose-example.git
strategy:
- name: remove-extra-local-files
path:
- path/to/remove-extra-local-files
- name: ignore-extra-package-files
path:
- library/inventories/platform_nodes/configuration/dev.yaml
- library/inventories/platform_nodes/configuration/prod.yaml
- library/inventories/platform_nodes/configuration/whatever.yaml
```
### Fetching and Installing Dependencies
The composition tool fetches and installs dependencies for a package by recursively processing the "plasma-compose.yaml" files for each package and its dependencies. The tool follows these general steps:
1. Fetch the package source code from the specified source location.
2. Extract the package contents to a temporary directory.
3. Process the "plasma-compose.yaml" file for the package, fetching and installing any necessary dependencies recursively.
4. Merge the package filesystem into the final platform filesystem.
5. Repeat steps 1-4 for each package and its dependencies.
The composition tool fetches and installs dependencies for a package by recursively processing the "plasma-compose.yaml"
files for each package and its dependencies. The tool follows these general steps:
1. Check if package exists locally and is up-to-date. If it's not, remove it from packages dir and proceed to next step.
2. Fetch the package from the specified location.
3. Extract the package contents to a packages directory.
4. Process the "plasma-compose.yaml" file for the package, fetching and installing any necessary dependencies
recursively.
5. Merge the package filesystem into the final platform filesystem.
6. Repeat steps 1-5 for each package and its dependencies.
During this process, the composition tool keeps track of the dependencies for each package.
### Plasma-compose commands
it's possible to manipulate plasma-compose.yaml file using commands:
- plasmactl compose:add
- plasmactl compose:update
- plasmactl compose:delete
Expand All @@ -84,17 +99,14 @@ For `compose:delete` it's possible to pass list of packaged to delete.

In other cases, user will be prompted to CLI form to fill necessary data of packages.

Example of usage

Examples of usage

```
launchr compose:add --url some-url --type http
launchr compose:add --package package-name --url some-url --ref v1.0.0
launchr compose:update --package package-name --url some-url --ref v1.0.0

launchr compose:add --package package-name --url some-url --ref v1.0.0 --strategy overwrite-local-file --strategy-path "path1|path2"
launchr compose:add --package package-name --url some-url --ref v1.0.0 --strategy overwrite-local-file,remove-extra-local-files --strategy-path "path1|path2,path3|path4"
launchr compose:add --package package-name --url some-url --ref branch --strategy overwrite-local-file,remove-extra-local-files --strategy-path "path1|path2,path3|path4"
launchr compose:add --package package-name --url some-url --ref v1.0.0 --strategy overwrite-local-file --strategy-path "path1|path2" --strategy remove-extra-local-files --strategy-path "path3|path4"


```
6 changes: 6 additions & 0 deletions compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ func CreateComposer(pwd string, opts ComposerOptions, k keyring.Keyring) (*Compo
return nil, err
}

for _, dep := range config.Dependencies {
if dep.Source.Tag != "" {
launchr.Term().Warning().Printfln("found deprecated field `tag` in `%s` dependency. Use `ref` field for tags or branches.", dep.Name)
}
}

return &Composer{pwd, &opts, config, k}, nil
}

Expand Down
44 changes: 24 additions & 20 deletions compose/downloadManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ import (
const (
// GitType is const for GIT source type download.
GitType = "git"
// SourceReferenceTag represents git tag source.
SourceReferenceTag = "tag"
// SourceReferenceBranch represents git branch source.
SourceReferenceBranch = "ref"
// HTTPType is const for http source type download.
HTTPType = "http"
)

// Downloader interface
type Downloader interface {
Download(pkg *Package, targetDir string, kw *keyringWrapper) error
Download(pkg *Package, targetDir string) error
EnsureLatest(pkg *Package, downloadPath string) (bool, error)
}

// DownloadManager struct, provides methods to fetch packages
Expand All @@ -35,14 +32,14 @@ func CreateDownloadManager(keyring *keyringWrapper) DownloadManager {
return DownloadManager{kw: keyring}
}

func getDownloaderForPackage(downloadType string) Downloader {
func getDownloaderForPackage(downloadType string, kw *keyringWrapper) Downloader {
switch {
case downloadType == GitType:
return newGit()
return newGit(kw)
case downloadType == HTTPType:
return newHTTP()
return newHTTP(kw)
default:
return newGit()
return newGit(kw)
}
}

Expand Down Expand Up @@ -85,16 +82,13 @@ func (m DownloadManager) recursiveDownload(yc *YamlCompose, kw *keyringWrapper,

packagePath := filepath.Join(targetDir, pkg.GetName(), pkg.GetTarget())

// Skip package download if it exists in packages dir.
if _, err := os.Stat(packagePath); os.IsNotExist(err) {
err = downloadPackage(pkg, targetDir, kw)
if err != nil {
return packages, err
}
err := downloadPackage(pkg, targetDir, kw)
if err != nil {
return packages, err
}

// If package has plasma-compose.yaml, proceed with it
if _, err := os.Stat(filepath.Join(packagePath, composeFile)); !os.IsNotExist(err) {
if _, err = os.Stat(filepath.Join(packagePath, composeFile)); !os.IsNotExist(err) {
cfg, err := Lookup(os.DirFS(packagePath))
if err == nil {
packages, err = m.recursiveDownload(cfg, kw, packages, pkg, targetDir)
Expand All @@ -111,20 +105,30 @@ func (m DownloadManager) recursiveDownload(yc *YamlCompose, kw *keyringWrapper,
}

func downloadPackage(pkg *Package, targetDir string, kw *keyringWrapper) error {
downloader := getDownloaderForPackage(pkg.GetType())
downloader := getDownloaderForPackage(pkg.GetType(), kw)
packagePath := filepath.Join(targetDir, pkg.GetName())
downloadPath := filepath.Join(packagePath, pkg.GetTarget())

if _, err := os.Stat(downloadPath); !os.IsNotExist(err) {
// Skip package download if folder exists in packages dir.
isLatest, err := downloader.EnsureLatest(pkg, downloadPath)
if err != nil {
return err
}

if isLatest {
return nil
}

// Ensure old package doesn't exist in case of update.
err = os.RemoveAll(downloadPath)
if err != nil {
return err
}

// temporary
if dtype := pkg.GetType(); dtype == HTTPType {
downloadPath = packagePath
}

err := downloader.Download(pkg, downloadPath, kw)
err = downloader.Download(pkg, downloadPath)
return err
}
20 changes: 1 addition & 19 deletions compose/forms.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ func processStrategiesForm(dependency *Dependency) error {
}

func preparePackageForm(dependency *Dependency, config *YamlCompose, isAdd bool) *huh.Form {
var refType string
uniqueLimit := 1
if isAdd {
uniqueLimit = 0
Expand Down Expand Up @@ -376,27 +375,11 @@ func preparePackageForm(dependency *Dependency, config *YamlCompose, isAdd bool)
}),
),

huh.NewGroup(
huh.NewSelect[string]().
Title("- Select source reference").
Options(
huh.NewOption("Tag", SourceReferenceTag).Selected(true),
huh.NewOption("Branch", SourceReferenceBranch),
).
Value(&refType),
).WithHideFunc(func() bool { return dependency.Source.Type != GitType }),

huh.NewGroup(
huh.NewInput().
Title("- Enter Tag").
Value(&dependency.Source.Tag),
).WithHideFunc(func() bool { return dependency.Source.Type != GitType || refType != SourceReferenceTag }),

huh.NewGroup(
huh.NewInput().
Title("- Enter Ref").
Value(&dependency.Source.Ref),
).WithHideFunc(func() bool { return dependency.Source.Type != GitType || refType != SourceReferenceBranch }),
).WithHideFunc(func() bool { return dependency.Source.Type != GitType }),
)
}

Expand Down Expand Up @@ -431,5 +414,4 @@ func sanitizeDependency(dependency *Dependency) {
dependency.Name = strings.TrimSpace(dependency.Name)
dependency.Source.URL = strings.TrimSpace(dependency.Source.URL)
dependency.Source.Ref = strings.TrimSpace(dependency.Source.Ref)
dependency.Source.Tag = strings.TrimSpace(dependency.Source.Tag)
}
Loading

0 comments on commit d693d89

Please sign in to comment.