[oXygen-user] Web Author and more then one git submodules

oXygen XML Editor Support (Gabriel Titerlea) support at oxygenxml.com
Fri Dec 6 06:54:04 CST 2019


Hello,

Regarding Web Author, we'll retain the current behavior regarding git 
sub-modules for now.

But for your use-case we think allowing users to switch the file-browser 
to the parent repository and choosing a file from there is a good 
compromise.
To make this work you will need to add custom code that transforms 
absolute URLs into relative URLs and vice versa while taking into 
account sub-modules.

To do that there are 3 hooks where you should intervene using a custom 
Web Author plugin [1][2].

1. Add a URI resolver [3] which will be used to resolve relative paths 
to absolute paths.
2. Add a Relative Reference Resolver which will be used to resolve 
absolute paths to relative paths on the server side.
3. Add a Relative Reference Resolver which will be used to resolve 
absolute paths to relative paths on the client side.

I'm attaching an example for points 1 & 2:

    package example.plugin

    import java.net.MalformedURLException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URL;
    import java.util.Optional;
    import java.util.function.Predicate;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    import javax.xml.transform.Source;
    import javax.xml.transform.TransformerException;
    import javax.xml.transform.URIResolver;

    import ro.sync.basic.util.URLUtil;
    import ro.sync.exml.plugin.workspace.WorkspaceAccessPluginExtension;
    import ro.sync.exml.workspace.api.standalone.StandalonePluginWorkspace;

    public class MyWorkspaceAccessPluginExtension implements
    WorkspaceAccessPluginExtension {

       /**
        * Predicate to check if a URL is inside a configured parent
    repository.
        * You can hard-code this, save it in an option or determine it
    dynamically depending on your use-case.
        * */
       private Predicate<String> urlIsInsideParentRepository =
    Pattern.compile("^gitgle://([^@]+@)?https%3A%2F%2Fgitlab.example.com%2Fowner%2Fparent-project/master/").asPredicate();

       /**
        * This regExp extract first part of a Git URL, without the path
    part.
        * More details about Git URLs:
    https://www.oxygenxml.com/doc/versions/21.1.1.0/ug-waCustom/topics/oxy-url.html#oxy-url__oxyurl_unique_scheme
        *
        * In this example I'm looking at `gitgle` URLs which are URLs
    for GitLab on-premise.
        */
       private Pattern gitUrlWithoutPathPattern =
    Pattern.compile("^gitgle://([^@]+@)?([^:/]+)(:\\d+)?/[^/]+/");

       /**
        * The URL of the submodule inside a parent repository.
        */
       private String submoduleUrlInsideParent =
    "gitgle://https%3A%2F%2Fgitlab.example.com%2Fowner%2Fparent-project/master/submodule/";

       URIResolver uriResolver = new URIResolver() {
         @Override
         public Source resolve(String href, String base) throws
    TransformerException {

           try {
             Optional<String> pathRelativeToParentRepo =
    getPathRelativeToSubmoduleInParentRepo(href, base);

             if (pathRelativeToParentRepo.isPresent()) {
               URI uriInParentRepo = new URI(submoduleUrlInsideParent +
    pathRelativeToParentRepo.get());

               URL normalizedUrlInParentRepo =
    uriInParentRepo.normalize().toURL();

               /*
                * Attach session information to the URL.
                * This is needed to authenticate the requests that will
    retrieve the content of this URL.
                * */
               URL hrefWithUserInfo =
    URLUtil.attachUserInfo(normalizedUrlInParentRepo, new
    URL(base).getUserInfo(), null, false);

               return new Source() {
                 @Override
                 public void setSystemId(String systemId) {/**/}

                 @Override
                 public String getSystemId() {
                   return hrefWithUserInfo.toExternalForm();
                 }
               };
             }
           } catch (URISyntaxException | MalformedURLException e) {/**/}

           return null;
         }

         /**
          * Returns a href that is relative to the submodule from the
    parent URL if the given href represents a navigation outside of the
    submodule.
          * @param href An href attribute, which may be relative or
    absolute.
          * @param base The base URI against which the first argument
    will be made absolute if the absolute URI is required.
          * @return A href that is relative to the parent URL (The
    repository that contains submodules).
          * @throws URISyntaxException
          */
         private Optional<String>
    getPathRelativeToSubmoduleInParentRepo(String href, String base)
    throws URISyntaxException {
           Optional<String> relativePathToParentRepo = Optional.empty();

           // If the URL is not inside a submodule there's no need to
    make any change to it.
           if (base != null && href != null /*&&
    urlIsInsideSubmodule.test(base)*/) {

             // If the href is absolute we leave it as is.
             if (!new URI(href).isAbsolute()) {

               String baseUrlWithoutFileName = base.substring(0,
    base.lastIndexOf('/') + 1);

               /*
                * ______________ ______ ____________
                * A git URL looks like this:
    gitgle://REPOSITORY_URI/BRANCH/PATH/TO/FILE
                *
                * We want to append our relative href to the base git
    URL and normalize it.
                * But we need to add an extra "../" to account for the
    /BRANCH/ part of the git URL.
                * */
               URI normalized = new URI(baseUrlWithoutFileName + "../" +
    href).normalize();

               String absoluteUrlInsideSubmodule = normalized.toString();
               int upOneLevelIndex =
    absoluteUrlInsideSubmodule.indexOf("..");

               // After normalization any "../" left represents a
    navigation outside the current submodule.
               if (upOneLevelIndex != -1) {
                 String hrefRelativeToParent =
    absoluteUrlInsideSubmodule.substring(upOneLevelIndex);
                 relativePathToParentRepo =
    Optional.of(hrefRelativeToParent);
               }
             }
           }

           return relativePathToParentRepo;
         }
       };

       @Override
       public void applicationStarted(StandalonePluginWorkspace
    pluginWorkspaceAccess) {
         // Add a URI resolver which will be used to resolve relative
    paths to absolute paths.
    pluginWorkspaceAccess.getXMLUtilAccess().addPriorityURIResolver(uriResolver);

         // Add a Relative Reference Resolver which will be used to
    resolve absolute paths to relative paths.
    pluginWorkspaceAccess.addRelativeReferencesResolver("gitgle",
    (baseUrl, childUrl) -> {

           try {
             boolean baseIsInsideAParent =
    urlIsInsideParentRepository.test(baseUrl.toExternalForm());
             boolean childIsInsideAParent =
    urlIsInsideParentRepository.test(childUrl.toExternalForm());

             if (!baseIsInsideAParent && childIsInsideAParent) {
               // Make the childUrl relative to the baseUrl while taking
    submodules into account.

               String baseUrlString = baseUrl.toExternalForm();
               Matcher matcher =
    gitUrlWithoutPathPattern.matcher(baseUrlString);

               if (matcher.find()) {
                 String submoduleUrl =
    baseUrlString.substring(matcher.start(), matcher.end());

                 URL submoduleURL = URLUtil.attachUserInfo(new
    URL(submoduleUrl), baseUrl.getUserInfo(), null, false);

                 // To make this work for all submodules you could have
    a map from a submodule URL to its URL inside the parent.
                 URL submoduleInParentURL = URLUtil.attachUserInfo(new
    URL(submoduleUrlInsideParent), baseUrl.getUserInfo(), null, false);

                 String relativePathToRootOfSubmodule =
    URLUtil.makeRelative(baseUrl, submoduleURL, true, true);
                 if (relativePathToRootOfSubmodule.equals(".")) {
                   relativePathToRootOfSubmodule = "";
                 }

                 String relativePathToTargetInsideParent =
    URLUtil.makeRelative(submoduleInParentURL, childUrl, true, true);

                 // Resolved relative URL
                 return relativePathToRootOfSubmodule +
    relativePathToTargetInsideParent;
               }
             }

           } catch (MalformedURLException e) { /**/ }

           return null;
         });
       }

       @Override
       public boolean applicationClosing() {
         return true;
       }
    }

The example.plugin.MyWorkspaceAccessPluginExtension class need to be 
referenced in the plugin.xml file of your plugin [4].

For point 2, you need to add a relative references resolver [5] in 
javascript. This resolver will be used on the client's browser to 
resolve URLs.

    (function () {
       workspace.addRelativeReferencesResolver('gitgle', function
    (baseUrl, childUrl) {

         // Re-implement the java code which was used for
    `pluginWorkspaceAccess.addRelativeReferencesResolver`.

         return "resolvedUrl";
       });
    })();


Let us know if you need anything else.

Best,
Gabriel

[1] 
https://www.oxygenxml.com/doc/versions/21.1.1.0/ug-waCustom/topics/customizing_plugins.html
[2] 
https://www.oxygenxml.com/doc/versions/21.1.1.0/ug-waCustom/topics/webapp-plugin-prototyping.html 
<https://www.oxygenxml.com/doc/versions/21.1.1.0/ug-waCustom/topics/webapp-plugin-prototyping.html?hl=Go%20to%20the%20following%20repository%20and%20follow%20the%20instructions>
[3] 
https://www.oxygenxml.com/doc/versions/21.1.1.0/ug-waCustom/topics/oxy-url.html
[4] 
https://www.oxygenxml.com/doc/versions/21.1/ug-editor/topics/workspace-access-plugin.html
[5] 
https://www.oxygenxml.com/maven/com/oxygenxml/oxygen-webapp/21.1.1.0/jsdoc/sync.api.Workspace.html#addRelativeReferencesResolver

Gabriel Titerlea
https://www.oxygenxml.com

On 03-Dec-19 18:48, Jirka Kosek wrote:
> On 3.12.2019 12:40, oXygen XML Editor Support (Gabriel Titerlea) wrote:
>> We're trying to justify a change to the current behavior regarding Git
>> sub-modules in Web Author. Please describe your use-case in more detail.
> It's project where requirements changed over the time ;-)
>
> Originally separate textbooks have been edited -- each textbook in a
> separate git repository. Each textbook has been standalone. For each
> textbook different group of users has access rights.
>
> Now requirements changed and some books need to reuse content
> (chapters/section, images, ...) from other books. Merging all individual
> repositories into one large repository (for example using git subtree
> feature) where there will be separate folder for each book is not viable
> as this way we would loose ability to give different access rights for
> different textbooks. Git can set access rights only on whole repository
> not on individual folders inside it.
>
> So using submodules we can keep textbooks that don't require inclusion
> of assets from other textbooks as they were in a separate repositories.
> Then textbooks that need to reuse content can be edited from "grandrepo"
> that would include all textbooks as submodules.
>
> Well, yes perhaps this is far beyond what git has been designed for. Git
> was fine for original requirements. Knowing current requirements at the
> start of project would mean that expensive CCMS should be used instead
> of git. :-(
>
> Thanks and have a nice day,
>
> 					Jirka
>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.oxygenxml.com/pipermail/oxygen-user/attachments/20191206/a4a83491/attachment.html>


More information about the oXygen-user mailing list