Thanks, perhaps this functionality should simply be folded directly
into bitbake-layers perhaps, as an extension of 'create-layers-setup'?
Does it need to be in a separate script?

Alex

On Wed, 12 Jul 2023 at 20:00, Chuck Wolber <chuckwol...@gmail.com> wrote:
>
> I wrote this tool to do automatic updating of layers managed by the 
> setup-layers script. This
> addresses some of the functionality I discussed in my OSSNA 2023 talk.
>
> A detailed explanation of what the following script does is found in the 
> comments, but in
> a nutshell:
>
> * If the --sync-upstream argument is provided, any layers that have remotes 
> called
>   "origin" and "upstream" have upstream changes on their configured branch 
> applied
>   to the origin remote (and local clone).
> * Updates rev and description for all layers managed by setup-layers after 
> pulling
>   the latest changes on the configured branch.
> * Leaves the setup-layers.json file in an updated state so git diff will show 
> changes.
>   Changes can then be reviewed and managed based on local project policy.
>
> I am looking for comments and feedback before I send this as a proper patch.
>
> In particular:
>
> * Are there any problems with this general approach?
> * Should this be managed in OE-Core in the same way setup-layers is?
> * I made some stylistic changes (e.g. main function, --dry-run, etc) that I 
> plan to also patch into
>   setup-layers if this is accepted and there are no objections.
>
>
> ---
>
> #!/usr/bin/env python3
> #
> # Copyright OpenEmbedded Contributors
> #
> # SPDX-License-Identifier: MIT
> #
>
> # This script is idempotent and assumes that the layers it is updating have
> # been managed by setup-layers according to the JSON formatted layers data.
> #
> # For each layer repository in the JSON formatted layers data file:
> #
> # * If remotes named upstream and origin exist and the --sync-upstream 
> argument
> # has been provided, merge upstream changes on the configured branch to the
> # origin remote.
> # * Pull the latest changes on the configured branch from origin.
> # * Update the JSON layers data to reflect the latest layer repo HEAD.
> # * Leave layer repository in an updated state with the configured branch
> # checked out.
> #
> # After reviewing the changes in the JSON layers data file, they can either be
> # committed or reverted. If they are reverted, it will be necessary to re-run
> # setup-layers to ensure your layer repositories reflect the intent captured 
> in
> # the configuration. For the sake of completeness, you may also wish to re-run
> # setup-layers even if you commit the configuration changes, as this script
> # leaves the local layer repo clones checked out to the configured branch 
> rather
> # than the configured rev. The HEAD of the configured branch and the 
> configured
> # rev are identical at the completion of this script, but the latter will be
> # more consistent with expectations established by the setup-layers script.
> #
> # The term "setup-layers" refers to the script found at
> # openembedded-core/scripts/oe-setup-layers. Pass the --help argument to this
> # script for the most up to date usage guidance.
>
> import argparse
> import json
> import os
> import subprocess
>
> def _do_git_command(repodir, command):
>     print("Running '{}' in {}".format(command, repodir))
>     if not args.dry_run:
>         subprocess.check_output(command, shell=True, cwd=repodir)
>
> def _do_git_checkout_branch(repodir, remote, branch):
>     _do_git_command(repodir, 'git checkout -B {0} --track {1}/{0} 
> --quiet'.format(branch, remote))
>
> def _do_git_pull(repodir, remote, branch):
>     _do_git_fetch(repodir, remote)
>     _do_git_merge(repodir, remote, branch)
>
> def _do_git_fetch(repodir, remote):
>     _do_git_command(repodir, 'git fetch {} --prune --prune-tags 
> --quiet'.format(remote))
>
> def _do_git_merge(repodir, remote, branch):
>     _do_git_command(repodir, 'git merge {}/{} --ff-only 
> --quiet'.format(remote, branch))
>
> def _do_git_force_push(repodir, remote, branch):
>     _do_git_command(repodir, 'git push {} heads/{} --force 
> --quiet'.format(remote, branch))
>
> def _get_git_rev(repodir):
>     rev = subprocess.check_output("git rev-parse HEAD", shell=True, 
> cwd=repodir, stderr=subprocess.DEVNULL)
>     return rev.strip().decode("utf-8")
>
> def _get_git_desc(repodir):
>     desc = subprocess.check_output("git describe HEAD --always", shell=True, 
> cwd=repodir, stderr=subprocess.DEVNULL)
>     return desc.strip().decode("utf-8")
>
> def _do_sync_upstream(repodir, repo_name, repo_data):
>     if not args.sync_upstream:
>         return
>
>     repo_remote = repo_data['git-remote']
>     branch = repo_remote['branch']
>     remotes = repo_remote['remotes']
>
>     print("Attempting to sync layer repo {} with upstream.".format(repo_name))
>
>     if 'origin' not in remotes or 'upstream' not in remotes:
>         print("Origin and/or upstream remotes not found on 
> {}".format(repo_name))
>         return
>
>     _do_git_checkout_branch(repodir, 'origin', branch)
>     _do_git_pull(repodir, 'origin', branch)
>     _do_git_fetch(repodir, 'upstream')
>     _do_git_merge(repodir, 'upstream', branch)
>     _do_git_force_push(repodir, 'origin', branch)
>
> def _do_update_layer_json(repodir, repo_name, layer_data):
>     print("Updating layer JSON for {} repo.".format(repo_name))
>     branch = layer_data['sources'][repo_name]['git-remote']['branch']
>
>     _do_git_checkout_branch(repodir, 'origin', branch)
>     _do_git_pull(repodir, 'origin', branch)
>
>     layer_data['sources'][repo_name]['git-remote']['rev'] = 
> _get_git_rev(repodir)
>     layer_data['sources'][repo_name]['git-remote']['describe'] = 
> _get_git_desc(repodir)
>
> def _do_update_layers(layer_data):
>     print("Updating layers...")
>     repos = layer_data['sources']
>     for repo_name in repos:
>         repo_data = repos[repo_name]
>         repodir = os.path.abspath(os.path.join(args.destdir, 
> repo_data['path']))
>
>         if 'contains_this_file' in repo_data.keys():
>             continue
>
>         _do_sync_upstream(repodir, repo_name, repo_data)
>         _do_update_layer_json(repodir, repo_name, layer_data)
>
> def _do_save_layer_config(layer_data):
>     print("Saving updated layer config.")
>     if args.dry_run:
>         return
>
>     with open(args.jsondata, 'w') as f:
>         json.dump(layer_data, f, ensure_ascii=False, indent=4)
>
>     print("\nReview {} for layer changes.".format(args.jsondata))
>
> def _parse_args():
>     global args
>
>     try:
>         defaultdest = os.path.dirname(subprocess.check_output('git rev-parse 
> --show-toplevel', universal_newlines=True, shell=True, 
> cwd=os.path.dirname(__file__)))
>     except subprocess.CalledProcessError as e:
>         defaultdest = os.path.abspath(".")
>
>     parser = argparse.ArgumentParser(description="Updates layer setup JSON in 
> addition to layer repos with upstream remotes.")
>
>     parser.add_argument('--destdir', default=defaultdest, help='Where to find 
> the layers (default is {defaultdest}).'.format(defaultdest=defaultdest))
>     parser.add_argument('--jsondata', default=__file__+".json", help='File 
> containing the layer data in json format (default is 
> {defaultjson}).'.format(defaultjson=__file__+".json"))
>     parser.add_argument('--sync-upstream', action='store_true', help="For 
> repositories with origin and upstream remotes, merge any upstream changes to 
> the configured branch.")
>     parser.add_argument('--dry-run', action='store_true', help="Performs a 
> dry run, but does not make any actual changes.")
>
>     args = parser.parse_args()
>
> def _parse_layer_config():
>     with open(args.jsondata) as f:
>         layer_data = json.load(f)
>
>     supported_versions = ["1.0"]
>     if layer_data["version"] not in supported_versions:
>         raise Exception("File {} has version {}, which is not in supported 
> versions: {}".format(args.jsondata, layer_data["version"], 
> supported_versions))
>
>     return layer_data
>
> def main():
>     _parse_args()
>
>     layer_data = _parse_layer_config()
>     _do_update_layers(layer_data)
>     _do_save_layer_config(layer_data)
>
> if __name__=="__main__":
>     main()
>
>
>
> --
> "Perfection must be reached by degrees; she requires the slow hand of time." 
> - Voltaire
>
> 
>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#184212): 
https://lists.openembedded.org/g/openembedded-core/message/184212
Mute This Topic: https://lists.openembedded.org/mt/100104869/21656
Group Owner: openembedded-core+ow...@lists.openembedded.org
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to